diff --git a/DEPS b/DEPS
index ac17347..8f80a4f 100644
--- a/DEPS
+++ b/DEPS
@@ -105,7 +105,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '6784ffa78e70e17084e1b30e724a8ded175d6007',
+  'skia_revision': 'cdefa23a23cfc411fb50a21d9a06bfaa8d037886',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -161,11 +161,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling HarfBuzz
   # and whatever else without interference from each other.
-  'harfbuzz_revision': '2cb075fe26201f3e370fccfff6c1bc242b5acc79',
+  'harfbuzz_revision': '957e7756634a4fdf1654041e20e883cf964ecac9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '5abd99f5f7685f0e3b18f11e2fcda667a3be83e3',
+  'catapult_revision': '82213060d5ce0d376671dda9ca3928b5ad1c9c69',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -346,16 +346,6 @@
       'condition': 'checkout_nacl',
   },
 
-  'src/tools/luci-go': {
-      'packages': [
-        {
-          'package': 'infra/tools/luci/isolate/${{platform}}',
-          'version': 'git_revision:8b15ba47cbaf07a56f93326e39f0c8e5069c19e8',
-        },
-      ],
-      'dep_type': 'cipd',
-  },
-
   'src/third_party/SPIRV-Tools/src':
     Var('chromium_git') + '/external/github.com/KhronosGroup/SPIRV-Tools.git' + '@' + '9166854ac93ef81b026e943ccd230fed6c8b8d3c',
 
@@ -1718,7 +1708,6 @@
     ],
   },
   # Pull luci-go binaries (isolate, swarming) using checked-in hashes.
-  # TODO(maruel): Remove, https://crbug.com/851596
   {
     'name': 'luci-go_win',
     'pattern': '.',
diff --git a/WATCHLISTS b/WATCHLISTS
index 08131aa..90f9c1f2 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1620,6 +1620,9 @@
                   '|third_party/blink/public/platform/modules/webshare/'\
                   '|third_party/blink/renderer/modules/webshare/',
     },
+    'webgpu': {
+        'filepath': 'third_party/blink/renderer/modules/webgpu/',
+    },
     'webrtc_browser_tests': {
       'filepath': 'chrome/browser/media/.*webrtc.*browsertest|'\
                   'content/browser/media/.*webrtc.*browsertest',
@@ -2081,8 +2084,7 @@
            'dpranke@chromium.org',
            'tfarina@chromium.org'],
     'gpu': ['piman+watch@chromium.org'],
-    'gpu_passthrough_cmd_decoder': ['cwallez+watch@chromium.org',
-                                    'geofflang+watch@chromium.org'],
+    'gpu_passthrough_cmd_decoder': ['geofflang+watch@chromium.org'],
     'headless': ['headless-reviews@chromium.org'],
     'history_ui': ['pam+watch@chromium.org'],
     'i18n': ['jshin+watch@chromium.org'],
@@ -2344,6 +2346,8 @@
     'wake_lock': ['mattreynolds+watch@chromium.org'],
     'web_package': ['twifkak+watch@chromium.org'],
     'web_share': ['mgiuca+watch@chromium.org'],
+    'webgpu': ['cwallez+watch@chromium.org',
+               'kainino+watch@chromium.org'],
     'webrtc_browser_tests': ['phoglund+watch@chromium.org'],
     'website_settings': ['dullweber+watch@chromium.org',
                          'markusheintz@chromium.org',
diff --git a/ash/system/unified/feature_pod_button.cc b/ash/system/unified/feature_pod_button.cc
index 240d183..3e01314 100644
--- a/ash/system/unified/feature_pod_button.cc
+++ b/ash/system/unified/feature_pod_button.cc
@@ -269,7 +269,8 @@
 }
 
 void FeaturePodButton::SetExpandedAmount(double expanded_amount) {
-  label_button_->layer()->SetOpacity(expanded_amount);
+  // TODO(tetsui): Confirm the animation curve with UX.
+  label_button_->layer()->SetOpacity(std::max(0., 5. * expanded_amount - 4.));
   label_button_->SetVisible(expanded_amount > 0.0);
 }
 
diff --git a/ash/system/unified/unified_system_tray.cc b/ash/system/unified/unified_system_tray.cc
index af76d4f..cc561b4a 100644
--- a/ash/system/unified/unified_system_tray.cc
+++ b/ash/system/unified/unified_system_tray.cc
@@ -61,6 +61,7 @@
 UnifiedSystemTray::UiDelegate::UiDelegate(UnifiedSystemTray* owner)
     : owner_(owner) {
   ui_controller_ = std::make_unique<message_center::UiController>(this);
+  ui_controller_->set_hide_on_last_notification(false);
   popup_alignment_delegate_ =
       std::make_unique<AshPopupAlignmentDelegate>(owner->shelf());
   message_popup_collection_ =
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index 462167c1..6ec855b 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -177,7 +177,22 @@
   UpdateExpandedAmount();
 }
 
+void UnifiedSystemTrayController::StartAnimation(bool expand) {
+  if (expand) {
+    animation_->Show();
+  } else {
+    // To animate to hidden state, first set SlideAnimation::IsShowing() to
+    // true.
+    animation_->Show();
+    animation_->Hide();
+  }
+}
+
 void UnifiedSystemTrayController::EndDrag(const gfx::Point& location) {
+  if (animation_->is_animating()) {
+    // Prevent overwriting the state right after fling event
+    return;
+  }
   bool expanded = GetDragExpandedAmount(location) > 0.5;
   if (was_expanded_ != expanded) {
     UMA_HISTOGRAM_ENUMERATION("ChromeOS.SystemTray.ToggleExpanded",
@@ -186,14 +201,12 @@
   }
 
   // If dragging is finished, animate to closer state.
-  if (expanded) {
-    animation_->Show();
-  } else {
-    // To animate to hidden state, first set SlideAnimation::IsShowing() to
-    // true.
-    animation_->Show();
-    animation_->Hide();
-  }
+  StartAnimation(expanded);
+}
+
+void UnifiedSystemTrayController::Fling(int velocity) {
+  // Expand when flinging up. Collapse otherwise.
+  StartAnimation(velocity < 0);
 }
 
 void UnifiedSystemTrayController::ShowUserChooserWidget() {
diff --git a/ash/system/unified/unified_system_tray_controller.h b/ash/system/unified/unified_system_tray_controller.h
index 8713455..c6bad93e 100644
--- a/ash/system/unified/unified_system_tray_controller.h
+++ b/ash/system/unified/unified_system_tray_controller.h
@@ -65,6 +65,7 @@
   void BeginDrag(const gfx::Point& location);
   void UpdateDrag(const gfx::Point& location);
   void EndDrag(const gfx::Point& location);
+  void Fling(int velocity);
 
   // Show user selector popup widget. Called from the view.
   void ShowUserChooserWidget();
@@ -139,6 +140,9 @@
   // Return true if UnifiedSystemTray is expanded.
   bool IsExpanded() const;
 
+  // Starts animation to expand or collapse the bubble.
+  void StartAnimation(bool expand);
+
   // Model that stores UI specific variables. Unowned.
   UnifiedSystemTrayModel* const model_;
 
diff --git a/ash/system/unified/unified_system_tray_view.cc b/ash/system/unified/unified_system_tray_view.cc
index a40bf17..ffbe438 100644
--- a/ash/system/unified/unified_system_tray_view.cc
+++ b/ash/system/unified/unified_system_tray_view.cc
@@ -106,15 +106,20 @@
 }
 
 void UnifiedSlidersContainerView::UpdateOpacity() {
+  const int height = GetPreferredSize().height();
   for (int i = 0; i < child_count(); ++i) {
     views::View* child = child_at(i);
     double opacity = 1.0;
-    if (child->y() > height())
+    if (child->y() > height) {
       opacity = 0.0;
-    else if (child->bounds().bottom() < height())
+    } else if (child->bounds().bottom() < height) {
       opacity = 1.0;
-    else
-      opacity = static_cast<double>(height() - child->y()) / child->height();
+    } else {
+      const double ratio =
+          static_cast<double>(height - child->y()) / child->height();
+      // TODO(tetsui): Confirm the animation curve with UX.
+      opacity = std::max(0., 2. * ratio - 1.);
+    }
     child->layer()->SetOpacity(opacity);
   }
 }
@@ -243,6 +248,9 @@
       controller_->EndDrag(screen_location);
       event->SetHandled();
       break;
+    case ui::ET_SCROLL_FLING_START:
+      controller_->Fling(event->details().velocity_y());
+      break;
     default:
       break;
   }
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 5443d2d..cb84017 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -814,16 +814,35 @@
     "task/cancelable_task_tracker.h",
     "task/sequence_manager/enqueue_order.cc",
     "task/sequence_manager/enqueue_order.h",
+    "task/sequence_manager/graceful_queue_shutdown_helper.cc",
+    "task/sequence_manager/graceful_queue_shutdown_helper.h",
     "task/sequence_manager/intrusive_heap.h",
     "task/sequence_manager/lazily_deallocated_deque.h",
     "task/sequence_manager/lazy_now.cc",
     "task/sequence_manager/lazy_now.h",
+    "task/sequence_manager/real_time_domain.cc",
+    "task/sequence_manager/real_time_domain.h",
     "task/sequence_manager/sequence_manager.h",
+    "task/sequence_manager/sequence_manager_impl.cc",
+    "task/sequence_manager/sequence_manager_impl.h",
     "task/sequence_manager/sequenced_task_source.h",
+    "task/sequence_manager/task_queue.cc",
     "task/sequence_manager/task_queue.h",
+    "task/sequence_manager/task_queue_impl.cc",
+    "task/sequence_manager/task_queue_impl.h",
+    "task/sequence_manager/task_queue_selector.cc",
+    "task/sequence_manager/task_queue_selector.h",
+    "task/sequence_manager/task_queue_selector_logic.h",
     "task/sequence_manager/task_time_observer.h",
     "task/sequence_manager/thread_controller.h",
+    "task/sequence_manager/thread_controller_impl.cc",
+    "task/sequence_manager/thread_controller_impl.h",
+    "task/sequence_manager/time_domain.cc",
     "task/sequence_manager/time_domain.h",
+    "task/sequence_manager/work_queue.cc",
+    "task/sequence_manager/work_queue.h",
+    "task/sequence_manager/work_queue_sets.cc",
+    "task/sequence_manager/work_queue_sets.h",
     "task_runner.cc",
     "task_runner.h",
     "task_runner_util.h",
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
index 05a3bd2..5dddc71 100644
--- a/base/files/important_file_writer_unittest.cc
+++ b/base/files/important_file_writer_unittest.cc
@@ -231,7 +231,7 @@
 
 TEST_F(ImportantFileWriterTest, ScheduleWrite) {
   constexpr TimeDelta kCommitInterval = TimeDelta::FromSeconds(12345);
-  MockTimer timer(true, false);
+  MockOneShotTimer timer;
   ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get(),
                              kCommitInterval);
   writer.SetTimerForTesting(&timer);
@@ -250,7 +250,7 @@
 }
 
 TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
-  MockTimer timer(true, false);
+  MockOneShotTimer timer;
   ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   writer.SetTimerForTesting(&timer);
   EXPECT_FALSE(writer.HasPendingWrite());
@@ -265,7 +265,7 @@
 }
 
 TEST_F(ImportantFileWriterTest, BatchingWrites) {
-  MockTimer timer(true, false);
+  MockOneShotTimer timer;
   ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   writer.SetTimerForTesting(&timer);
   DataSerializer foo("foo"), bar("bar"), baz("baz");
@@ -280,7 +280,7 @@
 }
 
 TEST_F(ImportantFileWriterTest, ScheduleWrite_FailToSerialize) {
-  MockTimer timer(true, false);
+  MockOneShotTimer timer;
   ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   writer.SetTimerForTesting(&timer);
   EXPECT_FALSE(writer.HasPendingWrite());
@@ -295,7 +295,7 @@
 }
 
 TEST_F(ImportantFileWriterTest, ScheduleWrite_WriteNow) {
-  MockTimer timer(true, false);
+  MockOneShotTimer timer;
   ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   writer.SetTimerForTesting(&timer);
   EXPECT_FALSE(writer.HasPendingWrite());
@@ -312,7 +312,7 @@
 }
 
 TEST_F(ImportantFileWriterTest, DoScheduledWrite_FailToSerialize) {
-  MockTimer timer(true, false);
+  MockOneShotTimer timer;
   ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
   writer.SetTimerForTesting(&timer);
   EXPECT_FALSE(writer.HasPendingWrite());
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 6f54a63..bd0a568 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -428,7 +428,7 @@
 bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
   if (!task_execution_allowed_ ||
       !incoming_task_queue_->delayed_tasks().HasTasks()) {
-    recent_time_ = *next_delayed_work_time = TimeTicks();
+    *next_delayed_work_time = TimeTicks();
 
     // It's possible to be woken up by a system event and have it cancel the
     // upcoming delayed task from under us before DoDelayedWork() -- see comment
diff --git a/third_party/blink/renderer/platform/scheduler/base/graceful_queue_shutdown_helper.cc b/base/task/sequence_manager/graceful_queue_shutdown_helper.cc
similarity index 85%
rename from third_party/blink/renderer/platform/scheduler/base/graceful_queue_shutdown_helper.cc
rename to base/task/sequence_manager/graceful_queue_shutdown_helper.cc
index 2a2b7da..9a8c893e 100644
--- a/third_party/blink/renderer/platform/scheduler/base/graceful_queue_shutdown_helper.cc
+++ b/base/task/sequence_manager/graceful_queue_shutdown_helper.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/graceful_queue_shutdown_helper.h"
+#include "base/task/sequence_manager/graceful_queue_shutdown_helper.h"
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/graceful_queue_shutdown_helper.h b/base/task/sequence_manager/graceful_queue_shutdown_helper.h
similarity index 80%
rename from third_party/blink/renderer/platform/scheduler/base/graceful_queue_shutdown_helper.h
rename to base/task/sequence_manager/graceful_queue_shutdown_helper.h
index e3ee7c91..108eb82 100644
--- a/third_party/blink/renderer/platform/scheduler/base/graceful_queue_shutdown_helper.h
+++ b/base/task/sequence_manager/graceful_queue_shutdown_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
+#ifndef BASE_TASK_SEQUENCE_MANAGER_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
+#define BASE_TASK_SEQUENCE_MANAGER_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
 
 #include <memory>
 #include <vector>
@@ -47,4 +47,4 @@
 }  // namespace sequence_manager
 }  // namespace base
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
+#endif  // BASE_TASK_SEQUENCE_MANAGER_GRACEFUL_QUEUE_SHUTDOWN_HELPER_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/real_time_domain.cc b/base/task/sequence_manager/real_time_domain.cc
similarity index 86%
rename from third_party/blink/renderer/platform/scheduler/base/real_time_domain.cc
rename to base/task/sequence_manager/real_time_domain.cc
index 03ef8432..6a6caf0 100644
--- a/third_party/blink/renderer/platform/scheduler/base/real_time_domain.cc
+++ b/base/task/sequence_manager/real_time_domain.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/real_time_domain.h"
+#include "base/task/sequence_manager/real_time_domain.h"
 
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
+#include "base/task/sequence_manager/sequence_manager.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/real_time_domain.h b/base/task/sequence_manager/real_time_domain.h
similarity index 60%
rename from third_party/blink/renderer/platform/scheduler/base/real_time_domain.h
rename to base/task/sequence_manager/real_time_domain.h
index 7489b83f..4923ebf0 100644
--- a/third_party/blink/renderer/platform/scheduler/base/real_time_domain.h
+++ b/base/task/sequence_manager/real_time_domain.h
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
+#ifndef BASE_TASK_SEQUENCE_MANAGER_REAL_TIME_DOMAIN_H_
+#define BASE_TASK_SEQUENCE_MANAGER_REAL_TIME_DOMAIN_H_
 
+#include "base/base_export.h"
 #include "base/macros.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
+#include "base/task/sequence_manager/time_domain.h"
 
 namespace base {
 namespace sequence_manager {
 namespace internal {
 
-class PLATFORM_EXPORT RealTimeDomain : public TimeDomain {
+class BASE_EXPORT RealTimeDomain : public TimeDomain {
  public:
   RealTimeDomain();
   ~RealTimeDomain() override;
@@ -34,4 +34,4 @@
 }  // namespace sequence_manager
 }  // namespace base
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
+#endif  // BASE_TASK_SEQUENCE_MANAGER_REAL_TIME_DOMAIN_H_
diff --git a/base/task/sequence_manager/sequence_manager.h b/base/task/sequence_manager/sequence_manager.h
index 47f20cd3b..e9f03fce 100644
--- a/base/task/sequence_manager/sequence_manager.h
+++ b/base/task/sequence_manager/sequence_manager.h
@@ -103,6 +103,13 @@
       const TaskQueue::Spec& spec) = 0;
 };
 
+// Create SequenceManager using MessageLoop on the current thread.
+// Implementation is located in sequence_manager_impl.cc.
+// TODO(scheduler-dev): Rename to TakeOverCurrentThread when we'll stop using
+// MessageLoop and will actually take over a thread.
+BASE_EXPORT std::unique_ptr<SequenceManager>
+CreateSequenceManagerOnCurrentThread();
+
 }  // namespace sequence_manager
 }  // namespace base
 
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc
similarity index 97%
rename from third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.cc
rename to base/task/sequence_manager/sequence_manager_impl.cc
index b3aae71..70c19a4 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.cc
+++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
 
 #include <queue>
 #include <vector>
@@ -13,16 +13,15 @@
 #include "base/debug/crash_logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/rand_util.h"
+#include "base/task/sequence_manager/real_time_domain.h"
 #include "base/task/sequence_manager/task_time_observer.h"
+#include "base/task/sequence_manager/thread_controller_impl.h"
+#include "base/task/sequence_manager/work_queue.h"
+#include "base/task/sequence_manager/work_queue_sets.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/tick_clock.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "third_party/blink/renderer/platform/scheduler/base/real_time_domain.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h b/base/task/sequence_manager/sequence_manager_impl.h
similarity index 94%
rename from third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h
rename to base/task/sequence_manager/sequence_manager_impl.h
index dd3a94e..b21b501 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h
+++ b/base/task/sequence_manager/sequence_manager_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_SEQUENCE_MANAGER_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_SEQUENCE_MANAGER_IMPL_H_
+#ifndef BASE_TASK_SEQUENCE_MANAGER_SEQUENCE_MANAGER_IMPL_H_
+#define BASE_TASK_SEQUENCE_MANAGER_SEQUENCE_MANAGER_IMPL_H_
 
 #include <list>
 #include <map>
@@ -26,13 +26,13 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/task/sequence_manager/enqueue_order.h"
+#include "base/task/sequence_manager/graceful_queue_shutdown_helper.h"
 #include "base/task/sequence_manager/moveable_auto_lock.h"
+#include "base/task/sequence_manager/sequence_manager.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/task_queue_selector.h"
 #include "base/task/sequence_manager/thread_controller.h"
 #include "base/threading/thread_checker.h"
-#include "third_party/blink/renderer/platform/scheduler/base/graceful_queue_shutdown_helper.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h"
 
 namespace base {
 
@@ -68,7 +68,7 @@
 //    the incoming task queue (if any) are moved here. The work queues are
 //    registered with the selector as input to the scheduling decision.
 //
-class PLATFORM_EXPORT SequenceManagerImpl
+class BASE_EXPORT SequenceManagerImpl
     : public SequenceManager,
       public internal::SequencedTaskSource,
       public internal::TaskQueueSelector::Observer,
@@ -304,7 +304,7 @@
   }
 
   // A check to bail out early during memory corruption.
-  // crbug.com/757940
+  // https://crbug.com/757940
   bool Validate();
 
   int32_t memory_corruption_sentinel_;
@@ -329,4 +329,4 @@
 }  // namespace sequence_manager
 }  // namespace base
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_SEQUENCE_MANAGER_IMPL_H_
+#endif  // BASE_TASK_SEQUENCE_MANAGER_SEQUENCE_MANAGER_IMPL_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue.cc b/base/task/sequence_manager/task_queue.cc
similarity index 96%
rename from third_party/blink/renderer/platform/scheduler/base/task_queue.cc
rename to base/task/sequence_manager/task_queue.cc
index 2a7aafb..2f23d072 100644
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue.cc
+++ b/base/task/sequence_manager/task_queue.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
+#include "base/task/sequence_manager/task_queue.h"
 
 #include "base/bind.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/base/task/sequence_manager/task_queue.h b/base/task/sequence_manager/task_queue.h
index d6773a0..80dda08b 100644
--- a/base/task/sequence_manager/task_queue.h
+++ b/base/task/sequence_manager/task_queue.h
@@ -15,14 +15,6 @@
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 
-// Currently the implementation is located in Blink because scheduler/base move
-// is in progress https://crbug.com/783309.
-// TODO(kraynov): Remove this hack ASAP.
-#ifndef HACKDEF_INCLUDED_FROM_BLINK
-// Need PLATFORM_EXPORT macro.
-#error Use third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h.
-#endif
-
 namespace base {
 
 namespace trace_event {
@@ -39,7 +31,7 @@
 
 class TimeDomain;
 
-class PLATFORM_EXPORT TaskQueue : public SingleThreadTaskRunner {
+class BASE_EXPORT TaskQueue : public SingleThreadTaskRunner {
  public:
   class Observer {
    public:
@@ -60,7 +52,7 @@
 
   // A wrapper around OnceClosure with additional metadata to be passed
   // to PostTask and plumbed until PendingTask is created.
-  struct PLATFORM_EXPORT PostedTask {
+  struct BASE_EXPORT PostedTask {
     PostedTask(OnceClosure callback,
                Location posted_from,
                TimeDelta delay = TimeDelta(),
@@ -143,7 +135,7 @@
   };
 
   // Interface to pass per-task metadata to RendererScheduler.
-  class PLATFORM_EXPORT Task : public PendingTask {
+  class BASE_EXPORT Task : public PendingTask {
    public:
     Task(PostedTask posted_task, TimeTicks desired_run_time);
 
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc
similarity index 98%
rename from third_party/blink/renderer/platform/scheduler/base/task_queue_impl.cc
rename to base/task/sequence_manager/task_queue_impl.cc
index 51dcc1e..2ec63102 100644
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_impl.cc
+++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 
 #include <memory>
 #include <utility>
 
 #include "base/strings/stringprintf.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/time_domain.h"
+#include "base/task/sequence_manager/work_queue.h"
 #include "base/time/time.h"
 #include "base/trace_event/blame_context.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h
index f21437d..72336fc1 100644
--- a/base/task/sequence_manager/task_queue_impl.h
+++ b/base/task/sequence_manager/task_queue_impl.h
@@ -69,7 +69,7 @@
 // queue is selected, it round-robins between the |immediate_work_queue| and
 // |delayed_work_queue|.  The reason for this is we want to make sure delayed
 // tasks (normally the most common type) don't starve out immediate work.
-class PLATFORM_EXPORT TaskQueueImpl {
+class BASE_EXPORT TaskQueueImpl {
  public:
   TaskQueueImpl(SequenceManagerImpl* sequence_manager,
                 TimeDomain* time_domain,
@@ -104,7 +104,7 @@
     }
   };
 
-  class PLATFORM_EXPORT Task : public TaskQueue::Task {
+  class BASE_EXPORT Task : public TaskQueue::Task {
    public:
     Task(TaskQueue::PostedTask task,
          TimeTicks desired_run_time,
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_selector.cc b/base/task/sequence_manager/task_queue_selector.cc
similarity index 97%
rename from third_party/blink/renderer/platform/scheduler/base/task_queue_selector.cc
rename to base/task/sequence_manager/task_queue_selector.cc
index 8fe0ba7..30a88bd 100644
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_selector.cc
+++ b/base/task/sequence_manager/task_queue_selector.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h"
+#include "base/task/sequence_manager/task_queue_selector.h"
 
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/work_queue.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h b/base/task/sequence_manager/task_queue_selector.h
similarity index 93%
rename from third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h
rename to base/task/sequence_manager/task_queue_selector.h
index 3db0a4e5c..182158b 100644
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h
+++ b/base/task/sequence_manager/task_queue_selector.h
@@ -2,16 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_
+#ifndef BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_
+#define BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_
 
 #include <stddef.h>
 
+#include "base/base_export.h"
 #include "base/macros.h"
 #include "base/pending_task.h"
+#include "base/task/sequence_manager/task_queue_selector_logic.h"
+#include "base/task/sequence_manager/work_queue_sets.h"
 #include "base/threading/thread_checker.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_selector_logic.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h"
 
 namespace base {
 namespace sequence_manager {
@@ -19,7 +20,7 @@
 
 // TaskQueueSelector is used by the SchedulerHelper to enable prioritization
 // of particular task queues.
-class PLATFORM_EXPORT TaskQueueSelector {
+class BASE_EXPORT TaskQueueSelector {
  public:
   TaskQueueSelector();
   ~TaskQueueSelector();
@@ -53,7 +54,7 @@
   // Serialize the selector state for tracing.
   void AsValueInto(trace_event::TracedValue* state) const;
 
-  class PLATFORM_EXPORT Observer {
+  class BASE_EXPORT Observer {
    public:
     virtual ~Observer() = default;
 
@@ -70,7 +71,7 @@
   bool AllEnabledWorkQueuesAreEmpty() const;
 
  protected:
-  class PLATFORM_EXPORT PrioritizingSelector {
+  class BASE_EXPORT PrioritizingSelector {
    public:
     PrioritizingSelector(TaskQueueSelector* task_queue_selector,
                          const char* name);
@@ -213,7 +214,7 @@
   size_t normal_priority_starvation_score_;
   size_t low_priority_starvation_score_;
 
-  Observer* task_queue_selector_observer_;  // NOT OWNED
+  Observer* task_queue_selector_observer_;  // Not owned.
   DISALLOW_COPY_AND_ASSIGN(TaskQueueSelector);
 };
 
@@ -221,4 +222,4 @@
 }  // namespace sequence_manager
 }  // namespace base
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_H_
+#endif  // BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_selector_logic.h b/base/task/sequence_manager/task_queue_selector_logic.h
similarity index 81%
rename from third_party/blink/renderer/platform/scheduler/base/task_queue_selector_logic.h
rename to base/task/sequence_manager/task_queue_selector_logic.h
index 7c8e91c..8cf8933 100644
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_selector_logic.h
+++ b/base/task/sequence_manager/task_queue_selector_logic.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_LOGIC_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_SELECTOR_LOGIC_H_
+#ifndef BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_LOGIC_H_
+#define BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_LOGIC_H_
 
 namespace base {
 namespace sequence_manager {
@@ -34,4 +34,4 @@
 }  // namespace sequence_manager
 }  // namespace base
 
-#endif
+#endif  // BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_SELECTOR_LOGIC_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.cc b/base/task/sequence_manager/thread_controller_impl.cc
similarity index 91%
rename from third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.cc
rename to base/task/sequence_manager/thread_controller_impl.cc
index 49c4d45..c68672b1 100644
--- a/third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.cc
+++ b/base/task/sequence_manager/thread_controller_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.h"
+#include "base/task/sequence_manager/thread_controller_impl.h"
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
@@ -170,7 +170,16 @@
 
     sequence_->DidRunTask();
 
-    // TODO(alexclarke): Find out why this is needed.
+    // NOTE: https://crbug.com/828835.
+    // When we're running inside a nested RunLoop it may quit anytime, so any
+    // outstanding pending tasks must run in the outer RunLoop
+    // (see SequenceManagerTestWithMessageLoop.QuitWhileNested test).
+    // Unfortunately, it's MessageLoop who's receving that signal and we can't
+    // know it before we return from DoWork, hence, OnExitNestedRunLoop
+    // will be called later. Since we must implement ThreadController and
+    // SequenceManager in conformance with MessageLoop task runners, we need
+    // to disable this batching optimization while nested.
+    // Implementing RunLoop::Delegate ourselves will help to resolve this issue.
     if (main_sequence_only().nesting_depth > 0)
       break;
   }
diff --git a/third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.h b/base/task/sequence_manager/thread_controller_impl.h
similarity index 88%
rename from third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.h
rename to base/task/sequence_manager/thread_controller_impl.h
index 5e005c2..a2cd61d72 100644
--- a/third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.h
+++ b/base/task/sequence_manager/thread_controller_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_THREAD_CONTROLLER_IMPL_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_THREAD_CONTROLLER_IMPL_H_
+#ifndef BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_IMPL_H_
+#define BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_IMPL_H_
 
 #include "base/cancelable_callback.h"
 #include "base/debug/task_annotator.h"
@@ -13,7 +13,6 @@
 #include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/sequence_manager/thread_controller.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
 
 namespace base {
 
@@ -24,8 +23,8 @@
 namespace sequence_manager {
 namespace internal {
 
-class PLATFORM_EXPORT ThreadControllerImpl : public ThreadController,
-                                             public RunLoop::NestingObserver {
+class BASE_EXPORT ThreadControllerImpl : public ThreadController,
+                                         public RunLoop::NestingObserver {
  public:
   ~ThreadControllerImpl() override;
 
@@ -127,4 +126,4 @@
 }  // namespace sequence_manager
 }  // namespace base
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_THREAD_CONTROLLER_IMPL_H_
+#endif  // BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_IMPL_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/time_domain.cc b/base/task/sequence_manager/time_domain.cc
similarity index 92%
rename from third_party/blink/renderer/platform/scheduler/base/time_domain.cc
rename to base/task/sequence_manager/time_domain.cc
index bcf7f0e..8f47eb3 100644
--- a/third_party/blink/renderer/platform/scheduler/base/time_domain.cc
+++ b/base/task/sequence_manager/time_domain.cc
@@ -2,13 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
+#include "base/task/sequence_manager/time_domain.h"
 
-#include <set>
-
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/work_queue.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/base/task/sequence_manager/time_domain.h b/base/task/sequence_manager/time_domain.h
index 14bad6a..e9e487b 100644
--- a/base/task/sequence_manager/time_domain.h
+++ b/base/task/sequence_manager/time_domain.h
@@ -32,7 +32,7 @@
 // TaskQueue maintains its own next wake-up time and communicates it
 // to the TimeDomain, which aggregates wake-ups across registered TaskQueues
 // into a global wake-up, which ultimately gets passed to the ThreadController.
-class PLATFORM_EXPORT TimeDomain {
+class BASE_EXPORT TimeDomain {
  public:
   virtual ~TimeDomain();
 
diff --git a/third_party/blink/renderer/platform/scheduler/base/work_queue.cc b/base/task/sequence_manager/work_queue.cc
similarity index 97%
rename from third_party/blink/renderer/platform/scheduler/base/work_queue.cc
rename to base/task/sequence_manager/work_queue.cc
index 10368d4e..4d95f4b 100644
--- a/third_party/blink/renderer/platform/scheduler/base/work_queue.cc
+++ b/base/task/sequence_manager/work_queue.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
+#include "base/task/sequence_manager/work_queue.h"
 
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h"
+#include "base/task/sequence_manager/work_queue_sets.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/work_queue.h b/base/task/sequence_manager/work_queue.h
similarity index 93%
rename from third_party/blink/renderer/platform/scheduler/base/work_queue.h
rename to base/task/sequence_manager/work_queue.h
index fe1c7d5a..5197949 100644
--- a/third_party/blink/renderer/platform/scheduler/base/work_queue.h
+++ b/base/task/sequence_manager/work_queue.h
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_H_
+#ifndef BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_
+#define BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_
 
+#include "base/base_export.h"
 #include "base/task/sequence_manager/enqueue_order.h"
 #include "base/task/sequence_manager/intrusive_heap.h"
 #include "base/task/sequence_manager/sequenced_task_source.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
 
 namespace base {
 namespace sequence_manager {
@@ -27,7 +28,7 @@
 // API subset used by WorkQueueSets pretends the WorkQueue is empty until the
 // fence is removed.  This functionality is a primitive intended for use by
 // throttling mechanisms.
-class PLATFORM_EXPORT WorkQueue {
+class BASE_EXPORT WorkQueue {
  public:
   using QueueType = internal::TaskQueueImpl::WorkQueueType;
 
@@ -148,4 +149,4 @@
 }  // namespace sequence_manager
 }  // namespace base
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_H_
+#endif  // BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/work_queue_sets.cc b/base/task/sequence_manager/work_queue_sets.cc
similarity index 98%
rename from third_party/blink/renderer/platform/scheduler/base/work_queue_sets.cc
rename to base/task/sequence_manager/work_queue_sets.cc
index 94235c9..e56fc82e 100644
--- a/third_party/blink/renderer/platform/scheduler/base/work_queue_sets.cc
+++ b/base/task/sequence_manager/work_queue_sets.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h"
+#include "base/task/sequence_manager/work_queue_sets.h"
 
 #include "base/logging.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h b/base/task/sequence_manager/work_queue_sets.h
similarity index 84%
rename from third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h
rename to base/task/sequence_manager/work_queue_sets.h
index 8e9fb97e..01db040 100644
--- a/third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h
+++ b/base/task/sequence_manager/work_queue_sets.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
+#ifndef BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_SETS_H_
+#define BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_SETS_H_
 
 #include <map>
 #include <vector>
 
+#include "base/base_export.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/task/sequence_manager/intrusive_heap.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/work_queue.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
 
 namespace base {
 namespace sequence_manager {
@@ -26,7 +26,7 @@
 // TaskQueueSelector chooses to run a task a given priority).  The reason this
 // works is because std::map is a tree based associative container and all the
 // values are kept in sorted order.
-class PLATFORM_EXPORT WorkQueueSets {
+class BASE_EXPORT WorkQueueSets {
  public:
   WorkQueueSets(size_t num_sets, const char* name);
   ~WorkQueueSets();
@@ -99,4 +99,4 @@
 }  // namespace sequence_manager
 }  // namespace base
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_WORK_QUEUE_SETS_H_
+#endif  // BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_SETS_H_
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
index bf89049..d3fad97 100644
--- a/base/threading/thread_perftest.cc
+++ b/base/threading/thread_perftest.cc
@@ -162,7 +162,10 @@
   void Init() override {
     TaskPerfTest::Init();
     for (size_t i = 0; i < threads_.size(); i++) {
-      threads_[i]->message_loop()->AddTaskObserver(&message_loop_observer);
+      threads_[i]->message_loop()->task_runner()->PostTask(
+          FROM_HERE, BindOnce(&MessageLoop::AddTaskObserver,
+                              Unretained(threads_[i]->message_loop()),
+                              Unretained(&message_loop_observer)));
     }
   }
 };
diff --git a/base/timer/mock_timer_unittest.cc b/base/timer/mock_timer_unittest.cc
index 61716a4..45d0388 100644
--- a/base/timer/mock_timer_unittest.cc
+++ b/base/timer/mock_timer_unittest.cc
@@ -15,7 +15,7 @@
 
 TEST(MockTimerTest, FiresOnce) {
   int calls = 0;
-  base::MockTimer timer(false, false);
+  base::MockOneShotTimer timer;
   base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
   timer.Start(FROM_HERE, delay,
               base::Bind(&CallMeMaybe,
@@ -29,7 +29,7 @@
 
 TEST(MockTimerTest, FiresRepeatedly) {
   int calls = 0;
-  base::MockTimer timer(true, true);
+  base::MockRepeatingTimer timer;
   base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
   timer.Start(FROM_HERE, delay,
               base::Bind(&CallMeMaybe,
@@ -44,7 +44,7 @@
 
 TEST(MockTimerTest, Stops) {
   int calls = 0;
-  base::MockTimer timer(true, true);
+  base::MockRepeatingTimer timer;
   base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
   timer.Start(FROM_HERE, delay,
               base::Bind(&CallMeMaybe,
@@ -66,7 +66,7 @@
 TEST(MockTimerTest, DoesNotRetainClosure) {
   HasWeakPtr *has_weak_ptr = new HasWeakPtr();
   base::WeakPtr<HasWeakPtr> weak_ptr(has_weak_ptr->AsWeakPtr());
-  base::MockTimer timer(false, false);
+  base::MockOneShotTimer timer;
   base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
   ASSERT_TRUE(weak_ptr.get());
   timer.Start(FROM_HERE, delay,
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc
index 079c9b4f..4ac38bf8 100644
--- a/cc/animation/animation_host.cc
+++ b/cc/animation/animation_host.cc
@@ -620,12 +620,14 @@
 
   TRACE_EVENT0("cc", "AnimationHost::SetMutationUpdate");
   for (auto& animation_state : output_state->animations) {
-    int id = animation_state.animation_id;
+    WorkletAnimationId id = animation_state.worklet_animation_id;
 
     // TODO(majidvp): Use a map to make lookup O(1)
-    auto to_update =
-        std::find_if(ticking_animations_.begin(), ticking_animations_.end(),
-                     [id](auto& it) { return it->id() == id; });
+    auto to_update = std::find_if(
+        ticking_animations_.begin(), ticking_animations_.end(), [id](auto& it) {
+          return it->IsWorkletAnimation() &&
+                 ToWorkletAnimation(it.get())->worklet_animation_id() == id;
+        });
 
     if (to_update == ticking_animations_.end())
       continue;
diff --git a/cc/animation/worklet_animation.cc b/cc/animation/worklet_animation.cc
index 7692880..4381586 100644
--- a/cc/animation/worklet_animation.cc
+++ b/cc/animation/worklet_animation.cc
@@ -4,6 +4,7 @@
 
 #include "cc/animation/worklet_animation.h"
 
+#include "cc/animation/animation_id_provider.h"
 #include "cc/animation/keyframe_effect.h"
 #include "cc/animation/scroll_timeline.h"
 #include "cc/trees/animation_options.h"
@@ -11,12 +12,14 @@
 namespace cc {
 
 WorkletAnimation::WorkletAnimation(
-    int id,
+    int cc_animation_id,
+    WorkletAnimationId worklet_animation_id,
     const std::string& name,
     std::unique_ptr<ScrollTimeline> scroll_timeline,
     std::unique_ptr<AnimationOptions> options,
     bool is_controlling_instance)
-    : SingleKeyframeEffectAnimation(id),
+    : SingleKeyframeEffectAnimation(cc_animation_id),
+      worklet_animation_id_(worklet_animation_id),
       name_(name),
       scroll_timeline_(std::move(scroll_timeline)),
       options_(std::move(options)),
@@ -28,12 +31,13 @@
 WorkletAnimation::~WorkletAnimation() = default;
 
 scoped_refptr<WorkletAnimation> WorkletAnimation::Create(
-    int id,
+    WorkletAnimationId worklet_animation_id,
     const std::string& name,
     std::unique_ptr<ScrollTimeline> scroll_timeline,
     std::unique_ptr<AnimationOptions> options) {
   return WrapRefCounted(new WorkletAnimation(
-      id, name, std::move(scroll_timeline), std::move(options), false));
+      AnimationIdProvider::NextAnimationId(), worklet_animation_id, name,
+      std::move(scroll_timeline), std::move(options), false));
 }
 
 scoped_refptr<Animation> WorkletAnimation::CreateImplInstance() const {
@@ -41,8 +45,9 @@
   if (scroll_timeline_)
     impl_timeline = scroll_timeline_->CreateImplInstance();
 
-  return WrapRefCounted(new WorkletAnimation(
-      id(), name(), std::move(impl_timeline), CloneOptions(), true));
+  return WrapRefCounted(new WorkletAnimation(id(), worklet_animation_id_,
+                                             name(), std::move(impl_timeline),
+                                             CloneOptions(), true));
 }
 
 void WorkletAnimation::PushPropertiesTo(Animation* animation_impl) {
@@ -89,15 +94,15 @@
 
   switch (state_) {
     case State::PENDING:
-      input_state->added_and_updated_animations.push_back(
-          {id(), name(), current_time, CloneOptions()});
+      input_state->Add(
+          {worklet_animation_id(), name(), current_time, CloneOptions()});
       state_ = State::RUNNING;
       break;
     case State::RUNNING:
-      input_state->updated_animations.push_back({id(), current_time});
+      input_state->Update({worklet_animation_id(), current_time});
       break;
     case State::REMOVED:
-      input_state->removed_animations.push_back(id());
+      input_state->Remove(worklet_animation_id());
       break;
   }
 }
diff --git a/cc/animation/worklet_animation.h b/cc/animation/worklet_animation.h
index 5a2497a..d30771b 100644
--- a/cc/animation/worklet_animation.h
+++ b/cc/animation/worklet_animation.h
@@ -24,18 +24,20 @@
     : public SingleKeyframeEffectAnimation {
  public:
   enum class State { PENDING, RUNNING, REMOVED };
-  WorkletAnimation(int id,
+  WorkletAnimation(int cc_animation_id,
+                   WorkletAnimationId worklet_animation_id,
                    const std::string& name,
                    std::unique_ptr<ScrollTimeline> scroll_timeline,
                    std::unique_ptr<AnimationOptions> options,
                    bool is_controlling_instance);
   static scoped_refptr<WorkletAnimation> Create(
-      int id,
+      WorkletAnimationId worklet_animation_id,
       const std::string& name,
       std::unique_ptr<ScrollTimeline> scroll_timeline,
       std::unique_ptr<AnimationOptions> options);
   scoped_refptr<Animation> CreateImplInstance() const override;
 
+  WorkletAnimationId worklet_animation_id() { return worklet_animation_id_; }
   const std::string& name() const { return name_; }
   const ScrollTimeline* scroll_timeline() const {
     return scroll_timeline_.get();
@@ -83,6 +85,7 @@
     return options_ ? options_->Clone() : nullptr;
   }
 
+  WorkletAnimationId worklet_animation_id_;
   std::string name_;
 
   // The ScrollTimeline associated with the underlying animation. If null, the
diff --git a/cc/animation/worklet_animation_unittest.cc b/cc/animation/worklet_animation_unittest.cc
index 939eecf4..058deac1 100644
--- a/cc/animation/worklet_animation_unittest.cc
+++ b/cc/animation/worklet_animation_unittest.cc
@@ -33,20 +33,20 @@
 
     worklet_animation_ = WorkletAnimation::Create(
         worklet_animation_id_, "test_name", nullptr, nullptr);
-
+    int cc_id = worklet_animation_->id();
     worklet_animation_->AttachElement(element_id_);
     host_->AddAnimationTimeline(timeline_);
     timeline_->AttachAnimation(worklet_animation_);
 
     host_->PushPropertiesTo(host_impl_);
     timeline_impl_ = host_impl_->GetTimelineById(timeline_id_);
-    worklet_animation_impl_ = ToWorkletAnimation(
-        timeline_impl_->GetAnimationById(worklet_animation_id_));
+    worklet_animation_impl_ =
+        ToWorkletAnimation(timeline_impl_->GetAnimationById(cc_id));
   }
 
   scoped_refptr<WorkletAnimation> worklet_animation_;
   scoped_refptr<WorkletAnimation> worklet_animation_impl_;
-  int worklet_animation_id_ = 11;
+  WorkletAnimationId worklet_animation_id_{11, 12};
 };
 
 class MockScrollTimeline : public ScrollTimeline {
@@ -73,8 +73,7 @@
   host_impl_->ActivateAnimations();
 
   base::TimeDelta local_time = base::TimeDelta::FromSecondsD(duration / 2);
-
-  worklet_animation_impl_->SetOutputState({0, local_time});
+  worklet_animation_impl_->SetOutputState({worklet_animation_id_, local_time});
 
   TickAnimationsTransferEvents(base::TimeTicks(), 0u);
 
@@ -157,7 +156,9 @@
       std::make_unique<MutatorInputState>();
   worklet_animation->UpdateInputState(state.get(), base::TimeTicks::Now(),
                                       scroll_tree, true);
-  EXPECT_EQ(1234, state->added_and_updated_animations[0].current_time);
+  std::unique_ptr<AnimationWorkletInput> input =
+      state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(1234, input->added_and_updated_animations[0].current_time);
 }
 
 TEST_F(WorkletAnimationTest,
@@ -173,23 +174,25 @@
       base::TimeTicks() + base::TimeDelta::FromMillisecondsD(111 + 246.8);
 
   ScrollTree scroll_tree;
-  std::unique_ptr<MutatorInputState> first_state =
+  std::unique_ptr<MutatorInputState> state =
       std::make_unique<MutatorInputState>();
-  worklet_animation->UpdateInputState(first_state.get(), first_ticks,
-                                      scroll_tree, true);
+  worklet_animation->UpdateInputState(state.get(), first_ticks, scroll_tree,
+                                      true);
   // First state request sets the start time and thus current time should be 0.
-  EXPECT_EQ(0, first_state->added_and_updated_animations[0].current_time);
-  std::unique_ptr<MutatorInputState> second_state =
-      std::make_unique<MutatorInputState>();
-  worklet_animation->UpdateInputState(second_state.get(), second_ticks,
-                                      scroll_tree, true);
-  EXPECT_EQ(123.4, second_state->updated_animations[0].current_time);
+  std::unique_ptr<AnimationWorkletInput> input =
+      state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(0, input->added_and_updated_animations[0].current_time);
+  state.reset(new MutatorInputState);
+  worklet_animation->UpdateInputState(state.get(), second_ticks, scroll_tree,
+                                      true);
+  input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(123.4, input->updated_animations[0].current_time);
   // Should always offset from start time.
-  std::unique_ptr<MutatorInputState> third_state =
-      std::make_unique<MutatorInputState>();
-  worklet_animation->UpdateInputState(third_state.get(), third_ticks,
-                                      scroll_tree, true);
-  EXPECT_EQ(246.8, third_state->updated_animations[0].current_time);
+  state.reset(new MutatorInputState());
+  worklet_animation->UpdateInputState(state.get(), third_ticks, scroll_tree,
+                                      true);
+  input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(246.8, input->updated_animations[0].current_time);
 }
 
 // This test verifies that worklet animation state is properly updated.
@@ -223,10 +226,12 @@
   base::TimeTicks time;
   worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
                                             true);
-  EXPECT_EQ(state->added_and_updated_animations.size(), 1u);
-  EXPECT_EQ("test_name", state->added_and_updated_animations[0].name);
-  EXPECT_EQ(state->updated_animations.size(), 0u);
-  EXPECT_EQ(state->removed_animations.size(), 0u);
+  std::unique_ptr<AnimationWorkletInput> input =
+      state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(input->added_and_updated_animations.size(), 1u);
+  EXPECT_EQ("test_name", input->added_and_updated_animations[0].name);
+  EXPECT_EQ(input->updated_animations.size(), 0u);
+  EXPECT_EQ(input->removed_animations.size(), 0u);
 
   // The state of WorkletAnimation is updated to RUNNING after calling
   // UpdateInputState above.
@@ -234,9 +239,10 @@
   time += base::TimeDelta::FromSecondsD(0.1);
   worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
                                             true);
-  EXPECT_EQ(state->added_and_updated_animations.size(), 0u);
-  EXPECT_EQ(state->updated_animations.size(), 1u);
-  EXPECT_EQ(state->removed_animations.size(), 0u);
+  input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+  EXPECT_EQ(input->updated_animations.size(), 1u);
+  EXPECT_EQ(input->removed_animations.size(), 0u);
 
   // Operating on individual KeyframeModel doesn't affect the state of
   // WorkletAnimation.
@@ -245,9 +251,10 @@
   time += base::TimeDelta::FromSecondsD(0.1);
   worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
                                             true);
-  EXPECT_EQ(state->added_and_updated_animations.size(), 0u);
-  EXPECT_EQ(state->updated_animations.size(), 1u);
-  EXPECT_EQ(state->removed_animations.size(), 0u);
+  input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+  EXPECT_EQ(input->updated_animations.size(), 1u);
+  EXPECT_EQ(input->removed_animations.size(), 0u);
 
   // WorkletAnimation sets state to REMOVED when JavaScript fires cancel() which
   // leads to RemoveKeyframeModels.
@@ -256,10 +263,11 @@
   state.reset(new MutatorInputState());
   worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
                                             true);
-  EXPECT_EQ(state->added_and_updated_animations.size(), 0u);
-  EXPECT_EQ(state->updated_animations.size(), 0u);
-  EXPECT_EQ(state->removed_animations.size(), 1u);
-  EXPECT_EQ(state->removed_animations[0], worklet_animation_id_);
+  input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(input->added_and_updated_animations.size(), 0u);
+  EXPECT_EQ(input->updated_animations.size(), 0u);
+  EXPECT_EQ(input->removed_animations.size(), 1u);
+  EXPECT_EQ(input->removed_animations[0], worklet_animation_id_);
 }
 
 // This test verifies that worklet animation gets skipped properly.
@@ -289,21 +297,25 @@
   base::TimeTicks time;
   worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
                                             true);
-  EXPECT_EQ(state->added_and_updated_animations.size(), 1u);
-  EXPECT_EQ(state->updated_animations.size(), 0u);
+  std::unique_ptr<AnimationWorkletInput> input =
+      state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(input->added_and_updated_animations.size(), 1u);
+  EXPECT_EQ(input->updated_animations.size(), 0u);
 
   state.reset(new MutatorInputState());
   // No update on the input state if input time stays the same.
   worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
                                             true);
-  EXPECT_EQ(state->updated_animations.size(), 0u);
+  input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_FALSE(input);
 
   state.reset(new MutatorInputState());
   // Different input time causes the input state to be updated.
   time += base::TimeDelta::FromSecondsD(0.1);
   worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
                                             true);
-  EXPECT_EQ(state->updated_animations.size(), 1u);
+  input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(input->updated_animations.size(), 1u);
 
   state.reset(new MutatorInputState());
   // Input state gets updated when the worklet animation is to be removed even
@@ -311,8 +323,9 @@
   worklet_animation_impl_->RemoveKeyframeModels();
   worklet_animation_impl_->UpdateInputState(state.get(), time, scroll_tree,
                                             true);
-  EXPECT_EQ(state->updated_animations.size(), 0u);
-  EXPECT_EQ(state->removed_animations.size(), 1u);
+  input = state->TakeWorkletState(worklet_animation_id_.scope_id);
+  EXPECT_EQ(input->updated_animations.size(), 0u);
+  EXPECT_EQ(input->removed_animations.size(), 1u);
 }
 
 }  // namespace
diff --git a/cc/scheduler/compositor_timing_history.cc b/cc/scheduler/compositor_timing_history.cc
index 20f2e5b4..d6fe934 100644
--- a/cc/scheduler/compositor_timing_history.cc
+++ b/cc/scheduler/compositor_timing_history.cc
@@ -282,10 +282,9 @@
  public:
   ~BrowserUMAReporter() override = default;
 
-  void AddBeginMainFrameIntervalCritical(base::TimeDelta interval) override {
-    UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
-        "Scheduling.Browser.BeginMainFrameIntervalCritical", interval);
-  }
+  // BeginMainFrameIntervalCritical is not meaningful to measure on browser
+  // side because browser rendering fps is not at 60.
+  void AddBeginMainFrameIntervalCritical(base::TimeDelta interval) override {}
 
   void AddBeginMainFrameIntervalNotCritical(base::TimeDelta interval) override {
     UMA_HISTOGRAM_CUSTOM_TIMES_VSYNC_ALIGNED(
diff --git a/cc/trees/layer_tree_mutator.cc b/cc/trees/layer_tree_mutator.cc
index 801e3ad..addb471 100644
--- a/cc/trees/layer_tree_mutator.cc
+++ b/cc/trees/layer_tree_mutator.cc
@@ -4,25 +4,88 @@
 
 #include "cc/trees/layer_tree_mutator.h"
 
+#include <algorithm>
+
 namespace cc {
 
-MutatorInputState::AddAndUpdateState::AddAndUpdateState(
-    int animation_id,
+AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState(
+    WorkletAnimationId worklet_animation_id,
     std::string name,
     double current_time,
     std::unique_ptr<AnimationOptions> options)
-    : animation_id(animation_id),
+    : worklet_animation_id(worklet_animation_id),
       name(name),
       current_time(current_time),
       options(std::move(options)) {}
-MutatorInputState::AddAndUpdateState::AddAndUpdateState(AddAndUpdateState&&) =
-    default;
-MutatorInputState::AddAndUpdateState::~AddAndUpdateState() = default;
+AnimationWorkletInput::AddAndUpdateState::AddAndUpdateState(
+    AddAndUpdateState&&) = default;
+AnimationWorkletInput::AddAndUpdateState::~AddAndUpdateState() = default;
+
+#if DCHECK_IS_ON()
+bool AnimationWorkletInput::ValidateScope(int scope_id) const {
+  return std::all_of(added_and_updated_animations.cbegin(),
+                     added_and_updated_animations.cend(),
+                     [scope_id](auto& it) {
+                       return it.worklet_animation_id.scope_id == scope_id;
+                     }) &&
+         std::all_of(updated_animations.cbegin(), updated_animations.cend(),
+                     [scope_id](auto& it) {
+                       return it.worklet_animation_id.scope_id == scope_id;
+                     }) &&
+         std::all_of(removed_animations.cbegin(), removed_animations.cend(),
+                     [scope_id](auto& it) { return it.scope_id == scope_id; });
+}
+#endif
+
+AnimationWorkletInput::AnimationWorkletInput() = default;
+AnimationWorkletInput::~AnimationWorkletInput() = default;
 
 MutatorInputState::MutatorInputState() = default;
 MutatorInputState::~MutatorInputState() = default;
 
-MutatorOutputState::MutatorOutputState() = default;
-MutatorOutputState::~MutatorOutputState() = default;
+bool MutatorInputState::IsEmpty() const {
+  // If there is an AnimationWorkletInput entry in the map then that entry is
+  // guranteed to be non-empty. So checking |inputs_| map emptiness is
+  // sufficient.
+  return inputs_.empty();
+}
+
+AnimationWorkletInput& MutatorInputState::EnsureWorkletEntry(int id) {
+  auto it = inputs_.find(id);
+  if (it == inputs_.end())
+    it = inputs_.emplace_hint(it, id, new AnimationWorkletInput);
+
+  return *it->second;
+}
+
+void MutatorInputState::Add(AnimationWorkletInput::AddAndUpdateState&& state) {
+  AnimationWorkletInput& worklet_input =
+      EnsureWorkletEntry(state.worklet_animation_id.scope_id);
+  worklet_input.added_and_updated_animations.push_back(std::move(state));
+}
+void MutatorInputState::Update(AnimationWorkletInput::UpdateState&& state) {
+  AnimationWorkletInput& worklet_input =
+      EnsureWorkletEntry(state.worklet_animation_id.scope_id);
+  worklet_input.updated_animations.push_back(std::move(state));
+}
+void MutatorInputState::Remove(WorkletAnimationId worklet_animation_id) {
+  AnimationWorkletInput& worklet_input =
+      EnsureWorkletEntry(worklet_animation_id.scope_id);
+  worklet_input.removed_animations.push_back(worklet_animation_id);
+}
+
+std::unique_ptr<AnimationWorkletInput> MutatorInputState::TakeWorkletState(
+    int scope_id) {
+  auto it = inputs_.find(scope_id);
+  if (it == inputs_.end())
+    return nullptr;
+
+  std::unique_ptr<AnimationWorkletInput> result = std::move(it->second);
+  inputs_.erase(it);
+  return result;
+}
+
+AnimationWorkletOutput::AnimationWorkletOutput() = default;
+AnimationWorkletOutput::~AnimationWorkletOutput() = default;
 
 }  // namespace cc
diff --git a/cc/trees/layer_tree_mutator.h b/cc/trees/layer_tree_mutator.h
index dec770b..700549f 100644
--- a/cc/trees/layer_tree_mutator.h
+++ b/cc/trees/layer_tree_mutator.h
@@ -12,50 +12,96 @@
 
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 namespace cc {
 
-struct CC_EXPORT MutatorInputState {
+struct CC_EXPORT WorkletAnimationId {
+  // Uniquely identifies the animation worklet with which this animation is
+  // associated.
+  int scope_id;
+  // Uniquely identifies the animation within its animation worklet. Note that
+  // animation_id is only guaranteed to be unique per animation worklet.
+  int animation_id;
+
+  inline bool operator==(const WorkletAnimationId& rhs) const {
+    return (this->scope_id == rhs.scope_id) &&
+           (this->animation_id == rhs.animation_id);
+  }
+};
+
+struct CC_EXPORT AnimationWorkletInput {
   struct CC_EXPORT AddAndUpdateState {
-    int animation_id;
+    WorkletAnimationId worklet_animation_id;
     // Name associated with worklet animation.
     std::string name;
     // Worklet animation's current time, from its associated timeline.
     double current_time;
     std::unique_ptr<AnimationOptions> options;
 
-    AddAndUpdateState(int animation_id,
+    AddAndUpdateState(WorkletAnimationId worklet_animation_id,
                       std::string name,
                       double current_time,
                       std::unique_ptr<AnimationOptions> options);
+
     AddAndUpdateState(AddAndUpdateState&&);
     ~AddAndUpdateState();
   };
   struct CC_EXPORT UpdateState {
-    int animation_id = 0;
+    WorkletAnimationId worklet_animation_id;
     // Worklet animation's current time, from its associated timeline.
     double current_time = 0;
   };
 
+  // Note: When adding any new fields please also update ValidateScope to
+  // reflect them if necessary.
+  std::vector<AddAndUpdateState> added_and_updated_animations;
+  std::vector<UpdateState> updated_animations;
+  std::vector<WorkletAnimationId> removed_animations;
+
+  AnimationWorkletInput();
+  ~AnimationWorkletInput();
+
+#if DCHECK_IS_ON()
+  // Verifies all animation states have the expected scope id.
+  bool ValidateScope(int scope_id) const;
+#endif
+  DISALLOW_COPY_AND_ASSIGN(AnimationWorkletInput);
+};
+
+class CC_EXPORT MutatorInputState {
+ public:
   MutatorInputState();
   ~MutatorInputState();
 
-  bool IsEmpty() {
-    return added_and_updated_animations.empty() && updated_animations.empty() &&
-           removed_animations.empty();
-  }
+  bool IsEmpty() const;
+  void Add(AnimationWorkletInput::AddAndUpdateState&& state);
+  void Update(AnimationWorkletInput::UpdateState&& state);
+  void Remove(WorkletAnimationId worklet_animation_id);
 
-  std::vector<AddAndUpdateState> added_and_updated_animations;
-  std::vector<UpdateState> updated_animations;
-  std::vector<int> removed_animations;
+  // Returns input for animation worklet with the given |scope_id| and nullptr
+  // if there is no input.
+  std::unique_ptr<AnimationWorkletInput> TakeWorkletState(int scope_id);
+
+ private:
+  using InputMap =
+      std::unordered_map<int, std::unique_ptr<AnimationWorkletInput>>;
+
+  // Maps a scope id to its associated AnimationWorkletInput instance.
+  // Only contains scope ids for which there is a non-empty input.
+  InputMap inputs_;
+
+  // Returns iterator pointing to the entry in |inputs_| map whose key is id. It
+  // inserts a new entry if none exists.
+  AnimationWorkletInput& EnsureWorkletEntry(int id);
 
   DISALLOW_COPY_AND_ASSIGN(MutatorInputState);
 };
 
-struct CC_EXPORT MutatorOutputState {
+struct CC_EXPORT AnimationWorkletOutput {
   struct CC_EXPORT AnimationState {
-    int animation_id = 0;
+    WorkletAnimationId worklet_animation_id;
     // The animator effect's local time.
     // TODO(majidvp): This assumes each animator has a single output effect
     // which does not hold once we state support group effects.
@@ -63,12 +109,16 @@
     base::TimeDelta local_time;
   };
 
-  MutatorOutputState();
-  ~MutatorOutputState();
+  AnimationWorkletOutput();
+  ~AnimationWorkletOutput();
 
   std::vector<AnimationState> animations;
 };
 
+// LayerTreeMutatorClient processes worklet outputs individually so we can
+// define mutator output to be the same as animation worklet output.
+using MutatorOutputState = AnimationWorkletOutput;
+
 class LayerTreeMutatorClient {
  public:
   // Called when mutator needs to update its output.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 2a8b891..94114c4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -162,29 +162,25 @@
  */
 public class ChromeTabbedActivity
         extends ChromeActivity implements OverviewModeObserver, ScreenshotMonitorDelegate {
+    @IntDef({BackPressedResult.NOTHING_HAPPENED, BackPressedResult.HELP_URL_CLOSED,
+            BackPressedResult.MINIMIZED_NO_TAB_CLOSED, BackPressedResult.MINIMIZED_TAB_CLOSED,
+            BackPressedResult.TAB_CLOSED, BackPressedResult.TAB_IS_NULL,
+            BackPressedResult.EXITED_TAB_SWITCHER, BackPressedResult.EXITED_FULLSCREEN,
+            BackPressedResult.NAVIGATED_BACK})
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-        BACK_PRESSED_NOTHING_HAPPENED,
-        BACK_PRESSED_HELP_URL_CLOSED,
-        BACK_PRESSED_MINIMIZED_NO_TAB_CLOSED,
-        BACK_PRESSED_MINIMIZED_TAB_CLOSED,
-        BACK_PRESSED_TAB_CLOSED,
-        BACK_PRESSED_TAB_IS_NULL,
-        BACK_PRESSED_EXITED_TAB_SWITCHER,
-        BACK_PRESSED_EXITED_FULLSCREEN,
-        BACK_PRESSED_NAVIGATED_BACK
-    })
-    private @interface BackPressedResult {}
-    private static final int BACK_PRESSED_NOTHING_HAPPENED = 0;
-    private static final int BACK_PRESSED_HELP_URL_CLOSED = 1;
-    private static final int BACK_PRESSED_MINIMIZED_NO_TAB_CLOSED = 2;
-    private static final int BACK_PRESSED_MINIMIZED_TAB_CLOSED = 3;
-    private static final int BACK_PRESSED_TAB_CLOSED = 4;
-    private static final int BACK_PRESSED_TAB_IS_NULL = 5;
-    private static final int BACK_PRESSED_EXITED_TAB_SWITCHER = 6;
-    private static final int BACK_PRESSED_EXITED_FULLSCREEN = 7;
-    private static final int BACK_PRESSED_NAVIGATED_BACK = 8;
-    private static final int BACK_PRESSED_COUNT = 9;
+    private @interface BackPressedResult {
+        int NOTHING_HAPPENED = 0;
+        int HELP_URL_CLOSED = 1;
+        int MINIMIZED_NO_TAB_CLOSED = 2;
+        int MINIMIZED_TAB_CLOSED = 3;
+        int TAB_CLOSED = 4;
+        int TAB_IS_NULL = 5;
+        int EXITED_TAB_SWITCHER = 6;
+        int EXITED_FULLSCREEN = 7;
+        int NAVIGATED_BACK = 8;
+
+        int NUM_ENTRIES = 9;
+    }
 
     private static final String TAG = "ChromeTabbedActivity";
 
@@ -1703,8 +1699,8 @@
     private void recordBackPressedUma(String logMessage, @BackPressedResult int action) {
         Log.i(TAG, "Back pressed: " + logMessage);
         RecordHistogram.recordEnumeratedHistogram(
-                "Android.Activity.ChromeTabbedActivity.SystemBackAction",
-                action, BACK_PRESSED_COUNT);
+                "Android.Activity.ChromeTabbedActivity.SystemBackAction", action,
+                BackPressedResult.NUM_ENTRIES);
     }
 
     private void recordLauncherShortcutAction(boolean isIncognito) {
@@ -1736,7 +1732,7 @@
         final Tab currentTab = getActivityTab();
 
         if (exitFullscreenIfShowing()) {
-            recordBackPressedUma("Exited fullscreen", BACK_PRESSED_EXITED_FULLSCREEN);
+            recordBackPressedUma("Exited fullscreen", BackPressedResult.EXITED_FULLSCREEN);
             return true;
         }
 
@@ -1745,20 +1741,20 @@
         if (mTabModalHandler.handleBackPress()) return true;
 
         if (currentTab == null) {
-            recordBackPressedUma("currentTab is null", BACK_PRESSED_TAB_IS_NULL);
+            recordBackPressedUma("currentTab is null", BackPressedResult.TAB_IS_NULL);
             moveTaskToBack(true);
             return true;
         }
 
         // If we are in overview mode and not a tablet, then leave overview mode on back.
         if (mLayoutManager.overviewVisible() && !isTablet()) {
-            recordBackPressedUma("Hid overview", BACK_PRESSED_EXITED_TAB_SWITCHER);
+            recordBackPressedUma("Hid overview", BackPressedResult.EXITED_TAB_SWITCHER);
             mLayoutManager.hideOverview(true);
             return true;
         }
 
         if (getToolbarManager().back()) {
-            recordBackPressedUma("Navigating backward", BACK_PRESSED_NAVIGATED_BACK);
+            recordBackPressedUma("Navigating backward", BackPressedResult.NAVIGATED_BACK);
             return true;
         }
 
@@ -1769,7 +1765,7 @@
         final boolean helpUrl = currentTab.getUrl().startsWith(HELP_URL_PREFIX);
         if (type == TabLaunchType.FROM_CHROME_UI && helpUrl) {
             getCurrentTabModel().closeTab(currentTab);
-            recordBackPressedUma("Closed tab for help URL", BACK_PRESSED_HELP_URL_CLOSED);
+            recordBackPressedUma("Closed tab for help URL", BackPressedResult.HELP_URL_CLOSED);
             return true;
         }
 
@@ -1782,24 +1778,26 @@
         final boolean minimizeApp = !shouldCloseTab || currentTab.isCreatedForExternalApp();
         if (minimizeApp) {
             if (shouldCloseTab) {
-                recordBackPressedUma("Minimized and closed tab", BACK_PRESSED_MINIMIZED_TAB_CLOSED);
+                recordBackPressedUma(
+                        "Minimized and closed tab", BackPressedResult.MINIMIZED_TAB_CLOSED);
                 mActivityStopMetrics.setStopReason(ActivityStopMetrics.STOP_REASON_BACK_BUTTON);
                 sendToBackground(currentTab);
                 return true;
             } else {
-                recordBackPressedUma("Minimized, kept tab", BACK_PRESSED_MINIMIZED_NO_TAB_CLOSED);
+                recordBackPressedUma(
+                        "Minimized, kept tab", BackPressedResult.MINIMIZED_NO_TAB_CLOSED);
                 mActivityStopMetrics.setStopReason(ActivityStopMetrics.STOP_REASON_BACK_BUTTON);
                 sendToBackground(null);
                 return true;
             }
         } else if (shouldCloseTab) {
-            recordBackPressedUma("Tab closed", BACK_PRESSED_TAB_CLOSED);
+            recordBackPressedUma("Tab closed", BackPressedResult.TAB_CLOSED);
             getCurrentTabModel().closeTab(currentTab, true, false, false);
             return true;
         }
 
         assert false : "The back button should have already been handled by this point";
-        recordBackPressedUma("Unhandled", BACK_PRESSED_NOTHING_HAPPENED);
+        recordBackPressedUma("Unhandled", BackPressedResult.NOTHING_HAPPENED);
         return false;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java b/chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java
index 86ab9e2e..801e50a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DevToolsServer.java
@@ -5,11 +5,15 @@
 package org.chromium.chrome.browser;
 
 import android.content.pm.PackageManager;
+import android.support.annotation.IntDef;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Controller for Remote Web Debugging (Developer Tools).
  */
@@ -19,13 +23,14 @@
     private long mNativeDevToolsServer;
 
     // Defines what processes may access to the socket.
-    public enum Security {
+    @IntDef({Security.DEFAULT, Security.ALLOW_DEBUG_PERMISSION})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Security {
         // Use content::CanUserConnectToDevTools to authorize access to the socket.
-        DEFAULT,
-
+        int DEFAULT = 0;
         // In addition to default authorization allows access to an app with android permission
         // named chromeAppPackageName + DEBUG_PERMISSION_SIFFIX.
-        ALLOW_DEBUG_PERMISSION,
+        int ALLOW_DEBUG_PERMISSION = 1;
     }
 
     public DevToolsServer(String socketNamePrefix) {
@@ -41,7 +46,7 @@
         return nativeIsRemoteDebuggingEnabled(mNativeDevToolsServer);
     }
 
-    public void setRemoteDebuggingEnabled(boolean enabled, Security security) {
+    public void setRemoteDebuggingEnabled(boolean enabled, @Security int security) {
         boolean allowDebugPermission = security == Security.ALLOW_DEBUG_PERMISSION;
         nativeSetRemoteDebuggingEnabled(mNativeDevToolsServer, enabled, allowDebugPermission);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
index eed0fcf..f1cf7955 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
@@ -92,19 +92,18 @@
 
     private static final int EXPIRATION_FIELDS_LENGTH = 2;
 
-    public static final int ERROR_TYPE_EXPIRATION_MONTH = 1;
-    public static final int ERROR_TYPE_EXPIRATION_YEAR = 2;
-    public static final int ERROR_TYPE_EXPIRATION_DATE = 3;
-    public static final int ERROR_TYPE_CVC = 4;
-    public static final int ERROR_TYPE_CVC_AND_EXPIRATION = 5;
-    public static final int ERROR_TYPE_NOT_ENOUGH_INFO = 6;
-    public static final int ERROR_TYPE_NONE = 7;
-
+    @IntDef({ErrorType.EXPIRATION_MONTH, ErrorType.EXPIRATION_YEAR, ErrorType.EXPIRATION_DATE,
+            ErrorType.CVC, ErrorType.CVC_AND_EXPIRATION, ErrorType.NOT_ENOUGH_INFO, ErrorType.NONE})
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ERROR_TYPE_EXPIRATION_MONTH, ERROR_TYPE_EXPIRATION_YEAR, ERROR_TYPE_EXPIRATION_DATE,
-            ERROR_TYPE_CVC, ERROR_TYPE_CVC_AND_EXPIRATION, ERROR_TYPE_NOT_ENOUGH_INFO,
-            ERROR_TYPE_NONE})
-    public @interface ErrorType {}
+    public @interface ErrorType {
+        int EXPIRATION_MONTH = 1;
+        int EXPIRATION_YEAR = 2;
+        int EXPIRATION_DATE = 3;
+        int CVC = 4;
+        int CVC_AND_EXPIRATION = 5;
+        int NOT_ENOUGH_INFO = 6;
+        int NONE = 7;
+    }
 
     /**
      * An interface to handle the interaction with an CardUnmaskPrompt object.
@@ -350,7 +349,7 @@
         Button positiveButton = mDialog.getButton(ModalDialogView.BUTTON_POSITIVE);
 
         @ErrorType int errorType = getExpirationAndCvcErrorType();
-        positiveButton.setEnabled(errorType == ERROR_TYPE_NONE);
+        positiveButton.setEnabled(errorType == ErrorType.NONE);
         showDetailedErrorMessage(errorType);
         moveFocus(errorType);
 
@@ -457,7 +456,7 @@
      * @param errorType The type of error detected.
      */
     private void moveFocus(@ErrorType int errorType) {
-        if (errorType == ERROR_TYPE_NOT_ENOUGH_INFO) {
+        if (errorType == ErrorType.NOT_ENOUGH_INFO) {
             if (mMonthInput.isFocused()
                     && mMonthInput.getText().length() == EXPIRATION_FIELDS_LENGTH) {
                 // The user just finished typing in the month field and there are no validation
@@ -489,28 +488,23 @@
      */
     private void showDetailedErrorMessage(@ErrorType int errorType) {
         switch (errorType) {
-            case ERROR_TYPE_EXPIRATION_MONTH:
+            case ErrorType.EXPIRATION_MONTH:
                 showErrorMessage(mExpirationMonthErrorMessage);
                 break;
-
-            case ERROR_TYPE_EXPIRATION_YEAR:
+            case ErrorType.EXPIRATION_YEAR:
                 showErrorMessage(mExpirationYearErrorMessage);
                 break;
-
-            case ERROR_TYPE_EXPIRATION_DATE:
+            case ErrorType.EXPIRATION_DATE:
                 showErrorMessage(mExpirationDateErrorMessage);
                 break;
-
-            case ERROR_TYPE_CVC:
+            case ErrorType.CVC:
                 showErrorMessage(mCvcErrorMessage);
                 break;
-
-            case ERROR_TYPE_CVC_AND_EXPIRATION:
+            case ErrorType.CVC_AND_EXPIRATION:
                 showErrorMessage(mCvcAndExpirationErrorMessage);
                 break;
-
-            case ERROR_TYPE_NONE:
-            case ERROR_TYPE_NOT_ENOUGH_INFO:
+            case ErrorType.NONE:
+            case ErrorType.NOT_ENOUGH_INFO:
             default:
                 clearInputError();
                 return;
@@ -536,14 +530,13 @@
                         PorterDuff.Mode.SRC_IN);
 
         // Decide on what field(s) to apply the filter.
-        boolean filterMonth = errorType == ERROR_TYPE_EXPIRATION_MONTH
-                || errorType == ERROR_TYPE_EXPIRATION_DATE
-                || errorType == ERROR_TYPE_CVC_AND_EXPIRATION;
-        boolean filterYear = errorType == ERROR_TYPE_EXPIRATION_YEAR
-                || errorType == ERROR_TYPE_EXPIRATION_DATE
-                || errorType == ERROR_TYPE_CVC_AND_EXPIRATION;
-        boolean filterCvc =
-                errorType == ERROR_TYPE_CVC || errorType == ERROR_TYPE_CVC_AND_EXPIRATION;
+        boolean filterMonth = errorType == ErrorType.EXPIRATION_MONTH
+                || errorType == ErrorType.EXPIRATION_DATE
+                || errorType == ErrorType.CVC_AND_EXPIRATION;
+        boolean filterYear = errorType == ErrorType.EXPIRATION_YEAR
+                || errorType == ErrorType.EXPIRATION_DATE
+                || errorType == ErrorType.CVC_AND_EXPIRATION;
+        boolean filterCvc = errorType == ErrorType.CVC || errorType == ErrorType.CVC_AND_EXPIRATION;
 
         updateColorForInput(mMonthInput, filterMonth ? filter : null);
         updateColorForInput(mYearInput, filterYear ? filter : null);
@@ -557,7 +550,8 @@
      * @return The ErrorType value representing the type of error found for the unmask fields.
      */
     @ErrorType private int getExpirationAndCvcErrorType() {
-        @ErrorType int errorType = ERROR_TYPE_NONE;
+        @ErrorType
+        int errorType = ErrorType.NONE;
 
         if (mShouldRequestExpirationDate) errorType = getExpirationDateErrorType();
 
@@ -567,15 +561,15 @@
         if (mDidFocusOnCvc && !mCardUnmaskInput.isFocused()) {
             // The CVC is invalid and the user has typed in the CVC field, but is not focused on it
             // now. Add the CVC error to the current error.
-            if (errorType == ERROR_TYPE_NONE || errorType == ERROR_TYPE_NOT_ENOUGH_INFO) {
-                errorType = ERROR_TYPE_CVC;
+            if (errorType == ErrorType.NONE || errorType == ErrorType.NOT_ENOUGH_INFO) {
+                errorType = ErrorType.CVC;
             } else {
-                errorType = ERROR_TYPE_CVC_AND_EXPIRATION;
+                errorType = ErrorType.CVC_AND_EXPIRATION;
             }
         } else {
             // The CVC is invalid but the user is not done with the field.
             // If no other errors were detected, set that there is not enough information.
-            if (errorType == ERROR_TYPE_NONE) errorType = ERROR_TYPE_NOT_ENOUGH_INFO;
+            if (errorType == ErrorType.NONE) errorType = ErrorType.NOT_ENOUGH_INFO;
         }
 
         return errorType;
@@ -591,7 +585,7 @@
     @ErrorType private int getExpirationDateErrorType() {
         if (mThisYear == -1 || mThisMonth == -1) {
             mValidationWaitsForCalendarTask = true;
-            return ERROR_TYPE_NOT_ENOUGH_INFO;
+            return ErrorType.NOT_ENOUGH_INFO;
         }
 
         int month = getMonth();
@@ -599,9 +593,9 @@
             if (mMonthInput.getText().length() == EXPIRATION_FIELDS_LENGTH
                     || (!mMonthInput.isFocused() && mDidFocusOnMonth)) {
                 // mFinishedTypingMonth = true;
-                return ERROR_TYPE_EXPIRATION_MONTH;
+                return ErrorType.EXPIRATION_MONTH;
             }
-            return ERROR_TYPE_NOT_ENOUGH_INFO;
+            return ErrorType.NOT_ENOUGH_INFO;
         }
 
         int year = getFourDigitYear();
@@ -609,16 +603,16 @@
             if (mYearInput.getText().length() == EXPIRATION_FIELDS_LENGTH
                     || (!mYearInput.isFocused() && mDidFocusOnYear)) {
                 // mFinishedTypingYear = true;
-                return ERROR_TYPE_EXPIRATION_YEAR;
+                return ErrorType.EXPIRATION_YEAR;
             }
-            return ERROR_TYPE_NOT_ENOUGH_INFO;
+            return ErrorType.NOT_ENOUGH_INFO;
         }
 
         if (year == mThisYear && month < mThisMonth) {
-            return ERROR_TYPE_EXPIRATION_DATE;
+            return ErrorType.EXPIRATION_DATE;
         }
 
-        return ERROR_TYPE_NONE;
+        return ErrorType.NONE;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/component_updater/UpdateScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/component_updater/UpdateScheduler.java
new file mode 100644
index 0000000..1a69649f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/component_updater/UpdateScheduler.java
@@ -0,0 +1,109 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.component_updater;
+
+import android.os.Build;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GoogleApiAvailability;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.components.background_task_scheduler.BackgroundTask.TaskFinishedCallback;
+import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
+import org.chromium.components.background_task_scheduler.TaskIds;
+import org.chromium.components.background_task_scheduler.TaskInfo;
+
+/** Java-side implementation of the component update scheduler using the BackgroundTaskScheduler. */
+@JNINamespace("component_updater")
+public class UpdateScheduler {
+    private static UpdateScheduler sInstance;
+    private TaskFinishedCallback mTaskFinishedCallback;
+    private long mNativeScheduler;
+    private long mDelayMs;
+
+    @CalledByNative
+    /* package */ static UpdateScheduler getInstance() {
+        if (sInstance == null) {
+            sInstance = new UpdateScheduler();
+        }
+        return sInstance;
+    }
+
+    @CalledByNative
+    /* package */ static boolean isAvailable() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
+                || GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(
+                           ContextUtils.getApplicationContext())
+                == ConnectionResult.SUCCESS;
+    }
+
+    /* package */ void onStartTaskBeforeNativeLoaded(TaskFinishedCallback callback) {
+        mTaskFinishedCallback = callback;
+    }
+
+    /* package */ void onStartTaskWithNative() {
+        assert mNativeScheduler != 0;
+        nativeOnStartTask(mNativeScheduler);
+    }
+
+    /* package */ void onStopTask() {
+        if (mNativeScheduler != 0) {
+            nativeOnStopTask(mNativeScheduler);
+        }
+        mTaskFinishedCallback = null;
+        scheduleInternal(mDelayMs);
+    }
+
+    /* package */ void reschedule() {
+        scheduleInternal(mDelayMs);
+    }
+
+    private UpdateScheduler() {}
+
+    private void scheduleInternal(long delayMs) {
+        // Skip re-scheduling if we are currently running the update task. Otherwise, the current
+        // update tasks would be cancelled.
+        if (mTaskFinishedCallback != null) return;
+
+        TaskInfo taskInfo = TaskInfo.createOneOffTask(TaskIds.COMPONENT_UPDATE_JOB_ID,
+                                            UpdateTask.class, delayMs, Integer.MAX_VALUE)
+                                    .setUpdateCurrent(true)
+                                    .setRequiredNetworkType(TaskInfo.NETWORK_TYPE_UNMETERED)
+                                    .setIsPersisted(true)
+                                    .build();
+        BackgroundTaskSchedulerFactory.getScheduler().schedule(
+                ContextUtils.getApplicationContext(), taskInfo);
+    }
+
+    @CalledByNative
+    private void schedule(long initialDelayMs, long delayMs) {
+        mDelayMs = delayMs;
+        scheduleInternal(initialDelayMs);
+    }
+
+    @CalledByNative
+    private void finishTask() {
+        assert mTaskFinishedCallback != null;
+        mTaskFinishedCallback.taskFinished(false);
+        mTaskFinishedCallback = null;
+        scheduleInternal(mDelayMs);
+    }
+
+    @CalledByNative
+    private void setNativeScheduler(long nativeScheduler) {
+        mNativeScheduler = nativeScheduler;
+    }
+
+    @CalledByNative
+    private void cancelTask() {
+        BackgroundTaskSchedulerFactory.getScheduler().cancel(
+                ContextUtils.getApplicationContext(), TaskIds.COMPONENT_UPDATE_JOB_ID);
+    }
+
+    private native void nativeOnStartTask(long nativeBackgroundTaskUpdateScheduler);
+    private native void nativeOnStopTask(long nativeBackgroundTaskUpdateScheduler);
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/component_updater/UpdateTask.java b/chrome/android/java/src/org/chromium/chrome/browser/component_updater/UpdateTask.java
new file mode 100644
index 0000000..9a60f4f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/component_updater/UpdateTask.java
@@ -0,0 +1,54 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.component_updater;
+
+import android.content.Context;
+
+import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask;
+import org.chromium.components.background_task_scheduler.BackgroundTask.TaskFinishedCallback;
+import org.chromium.components.background_task_scheduler.TaskIds;
+import org.chromium.components.background_task_scheduler.TaskParameters;
+
+/** Task for initiating a component update. */
+public class UpdateTask extends NativeBackgroundTask {
+    @Override
+    @StartBeforeNativeResult
+    protected int onStartTaskBeforeNativeLoaded(
+            Context context, TaskParameters taskParameters, TaskFinishedCallback callback) {
+        assert taskParameters.getTaskId() == TaskIds.COMPONENT_UPDATE_JOB_ID;
+        UpdateScheduler.getInstance().onStartTaskBeforeNativeLoaded(callback);
+        return LOAD_NATIVE;
+    }
+
+    @Override
+    protected void onStartTaskWithNative(
+            Context context, TaskParameters taskParameters, TaskFinishedCallback callback) {
+        assert taskParameters.getTaskId() == TaskIds.COMPONENT_UPDATE_JOB_ID;
+        UpdateScheduler.getInstance().onStartTaskWithNative();
+    }
+
+    @Override
+    protected boolean onStopTaskBeforeNativeLoaded(Context context, TaskParameters taskParameters) {
+        assert taskParameters.getTaskId() == TaskIds.COMPONENT_UPDATE_JOB_ID;
+        UpdateScheduler.getInstance().onStopTask();
+
+        // Don't reschedule task here. We are rescheduling with our parameters.
+        return false;
+    }
+
+    @Override
+    protected boolean onStopTaskWithNative(Context context, TaskParameters taskParameters) {
+        assert taskParameters.getTaskId() == TaskIds.COMPONENT_UPDATE_JOB_ID;
+        UpdateScheduler.getInstance().onStopTask();
+
+        // Don't reschedule task here. We are rescheduling with our parameters.
+        return false;
+    }
+
+    @Override
+    public void reschedule(Context context) {
+        UpdateScheduler.getInstance().reschedule();
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
index 832d1f7..3900b86 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java
@@ -60,14 +60,16 @@
     private static final int FAILURE = 0;
     private static final int SUCCESS = 1;
 
-    @StringDef({BROWSER, RENDERER, GPU, OTHER})
-    public @interface ProcessType {}
-    static final String BROWSER = "Browser";
-    static final String RENDERER = "Renderer";
-    static final String GPU = "GPU";
-    static final String OTHER = "Other";
+    @StringDef({ProcessType.BROWSER, ProcessType.RENDERER, ProcessType.GPU, ProcessType.OTHER})
+    public @interface ProcessType {
+        String BROWSER = "Browser";
+        String RENDERER = "Renderer";
+        String GPU = "GPU";
+        String OTHER = "Other";
+    }
 
-    static final String[] TYPES = {BROWSER, RENDERER, GPU, OTHER};
+    static final String[] TYPES = {
+            ProcessType.BROWSER, ProcessType.RENDERER, ProcessType.GPU, ProcessType.OTHER};
 
     public MinidumpUploadService() {
         super(TAG);
@@ -217,23 +219,11 @@
                     // Crash type is on the line after the next line.
                     fileReader.readLine();
                     String crashType = fileReader.readLine();
-                    if (crashType == null) {
-                        return OTHER;
-                    }
-
-                    if (crashType.equals("browser")) {
-                        return BROWSER;
-                    }
-
-                    if (crashType.equals("renderer")) {
-                        return RENDERER;
-                    }
-
-                    if (crashType.equals("gpu-process")) {
-                        return GPU;
-                    }
-
-                    return OTHER;
+                    if (crashType == null) return ProcessType.OTHER;
+                    if (crashType.equals("browser")) return ProcessType.BROWSER;
+                    if (crashType.equals("renderer")) return ProcessType.RENDERER;
+                    if (crashType.equals("gpu-process")) return ProcessType.GPU;
+                    return ProcessType.OTHER;
                 }
             }
         } catch (IOException e) {
@@ -241,7 +231,7 @@
         } finally {
             StreamUtil.closeQuietly(fileReader);
         }
-        return OTHER;
+        return ProcessType.OTHER;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 3dccd16..e1cf797 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -379,6 +379,10 @@
     }
 
     public void setBottomBarContentView(View view) {
+        // This method is currently only used by dynamic modules, and all its known uses require
+        // the shadow to be hidden. If this requirement ever changes, we could introduce an explicit
+        // API for that.
+        mBottomBarDelegate.setShowShadow(false);
         mBottomBarDelegate.setBottomBarContentView(view);
         mBottomBarDelegate.showBottomBarIfNecessary();
     }
@@ -391,6 +395,10 @@
         addContentView(view, layoutParams);
     }
 
+    public void setBottomBarHeight(int height) {
+        mBottomBarDelegate.setBottomBarHeight(height);
+    }
+
     @Override
     public boolean shouldAllocateChildConnection() {
         return !mHasCreatedTabEarly && !mHasSpeculated
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
index 1c53fb6..7a31709 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java
@@ -52,6 +52,13 @@
     private CustomTabIntentDataProvider mDataProvider;
     private PendingIntent mClickPendingIntent;
     private int[] mClickableIDs;
+    private boolean mShowShadow = true;
+
+    /**
+     * The override height in pixels. A value of -1 is interpreted as "not set" and means it should
+     * not be used.
+     */
+    private int mBottomBarHeightOverride = -1;
 
     private OnClickListener mBottomBarClickListener = new OnClickListener() {
         @Override
@@ -77,6 +84,10 @@
     public void showBottomBarIfNecessary() {
         if (!shouldShowBottomBar()) return;
 
+        getBottomBarView()
+                .findViewById(R.id.bottombar_shadow)
+                .setVisibility(mShowShadow ? View.VISIBLE : View.GONE);
+
         if (mBottomBarContentView != null) {
             getBottomBarView().addView(mBottomBarContentView);
             mBottomBarContentView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@@ -84,7 +95,7 @@
                 public void onLayoutChange(View v, int left, int top, int right, int bottom,
                         int oldLeft, int oldTop, int oldRight, int oldBottom) {
                     mBottomBarContentView.removeOnLayoutChangeListener(this);
-                    mFullscreenManager.setBottomControlsHeight(v.getHeight());
+                    mFullscreenManager.setBottomControlsHeight(getBottomBarHeight());
                 }
             });
             return;
@@ -161,6 +172,13 @@
     }
 
     /**
+     * Sets the visibility of the bottom bar shadow.
+     */
+    public void setShowShadow(boolean show) {
+        mShowShadow = show;
+    }
+
+    /**
      * @return The height of the bottom bar, excluding its top shadow.
      */
     public int getBottomBarHeight() {
@@ -168,10 +186,22 @@
                 || mBottomBarView.getChildCount() < 2) {
             return 0;
         }
+        if (mBottomBarHeightOverride != -1) return mBottomBarHeightOverride;
         return mBottomBarView.getChildAt(1).getHeight();
     }
 
     /**
+     * Sets a height override for the bottom bar. If this value is not set, the height of the
+     * content is used instead.
+     *
+     * @param height The override height in pixels. A value of -1 is interpreted as "not set" and
+     *     means it will not be used.
+     */
+    public void setBottomBarHeight(int height) {
+        mBottomBarHeightOverride = height;
+    }
+
+    /**
      * Gets the {@link ViewGroup} of the bottom bar. If it has not been inflated, inflate it first.
      */
     private ViewGroup getBottomBarView() {
@@ -247,7 +277,7 @@
             public void onLayoutChange(View v, int left, int top, int right, int bottom,
                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
                 inflatedView.removeOnLayoutChangeListener(this);
-                mFullscreenManager.setBottomControlsHeight(v.getHeight());
+                mFullscreenManager.setBottomControlsHeight(getBottomBarHeight());
             }
         });
         return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
index e935970..26f2c9f6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java
@@ -32,4 +32,9 @@
     public void setOverlayView(IObjectWrapper overlayView) {
         mActivity.setOverlayView(ObjectWrapper.unwrap(overlayView, View.class));
     }
+
+    @Override
+    public void setBottomBarHeight(int height) {
+        mActivity.setBottomBarHeight(height);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/IActivityHost.aidl b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/IActivityHost.aidl
index abd54d8..17a8f35 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/IActivityHost.aidl
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/IActivityHost.aidl
@@ -12,4 +12,6 @@
   void setBottomBarView(in IObjectWrapper /* View */ bottomBarView) = 1;
 
   void setOverlayView(in IObjectWrapper /* View */ overlayView) = 2;
+
+  void setBottomBarHeight(int height) = 3;
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DirectoryOption.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DirectoryOption.java
index d5a821c..08183dc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DirectoryOption.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DirectoryOption.java
@@ -17,14 +17,16 @@
 public class DirectoryOption {
     // Type to track user's selection of directory option. This enum is used in histogram and must
     // match DownloadLocationDirectoryType in enums.xml, so don't delete or reuse values.
+    @IntDef({DownloadLocationDirectoryType.DEFAULT, DownloadLocationDirectoryType.ADDITIONAL,
+            DownloadLocationDirectoryType.ERROR})
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({DEFAULT_OPTION, ADDITIONAL_OPTION, ERROR_OPTION, OPTION_COUNT})
-    public @interface DownloadLocationDirectoryType {}
+    public @interface DownloadLocationDirectoryType {
+        int DEFAULT = 0;
+        int ADDITIONAL = 1;
+        int ERROR = 2;
 
-    public static final int DEFAULT_OPTION = 0;
-    public static final int ADDITIONAL_OPTION = 1;
-    public static final int ERROR_OPTION = 2;
-    public static final int OPTION_COUNT = 3;
+        int NUM_ENTRIES = 3;
+    }
 
     /**
      * Name of the current download directory.
@@ -77,6 +79,6 @@
      */
     public void recordDirectoryOptionType() {
         RecordHistogram.recordEnumeratedHistogram("MobileDownload.Location.Setting.DirectoryType",
-                type, DirectoryOption.OPTION_COUNT);
+                type, DirectoryOption.DownloadLocationDirectoryType.NUM_ENTRIES);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadDirectoryProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadDirectoryProvider.java
index 7031905..4e4660f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadDirectoryProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadDirectoryProvider.java
@@ -52,12 +52,13 @@
 
             // If no default directory, return an error option.
             if (defaultDirectory == null) {
-                dirs.add(new DirectoryOption(null, 0, 0, DirectoryOption.ERROR_OPTION));
+                dirs.add(new DirectoryOption(
+                        null, 0, 0, DirectoryOption.DownloadLocationDirectoryType.ERROR));
                 return dirs;
             }
 
-            DirectoryOption defaultOption =
-                    toDirectoryOption(defaultDirectory, DirectoryOption.DEFAULT_OPTION);
+            DirectoryOption defaultOption = toDirectoryOption(
+                    defaultDirectory, DirectoryOption.DownloadLocationDirectoryType.DEFAULT);
             dirs.add(defaultOption);
 
             // Retrieve additional directories, i.e. the external SD card directory.
@@ -78,7 +79,8 @@
 
                 // Skip primary storage directory.
                 if (files[i].getAbsolutePath().contains(mExternalStorageDirectory)) continue;
-                dirs.add(toDirectoryOption(files[i], DirectoryOption.ADDITIONAL_OPTION));
+                dirs.add(toDirectoryOption(
+                        files[i], DirectoryOption.DownloadLocationDirectoryType.ADDITIONAL));
             }
             return dirs;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/StorageSummary.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/StorageSummary.java
index 7e0900a7..513023a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/StorageSummary.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/StorageSummary.java
@@ -33,9 +33,10 @@
         protected DirectoryOption doInBackground(Void... params) {
             File defaultDownloadDir =
                     Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
-            DirectoryOption directoryOption = new DirectoryOption("",
-                    defaultDownloadDir.getAbsolutePath(), defaultDownloadDir.getUsableSpace(),
-                    defaultDownloadDir.getTotalSpace(), DirectoryOption.DEFAULT_OPTION);
+            DirectoryOption directoryOption =
+                    new DirectoryOption("", defaultDownloadDir.getAbsolutePath(),
+                            defaultDownloadDir.getUsableSpace(), defaultDownloadDir.getTotalSpace(),
+                            DirectoryOption.DownloadLocationDirectoryType.DEFAULT);
             return directoryOption;
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/download/DownloadDirectoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/download/DownloadDirectoryAdapter.java
index f29bd57..e029caff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/download/DownloadDirectoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/download/DownloadDirectoryAdapter.java
@@ -81,11 +81,9 @@
             return mErrorOptions.get(position);
         }
 
-        if (position < mCanonicalOptions.size()) {
-            return mCanonicalOptions.get(position);
-        } else {
-            return mAdditionalOptions.get(position - mCanonicalOptions.size());
-        }
+        return position < mCanonicalOptions.size()
+                ? mCanonicalOptions.get(position)
+                : mAdditionalOptions.get(position - mCanonicalOptions.size());
     }
 
     @Override
@@ -96,10 +94,9 @@
     @NonNull
     @Override
     public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
-        View view = convertView;
-        if (view == null) {
-            view = mLayoutInflater.inflate(R.layout.download_location_spinner_item, null);
-        }
+        View view = convertView != null
+                ? convertView
+                : mLayoutInflater.inflate(R.layout.download_location_spinner_item, null);
 
         view.setTag(position);
 
@@ -121,10 +118,9 @@
     @Override
     public View getDropDownView(
             int position, @Nullable View convertView, @NonNull ViewGroup parent) {
-        View view = convertView;
-        if (view == null) {
-            view = mLayoutInflater.inflate(R.layout.download_location_spinner_dropdown_item, null);
-        }
+        View view = convertView != null
+                ? convertView
+                : mLayoutInflater.inflate(R.layout.download_location_spinner_dropdown_item, null);
 
         view.setTag(position);
 
@@ -232,11 +228,11 @@
         for (DirectoryOption dir : dirs) {
             DirectoryOption directory = (DirectoryOption) dir.clone();
             switch (directory.type) {
-                case DirectoryOption.DEFAULT_OPTION:
+                case DirectoryOption.DownloadLocationDirectoryType.DEFAULT:
                     directory.name = mContext.getString(R.string.menu_downloads);
                     mCanonicalOptions.add(directory);
                     break;
-                case DirectoryOption.ADDITIONAL_OPTION:
+                case DirectoryOption.DownloadLocationDirectoryType.ADDITIONAL:
                     String directoryName = (numOtherAdditionalDirectories > 0)
                             ? mContext.getString(org.chromium.chrome.R.string
                                                          .downloads_location_sd_card_number,
@@ -247,7 +243,7 @@
                     mAdditionalOptions.add(directory);
                     numOtherAdditionalDirectories++;
                     break;
-                case DirectoryOption.ERROR_OPTION:
+                case DirectoryOption.DownloadLocationDirectoryType.ERROR:
                     directory.name =
                             mContext.getString(R.string.download_location_no_available_locations);
                     mErrorOptions.add(directory);
@@ -273,7 +269,7 @@
         } else {
             mErrorOptions.add(new DirectoryOption(
                     mContext.getString(R.string.download_location_no_available_locations), null, 0,
-                    0, DirectoryOption.ERROR_OPTION));
+                    0, DirectoryOption.DownloadLocationDirectoryType.ERROR));
         }
     }
 }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 55ec569f..eb2458c 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -170,6 +170,8 @@
   "java/src/org/chromium/chrome/browser/browsing_data/UrlFilters.java",
   "java/src/org/chromium/chrome/browser/childaccounts/ChildAccountFeedbackReporter.java",
   "java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java",
+  "java/src/org/chromium/chrome/browser/component_updater/UpdateScheduler.java",
+  "java/src/org/chromium/chrome/browser/component_updater/UpdateTask.java",
   "java/src/org/chromium/chrome/browser/compositor/CompositorSurfaceManager.java",
   "java/src/org/chromium/chrome/browser/compositor/CompositorSurfaceManagerImpl.java",
   "java/src/org/chromium/chrome/browser/compositor/CompositorView.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
index 5048b43..1830419f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/crash/MinidumpUploadServiceTest.java
@@ -4,11 +4,6 @@
 
 package org.chromium.chrome.browser.crash;
 
-import static org.chromium.chrome.browser.crash.MinidumpUploadService.BROWSER;
-import static org.chromium.chrome.browser.crash.MinidumpUploadService.GPU;
-import static org.chromium.chrome.browser.crash.MinidumpUploadService.OTHER;
-import static org.chromium.chrome.browser.crash.MinidumpUploadService.RENDERER;
-
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.job.JobInfo;
@@ -585,8 +580,8 @@
         final File minidumpFile =
                 new File(mTestRule.getCrashDir(), "chromium_renderer-123.dmp.try0");
         CrashTestRule.setUpMinidumpFile(minidumpFile, BOUNDARY, "browser");
-        Assert.assertEquals(
-                BROWSER, MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath()));
+        Assert.assertEquals(MinidumpUploadService.ProcessType.BROWSER,
+                MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath()));
     }
 
     @Test
@@ -596,8 +591,8 @@
         final File minidumpFile =
                 new File(mTestRule.getCrashDir(), "chromium_renderer-123.dmp.try0");
         CrashTestRule.setUpMinidumpFile(minidumpFile, BOUNDARY, "renderer");
-        Assert.assertEquals(
-                RENDERER, MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath()));
+        Assert.assertEquals(MinidumpUploadService.ProcessType.RENDERER,
+                MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath()));
     }
 
     @Test
@@ -607,8 +602,8 @@
         final File minidumpFile =
                 new File(mTestRule.getCrashDir(), "chromium_renderer-123.dmp.try0");
         CrashTestRule.setUpMinidumpFile(minidumpFile, BOUNDARY, "gpu-process");
-        Assert.assertEquals(
-                GPU, MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath()));
+        Assert.assertEquals(MinidumpUploadService.ProcessType.GPU,
+                MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath()));
     }
 
     @Test
@@ -618,8 +613,8 @@
         final File minidumpFile =
                 new File(mTestRule.getCrashDir(), "chromium_renderer-123.dmp.try0");
         CrashTestRule.setUpMinidumpFile(minidumpFile, BOUNDARY, "weird test type");
-        Assert.assertEquals(
-                OTHER, MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath()));
+        Assert.assertEquals(MinidumpUploadService.ProcessType.OTHER,
+                MinidumpUploadService.getCrashType(minidumpFile.getAbsolutePath()));
     }
 
     private class MinidumpPreparationContext extends AdvancedMockContext {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java
index b4c593d..6183b6c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/OAuth2TokenServiceIntegrationTest.java
@@ -158,7 +158,7 @@
 
             // First seed the account state (some native classes make the assumption that
             // a notification that a token was revoked for a given account was preceded by a
-            // notifictation that that account was available).
+            // notification that that account was available).
             mOAuth2TokenService.fireRefreshTokenAvailable(TEST_ACCOUNT1);
             mOAuth2TokenService.fireRefreshTokenAvailable(TEST_ACCOUNT2);
 
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index a9c558e..7733693 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-69.0.3480.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-69.0.3481.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 3ac2ef1..3cdaf48 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -256,6 +256,9 @@
   <message name="IDS_FILE_BROWSER_LINUX_FILES_ROOT_LABEL" desc="A label for the 'Linux Files' root which shows crostini files.">
     Linux Files
   </message>
+  <message name="IDS_FILE_BROWSER_MY_FILES_ROOT_LABEL" desc="A label for the 'My Files' root which is parent of Downloads, Linux and Android files.">
+    My Files
+  </message>
   <message name="IDS_FILE_BROWSER_MEDIA_VIEW_IMAGES_ROOT_LABEL" desc="A label for the 'Images' root of media views.">
     Images
   </message>
@@ -5025,6 +5028,9 @@
   <message name="IDS_CROSTINI_UNINSTALLER_ERROR" desc="Text shown in the Crostini uninstaller dialog when the Linux uninstall process fails.">
     Error uninstalling Linux. Please try again.
   </message>
+  <message name="IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM" desc="Text shown in the context menu for the Linux terminal app, allowing users to shut down the Linux virtual machine.">
+    Shut Down Linux
+  </message>
 
   <!-- Time limit notification -->
   <message name="IDS_SCREEN_TIME_NOTIFICATION_TITLE" desc="The title of the notification when screen usage limit reaches before locking the device.">
diff --git a/chrome/app/chromeos_strings_grdp/IDS_FILE_BROWSER_MY_FILES_ROOT_LABEL.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_FILE_BROWSER_MY_FILES_ROOT_LABEL.png.sha1
new file mode 100644
index 0000000..a089841
--- /dev/null
+++ b/chrome/app/chromeos_strings_grdp/IDS_FILE_BROWSER_MY_FILES_ROOT_LABEL.png.sha1
@@ -0,0 +1 @@
+cef0df144e133cdff7b8997a6b0ecee405e8ec53
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index e56441a..57654fac 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3184,6 +3184,11 @@
       <message name="IDS_UTILITY_PROCESS_FILE_UTILITY_NAME" desc="The name of the utility process used for various Chrome specific file operations.">
           Chrome File Utilities
       </message>
+      <if expr="is_linux">
+        <message name="IDS_UTILITY_PROCESS_FONT_SERVICE_UTILITY_NAME" desc="The name of the utility process used for FontConfig operations for Chrome on Linux.">
+          Linux Font Service
+        </message>
+      </if>
       <if expr="not is_android">
         <message name="IDS_UTILITY_PROCESS_PROFILE_IMPORTER_NAME" desc="The name of the utility process used for importing profiles.">
           Profile Importer
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7f157f0..57025ed 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1954,6 +1954,8 @@
       "android/chrome_startup_flags.h",
       "android/color_helpers.cc",
       "android/color_helpers.h",
+      "android/component_updater/background_task_update_scheduler.cc",
+      "android/component_updater/background_task_update_scheduler.h",
       "android/compositor/compositor_view.cc",
       "android/compositor/compositor_view.h",
       "android/compositor/decoration_title.cc",
@@ -4375,6 +4377,7 @@
       "../android/java/src/org/chromium/chrome/browser/browsing_data/UrlFilterBridge.java",
       "../android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountFeedbackReporter.java",
       "../android/java/src/org/chromium/chrome/browser/childaccounts/ChildAccountService.java",
+      "../android/java/src/org/chromium/chrome/browser/component_updater/UpdateScheduler.java",
       "../android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java",
       "../android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java",
       "../android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f114be4..9fd4eae 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3374,12 +3374,6 @@
      FEATURE_VALUE_TYPE(chrome::android::kPwaPersistentNotification)},
 #endif  // OS_ANDROID
 
-    {"enable-manual-fallbacks-filling",
-     flag_descriptions::kEnableManualFallbacksFillingName,
-     flag_descriptions::kEnableManualFallbacksFillingDescription,
-     kOsDesktop | kOsAndroid,
-     FEATURE_VALUE_TYPE(password_manager::features::kManualFallbacksFilling)},
-
 #if !defined(OS_ANDROID)
     {"voice-search-on-local-ntp", flag_descriptions::kVoiceSearchOnLocalNtpName,
      flag_descriptions::kVoiceSearchOnLocalNtpDescription, kOsDesktop,
@@ -4051,6 +4045,13 @@
      FEATURE_VALUE_TYPE(chromeos::features::kDriveFs)},
 #endif  // OS_CHROMEOS
 
+#if defined(OS_ANDROID)
+    {"background-task-component-update",
+     flag_descriptions::kBackgroundTaskComponentUpdateName,
+     flag_descriptions::kBackgroundTaskComponentUpdateDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kBackgroundTaskComponentUpdate)},
+#endif
+
     // NOTE: Adding a new flag requires adding a corresponding entry to enum
     // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag
     // Histograms" in tools/metrics/histograms/README.md (run the
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index d007da9..96a525a 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -188,6 +188,9 @@
 const base::Feature kAndroidPaymentApps{"AndroidPaymentApps",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kBackgroundTaskComponentUpdate{
+    "BackgroundTaskComponentUpdate", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kCCTBackgroundTab{"CCTBackgroundTab",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index d7bc6bad..7d4ee14a 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -17,6 +17,7 @@
 extern const base::Feature kAndroidPayIntegrationV1;
 extern const base::Feature kAndroidPayIntegrationV2;
 extern const base::Feature kAndroidPaymentApps;
+extern const base::Feature kBackgroundTaskComponentUpdate;
 extern const base::Feature kCCTBackgroundTab;
 extern const base::Feature kCCTExternalLinkHandling;
 extern const base::Feature kCCTModule;
diff --git a/chrome/browser/android/component_updater/background_task_update_scheduler.cc b/chrome/browser/android/component_updater/background_task_update_scheduler.cc
new file mode 100644
index 0000000..5c0c5a0
--- /dev/null
+++ b/chrome/browser/android/component_updater/background_task_update_scheduler.cc
@@ -0,0 +1,57 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/component_updater/background_task_update_scheduler.h"
+
+#include "jni/UpdateScheduler_jni.h"
+
+namespace component_updater {
+
+// static
+bool BackgroundTaskUpdateScheduler::IsAvailable() {
+  return Java_UpdateScheduler_isAvailable(base::android::AttachCurrentThread());
+}
+
+BackgroundTaskUpdateScheduler::BackgroundTaskUpdateScheduler() {
+  DCHECK(IsAvailable());
+  JNIEnv* env = base::android::AttachCurrentThread();
+  j_update_scheduler_.Reset(Java_UpdateScheduler_getInstance(env));
+  Java_UpdateScheduler_setNativeScheduler(env, j_update_scheduler_,
+                                          reinterpret_cast<intptr_t>(this));
+}
+
+BackgroundTaskUpdateScheduler::~BackgroundTaskUpdateScheduler() = default;
+
+void BackgroundTaskUpdateScheduler::Schedule(
+    const base::TimeDelta& initial_delay,
+    const base::TimeDelta& delay,
+    const UserTask& user_task,
+    const OnStopTaskCallback& on_stop) {
+  user_task_ = user_task;
+  on_stop_ = on_stop;
+  Java_UpdateScheduler_schedule(
+      base::android::AttachCurrentThread(), j_update_scheduler_,
+      initial_delay.InMilliseconds(), delay.InMilliseconds());
+}
+
+void BackgroundTaskUpdateScheduler::Stop() {
+  Java_UpdateScheduler_cancelTask(base::android::AttachCurrentThread(),
+                                  j_update_scheduler_);
+}
+
+void BackgroundTaskUpdateScheduler::OnStartTask(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  user_task_.Run(base::BindOnce(&Java_UpdateScheduler_finishTask,
+                                base::Unretained(env), j_update_scheduler_));
+}
+
+void BackgroundTaskUpdateScheduler::OnStopTask(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  DCHECK(on_stop_);
+  on_stop_.Run();
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/android/component_updater/background_task_update_scheduler.h b/chrome/browser/android/component_updater/background_task_update_scheduler.h
new file mode 100644
index 0000000..2a1b647
--- /dev/null
+++ b/chrome/browser/android/component_updater/background_task_update_scheduler.h
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_COMPONENT_UPDATER_BACKGROUND_TASK_UPDATE_SCHEDULER_H_
+#define CHROME_BROWSER_ANDROID_COMPONENT_UPDATER_BACKGROUND_TASK_UPDATE_SCHEDULER_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/component_updater/update_scheduler.h"
+
+namespace component_updater {
+
+// Native-side implementation of the component update scheduler using the
+// BackgroundTaskScheduler.
+class BackgroundTaskUpdateScheduler : public UpdateScheduler {
+ public:
+  // Returns true if this scheduler can be used.
+  static bool IsAvailable();
+
+  BackgroundTaskUpdateScheduler();
+  ~BackgroundTaskUpdateScheduler() override;
+
+  // UpdateScheduler:
+  void Schedule(const base::TimeDelta& initial_delay,
+                const base::TimeDelta& delay,
+                const UserTask& user_task,
+                const OnStopTaskCallback& on_stop) override;
+  void Stop() override;
+
+  // JNI:
+  void OnStartTask(JNIEnv* env,
+                   const base::android::JavaParamRef<jobject>& obj);
+  void OnStopTask(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+
+ private:
+  base::android::ScopedJavaGlobalRef<jobject> j_update_scheduler_;
+  UserTask user_task_;
+  OnStopTaskCallback on_stop_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundTaskUpdateScheduler);
+};
+
+}  // namespace component_updater
+
+#endif  // CHROME_BROWSER_ANDROID_COMPONENT_UPDATER_BACKGROUND_TASK_UPDATE_SCHEDULER_H_
diff --git a/chrome/browser/android/vr/android_ui_gesture_target.cc b/chrome/browser/android/vr/android_ui_gesture_target.cc
index fef7600..16c92c1 100644
--- a/chrome/browser/android/vr/android_ui_gesture_target.cc
+++ b/chrome/browser/android/vr/android_ui_gesture_target.cc
@@ -6,11 +6,8 @@
 
 #include <cmath>
 
+#include "chrome/browser/vr/input_event.h"
 #include "jni/AndroidUiGestureTarget_jni.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
-#include "third_party/blink/public/platform/web_input_event.h"
-#include "third_party/blink/public/platform/web_mouse_event.h"
-#include "third_party/blink/public/platform/web_touch_event.h"
 
 using base::android::JavaParamRef;
 using base::android::JavaRef;
@@ -33,30 +30,16 @@
 
 AndroidUiGestureTarget::~AndroidUiGestureTarget() = default;
 
-void AndroidUiGestureTarget::DispatchWebInputEvent(
-    std::unique_ptr<blink::WebInputEvent> event) {
-  blink::WebMouseEvent* mouse;
-  blink::WebTouchEvent* touch;
-  blink::WebGestureEvent* gesture;
-  if (blink::WebInputEvent::IsMouseEventType(event->GetType())) {
-    mouse = static_cast<blink::WebMouseEvent*>(event.get());
-  } else if (blink::WebInputEvent::IsTouchEventType(event->GetType())) {
-    touch = static_cast<blink::WebTouchEvent*>(event.get());
-  } else {
-    gesture = static_cast<blink::WebGestureEvent*>(event.get());
-  }
-
-  int64_t event_time_ms = event->TimeStamp().since_origin().InMilliseconds();
-  switch (event->GetType()) {
-    case blink::WebGestureEvent::kGestureScrollBegin: {
-      DCHECK(gesture->data.scroll_begin.delta_hint_units ==
-             blink::WebGestureEvent::ScrollUnits::kPrecisePixels);
-
-      SetPointer(gesture->PositionInWidget().x, gesture->PositionInWidget().y);
+void AndroidUiGestureTarget::DispatchInputEvent(
+    std::unique_ptr<InputEvent> event) {
+  int64_t event_time_ms = event->time_stamp().since_origin().InMilliseconds();
+  switch (event->type()) {
+    case InputEvent::kScrollBegin: {
+      SetPointer(event->position_in_widget());
       Inject(content::MOTION_EVENT_ACTION_START, event_time_ms);
 
-      float xdiff = gesture->data.scroll_begin.delta_x_hint;
-      float ydiff = gesture->data.scroll_begin.delta_y_hint;
+      float xdiff = event->scroll_data.delta_x;
+      float ydiff = event->scroll_data.delta_y;
 
       if (xdiff == 0 && ydiff == 0)
         ydiff = touch_slop_;
@@ -66,8 +49,8 @@
         ydiff *= touch_slop_ / dist;
       }
 
-      float xtarget = xdiff * scroll_ratio_ + gesture->PositionInWidget().x;
-      float ytarget = ydiff * scroll_ratio_ + gesture->PositionInWidget().y;
+      float xtarget = xdiff * scroll_ratio_ + event->position_in_widget().x();
+      float ytarget = ydiff * scroll_ratio_ + event->position_in_widget().y();
       scroll_x_ = xtarget > 0 ? std::ceil(xtarget) : std::floor(xtarget);
       scroll_y_ = ytarget > 0 ? std::ceil(ytarget) : std::floor(ytarget);
 
@@ -76,61 +59,50 @@
       Inject(content::MOTION_EVENT_ACTION_MOVE, event_time_ms);
       break;
     }
-    case blink::WebGestureEvent::kGestureScrollEnd:
+    case InputEvent::kScrollEnd:
       SetPointer(scroll_x_, scroll_y_);
       Inject(content::MOTION_EVENT_ACTION_END, event_time_ms);
       break;
-    case blink::WebGestureEvent::kGestureScrollUpdate: {
+    case InputEvent::kScrollUpdate: {
       float scale = scroll_ratio_ / kScrollEventsPerFrame;
-      scroll_x_ += gesture->data.scroll_update.delta_x * scale;
-      scroll_y_ += gesture->data.scroll_update.delta_y * scale;
+      scroll_x_ += event->scroll_data.delta_x * scale;
+      scroll_y_ += event->scroll_data.delta_y * scale;
 
       SetPointer(scroll_x_, scroll_y_);
       Inject(content::MOTION_EVENT_ACTION_MOVE, event_time_ms);
 
-      scroll_x_ += gesture->data.scroll_update.delta_x * scale;
-      scroll_y_ += gesture->data.scroll_update.delta_y * scale;
+      scroll_x_ += event->scroll_data.delta_x * scale;
+      scroll_y_ += event->scroll_data.delta_y * scale;
       SetDelayedEvent(scroll_x_, scroll_y_, content::MOTION_EVENT_ACTION_MOVE,
                       event_time_ms, kFrameDurationMs / kScrollEventsPerFrame);
 
       break;
     }
-    case blink::WebGestureEvent::kGestureTapDown:
-      SetPointer(gesture->PositionInWidget().x, gesture->PositionInWidget().y);
-      Inject(content::MOTION_EVENT_ACTION_START, event_time_ms);
-      Inject(content::MOTION_EVENT_ACTION_END, event_time_ms);
-      break;
-    case blink::WebGestureEvent::kGestureFlingCancel:
+    case InputEvent::kFlingCancel:
       Inject(content::MOTION_EVENT_ACTION_START, event_time_ms);
       Inject(content::MOTION_EVENT_ACTION_CANCEL, event_time_ms);
       break;
-    case blink::WebMouseEvent::kMouseEnter:
-      SetPointer(mouse->PositionInWidget().x, mouse->PositionInWidget().y);
+    case InputEvent::kHoverEnter:
+      SetPointer(event->position_in_widget());
       Inject(content::MOTION_EVENT_ACTION_HOVER_ENTER, event_time_ms);
       break;
-    case blink::WebMouseEvent::kMouseMove:
-    case blink::WebMouseEvent::kMouseLeave:
+    case InputEvent::kHoverLeave:
+    case InputEvent::kHoverMove:
       // The platform ignores HOVER_EXIT, so we instead send a fixed
       // out-of-bounds point (http://crbug.com/715114).
-      SetPointer(mouse->PositionInWidget().x, mouse->PositionInWidget().y);
+      SetPointer(event->position_in_widget());
       Inject(content::MOTION_EVENT_ACTION_HOVER_MOVE, event_time_ms);
       break;
-    case blink::WebTouchEvent::kTouchStart:
-      // Mouse down events are translated into touch events on Android anyways,
-      // so we can just send touch events.
-      SetPointer(touch->touches[0].PositionInWidget().x,
-                 touch->touches[0].PositionInWidget().y);
+    case InputEvent::kButtonDown:
+      SetPointer(event->position_in_widget());
       Inject(content::MOTION_EVENT_ACTION_START, event_time_ms);
       break;
-    case blink::WebTouchEvent::kTouchEnd:
-      SetPointer(touch->touches[0].PositionInWidget().x,
-                 touch->touches[0].PositionInWidget().y);
+    case InputEvent::kButtonUp:
+      SetPointer(event->position_in_widget());
       Inject(content::MOTION_EVENT_ACTION_END, event_time_ms);
       break;
-    case blink::WebTouchEvent::kTouchMove:
-      DCHECK_EQ(touch->touches_length, 1u);
-      SetPointer(touch->touches[0].PositionInWidget().x,
-                 touch->touches[0].PositionInWidget().y);
+    case InputEvent::kMove:
+      SetPointer(event->position_in_widget());
       Inject(content::MOTION_EVENT_ACTION_MOVE, event_time_ms);
       break;
     default:
@@ -148,18 +120,23 @@
   Java_AndroidUiGestureTarget_inject(env, obj, action, time_ms);
 }
 
-void AndroidUiGestureTarget::SetPointer(int x, int y) {
+void AndroidUiGestureTarget::SetPointer(const gfx::PointF& position) {
+  SetPointer(position.x(), position.y());
+}
+
+void AndroidUiGestureTarget::SetPointer(float x, float y) {
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
   if (obj.is_null())
     return;
 
-  Java_AndroidUiGestureTarget_setPointer(env, obj, x * scale_factor_,
-                                         y * scale_factor_);
+  Java_AndroidUiGestureTarget_setPointer(env, obj,
+                                         static_cast<int>(x * scale_factor_),
+                                         static_cast<int>(y * scale_factor_));
 }
 
-void AndroidUiGestureTarget::SetDelayedEvent(int x,
-                                             int y,
+void AndroidUiGestureTarget::SetDelayedEvent(float x,
+                                             float y,
                                              MotionEventAction action,
                                              int64_t time_ms,
                                              int delay_ms) {
@@ -168,9 +145,9 @@
   if (obj.is_null())
     return;
 
-  Java_AndroidUiGestureTarget_setDelayedEvent(env, obj, x * scale_factor_,
-                                              y * scale_factor_, action,
-                                              time_ms, delay_ms);
+  Java_AndroidUiGestureTarget_setDelayedEvent(
+      env, obj, static_cast<int>(x * scale_factor_),
+      static_cast<int>(y * scale_factor_), action, time_ms, delay_ms);
 }
 
 // static
diff --git a/chrome/browser/android/vr/android_ui_gesture_target.h b/chrome/browser/android/vr/android_ui_gesture_target.h
index 3021564..d1f1a3d 100644
--- a/chrome/browser/android/vr/android_ui_gesture_target.h
+++ b/chrome/browser/android/vr/android_ui_gesture_target.h
@@ -10,12 +10,14 @@
 #include "base/macros.h"
 #include "content/public/browser/android/motion_event_action.h"
 
-namespace blink {
-class WebInputEvent;
+namespace gfx {
+class PointF;
 }
 
 namespace vr {
 
+class InputEvent;
+
 // Used to forward events to MotionEventSynthesizer. Owned by VrShell.
 class AndroidUiGestureTarget {
  public:
@@ -29,13 +31,14 @@
   static AndroidUiGestureTarget* FromJavaObject(
       const base::android::JavaRef<jobject>& obj);
 
-  void DispatchWebInputEvent(std::unique_ptr<blink::WebInputEvent> event);
+  void DispatchInputEvent(std::unique_ptr<InputEvent> event);
 
  private:
   void Inject(content::MotionEventAction action, int64_t time_ms);
-  void SetPointer(int x, int y);
-  void SetDelayedEvent(int x,
-                       int y,
+  void SetPointer(const gfx::PointF& position);
+  void SetPointer(float x, float y);
+  void SetDelayedEvent(float x,
+                       float y,
                        content::MotionEventAction action,
                        int64_t time_ms,
                        int delay_ms);
diff --git a/chrome/browser/android/vr/vr_controller.cc b/chrome/browser/android/vr/vr_controller.cc
index 87e6ade3..247dfb2 100644
--- a/chrome/browser/android/vr/vr_controller.cc
+++ b/chrome/browser/android/vr/vr_controller.cc
@@ -10,8 +10,7 @@
 #include "base/logging.h"
 #include "base/numerics/math_constants.h"
 #include "base/numerics/ranges.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
-#include "third_party/blink/public/platform/web_input_event.h"
+#include "chrome/browser/vr/input_event.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_controller.h"
 
@@ -336,9 +335,9 @@
       gvr::GvrApi::GetTimePointNow().monotonic_system_time_nanos;
 }
 
-std::unique_ptr<GestureList> VrController::DetectGestures() {
+std::unique_ptr<InputEventList> VrController::DetectGestures() {
   if (controller_state_->GetConnectionState() != gvr::kControllerConnected) {
-    return std::make_unique<GestureList>();
+    return std::make_unique<InputEventList>();
   }
 
   UpdateCurrentTouchInfo();
diff --git a/chrome/browser/android/vr/vr_controller.h b/chrome/browser/android/vr/vr_controller.h
index 7ee3bd9..6146347b 100644
--- a/chrome/browser/android/vr/vr_controller.h
+++ b/chrome/browser/android/vr/vr_controller.h
@@ -22,10 +22,6 @@
 #include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/gfx/transform.h"
 
-namespace blink {
-class WebGestureEvent;
-}
-
 namespace gfx {
 class Transform;
 }
@@ -39,8 +35,6 @@
 // Angle (radians) the beam down from the controller axis, for wrist comfort.
 constexpr float kErgoAngleOffset = 0.26f;
 
-using GestureList = std::vector<std::unique_ptr<blink::WebGestureEvent>>;
-
 class VrController : public PlatformController {
  public:
   // Controller API entry point.
@@ -59,7 +53,7 @@
   // Called once per frame to update controller state.
   void UpdateState(const gfx::Transform& head_pose);
 
-  std::unique_ptr<GestureList> DetectGestures();
+  std::unique_ptr<InputEventList> DetectGestures();
 
   bool IsTouching();
 
diff --git a/chrome/browser/android/vr/vr_gl_thread.cc b/chrome/browser/android/vr/vr_gl_thread.cc
index 802ddec..d5a3c30 100644
--- a/chrome/browser/android/vr/vr_gl_thread.cc
+++ b/chrome/browser/android/vr/vr_gl_thread.cc
@@ -159,9 +159,8 @@
       base::BindOnce(&VrShell::UpdateGamepadData, weak_vr_shell_, pad));
 }
 
-void VrGLThread::ForwardEventToContent(
-    std::unique_ptr<blink::WebInputEvent> event,
-    int content_id) {
+void VrGLThread::ForwardEventToContent(std::unique_ptr<InputEvent> event,
+                                       int content_id) {
   DCHECK(OnGlThread());
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&VrShell::ProcessContentGesture, weak_vr_shell_,
@@ -192,8 +191,7 @@
   input_connection_->RequestTextState(std::move(callback));
 }
 
-void VrGLThread::ForwardEventToPlatformUi(
-    std::unique_ptr<blink::WebInputEvent> event) {
+void VrGLThread::ForwardEventToPlatformUi(std::unique_ptr<InputEvent> event) {
   DCHECK(OnGlThread());
   main_thread_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&VrShell::ProcessDialogGesture, weak_vr_shell_,
diff --git a/chrome/browser/android/vr/vr_gl_thread.h b/chrome/browser/android/vr/vr_gl_thread.h
index 8aaa416..4dc2f7fc 100644
--- a/chrome/browser/android/vr/vr_gl_thread.h
+++ b/chrome/browser/android/vr/vr_gl_thread.h
@@ -77,9 +77,8 @@
   void ToggleCardboardGamepad(bool enabled) override;
 
   // PlatformInputHandler
-  void ForwardEventToPlatformUi(
-      std::unique_ptr<blink::WebInputEvent> event) override;
-  void ForwardEventToContent(std::unique_ptr<blink::WebInputEvent> event,
+  void ForwardEventToPlatformUi(std::unique_ptr<InputEvent> event) override;
+  void ForwardEventToContent(std::unique_ptr<InputEvent> event,
                              int content_id) override;
   void ClearFocusedElement() override;
   void OnWebInputEdited(const TextEdits& edits) override;
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index 694849cc..8ff6090 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -69,7 +69,6 @@
 #include "services/device/public/mojom/constants.mojom.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/connector.h"
-#include "third_party/blink/public/platform/web_input_event.h"
 #include "ui/android/window_android.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/display/display.h"
@@ -1112,7 +1111,7 @@
   web_contents_->ClearFocusedElement();
 }
 
-void VrShell::ProcessContentGesture(std::unique_ptr<blink::WebInputEvent> event,
+void VrShell::ProcessContentGesture(std::unique_ptr<InputEvent> event,
                                     int content_id) {
   // Block the events if they don't belong to the current content
   if (content_id_ != content_id)
@@ -1121,15 +1120,14 @@
   if (!android_ui_gesture_target_)
     return;
 
-  android_ui_gesture_target_->DispatchWebInputEvent(std::move(event));
+  android_ui_gesture_target_->DispatchInputEvent(std::move(event));
 }
 
-void VrShell::ProcessDialogGesture(
-    std::unique_ptr<blink::WebInputEvent> event) {
+void VrShell::ProcessDialogGesture(std::unique_ptr<InputEvent> event) {
   if (!dialog_gesture_target_)
     return;
 
-  dialog_gesture_target_->DispatchWebInputEvent(std::move(event));
+  dialog_gesture_target_->DispatchInputEvent(std::move(event));
 }
 
 void VrShell::UpdateGamepadData(device::GvrGamepadData pad) {
diff --git a/chrome/browser/android/vr/vr_shell.h b/chrome/browser/android/vr/vr_shell.h
index 509b67fe..929274f 100644
--- a/chrome/browser/android/vr/vr_shell.h
+++ b/chrome/browser/android/vr/vr_shell.h
@@ -38,10 +38,6 @@
 class Version;
 }  // namespace base
 
-namespace blink {
-class WebInputEvent;
-}  // namespace blink
-
 namespace content {
 class WebContents;
 }  // namespace content
@@ -216,10 +212,9 @@
   bool HasAudioPermission();
 
   void ClearFocusedElement();
-  void ProcessContentGesture(std::unique_ptr<blink::WebInputEvent> event,
-                             int content_id);
+  void ProcessContentGesture(std::unique_ptr<InputEvent> event, int content_id);
 
-  void ProcessDialogGesture(std::unique_ptr<blink::WebInputEvent> event);
+  void ProcessDialogGesture(std::unique_ptr<InputEvent> event);
 
   void SetAlertDialog(JNIEnv* env,
                       const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/vr/vr_shell_gl.cc b/chrome/browser/android/vr/vr_shell_gl.cc
index 4d9c3d3..785d0bf 100644
--- a/chrome/browser/android/vr/vr_shell_gl.cc
+++ b/chrome/browser/android/vr/vr_shell_gl.cc
@@ -49,7 +49,6 @@
 #include "device/vr/android/gvr/gvr_gamepad_data_provider.h"
 #include "gpu/config/gpu_driver_bug_workaround_type.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 #include "ui/gfx/geometry/angle_conversions.h"
 #include "ui/gfx/gpu_fence.h"
 #include "ui/gl/android/scoped_java_surface.h"
@@ -1253,8 +1252,8 @@
 
   ControllerModel controller_model;
   controller_->GetTransform(&controller_model.transform);
-  std::unique_ptr<GestureList> gesture_list_ptr = controller_->DetectGestures();
-  GestureList& gesture_list = *gesture_list_ptr;
+  std::unique_ptr<InputEventList> input_event_list =
+      controller_->DetectGestures();
   controller_model.touchpad_button_state = UiInputManager::ButtonState::UP;
   DCHECK(!(controller_->ButtonUpHappened(gvr::kControllerButtonClick) &&
            controller_->ButtonDownHappened(gvr::kControllerButtonClick)))
@@ -1304,7 +1303,7 @@
 
   ReticleModel reticle_model;
   ui_->input_manager()->HandleInput(current_time, render_info, controller_model,
-                                    &reticle_model, &gesture_list);
+                                    &reticle_model, input_event_list.get());
   ui_->OnControllerUpdated(controller_model, reticle_model);
 }
 
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 496e7aa..ebe7c241 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -151,7 +151,10 @@
 #include "ui/message_center/message_center.h"
 #endif
 
-#if !defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+#include "chrome/browser/android/chrome_feature_list.h"
+#include "chrome/browser/android/component_updater/background_task_update_scheduler.h"
+#else
 #include "chrome/browser/gcm/gcm_product_util.h"
 #include "components/gcm_driver/gcm_client_factory.h"
 #include "components/gcm_driver/gcm_desktop_utils.h"
@@ -1011,11 +1014,23 @@
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI))
     return nullptr;
 
+  std::unique_ptr<component_updater::UpdateScheduler> scheduler;
+#if defined(OS_ANDROID)
+  if (base::FeatureList::IsEnabled(
+          chrome::android::kBackgroundTaskComponentUpdate) &&
+      component_updater::BackgroundTaskUpdateScheduler::IsAvailable()) {
+    scheduler =
+        std::make_unique<component_updater::BackgroundTaskUpdateScheduler>();
+  }
+#endif
+  if (!scheduler)
+    scheduler = std::make_unique<component_updater::TimerUpdateScheduler>();
+
   component_updater_ = component_updater::ComponentUpdateServiceFactory(
       component_updater::MakeChromeComponentUpdaterConfigurator(
           base::CommandLine::ForCurrentProcess(),
           g_browser_process->local_state()),
-      std::make_unique<component_updater::TimerUpdateScheduler>());
+      std::move(scheduler));
 
   return component_updater_.get();
 }
diff --git a/chrome/browser/chrome_browser_main_linux.cc b/chrome/browser/chrome_browser_main_linux.cc
index 3a26947e..be63d8b 100644
--- a/chrome/browser/chrome_browser_main_linux.cc
+++ b/chrome/browser/chrome_browser_main_linux.cc
@@ -64,8 +64,6 @@
       l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME));
 
 #if !defined(OS_CHROMEOS)
-  // Set up crypt config. This should be kept in sync with the OSCrypt parts of
-  // SystemNetworkContextManager::OnNetworkServiceCreated.
   std::unique_ptr<os_crypt::Config> config(new os_crypt::Config());
   // Forward to os_crypt the flag to use a specific password store.
   config->store =
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index e21d6c4..0d167f1d 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -497,6 +497,10 @@
 #include "chrome/browser/offline_pages/offline_page_url_loader_request_interceptor.h"
 #endif
 
+#if defined(OS_LINUX)
+#include "components/services/font/public/interfaces/constants.mojom.h"
+#endif
+
 using base::FileDescriptor;
 using content::BrowserThread;
 using content::BrowserURLHandler;
@@ -3640,6 +3644,12 @@
       &l10n_util::GetStringUTF16, IDS_UTILITY_PROCESS_FILE_UTILITY_NAME);
 #endif
 
+#if defined(OS_LINUX)
+  (*services)[font_service::mojom::kServiceName] =
+      base::BindRepeating(&l10n_util::GetStringUTF16,
+                          IDS_UTILITY_PROCESS_FONT_SERVICE_UTILITY_NAME);
+#endif
+
   (*services)[patch::mojom::kServiceName] = base::BindRepeating(
       &l10n_util::GetStringUTF16, IDS_UTILITY_PROCESS_PATCH_NAME);
 
diff --git a/chrome/browser/chrome_network_service_browsertest.cc b/chrome/browser/chrome_network_service_browsertest.cc
deleted file mode 100644
index 2da89e4..0000000
--- a/chrome/browser/chrome_network_service_browsertest.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/test/bind_test_util.h"
-#include "base/test/scoped_feature_list.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "components/cookie_config/cookie_store_util.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/network_service_instance.h"
-#include "content/public/test/browser_test.h"
-#include "net/extras/sqlite/cookie_crypto_delegate.h"
-#include "services/network/public/cpp/features.h"
-
-namespace content {
-namespace {
-
-constexpr char kCookieName[] = "Name";
-constexpr char kCookieValue[] = "Value";
-
-net::CookieList GetCookies(
-    const network::mojom::CookieManagerPtr& cookie_manager) {
-  base::RunLoop run_loop;
-  net::CookieList cookies_out;
-  cookie_manager->GetAllCookies(
-      base::BindLambdaForTesting([&](const net::CookieList& cookies) {
-        cookies_out = cookies;
-        run_loop.Quit();
-      }));
-  run_loop.Run();
-  return cookies_out;
-}
-
-void SetCookie(const network::mojom::CookieManagerPtr& cookie_manager) {
-  base::Time t = base::Time::Now();
-  net::CanonicalCookie cookie(kCookieName, kCookieValue, "www.test.com", "/", t,
-                              t + base::TimeDelta::FromDays(1), base::Time(),
-                              false, false, net::CookieSameSite::DEFAULT_MODE,
-                              net::COOKIE_PRIORITY_DEFAULT);
-  base::RunLoop run_loop;
-  cookie_manager->SetCanonicalCookie(
-      cookie, false, false,
-      base::BindLambdaForTesting([&](bool success) { run_loop.Quit(); }));
-  run_loop.Run();
-}
-
-// See |NetworkServiceBrowserTest| for content's version of tests.
-class ChromeNetworkServiceBrowserTest : public InProcessBrowserTest {
- public:
-  ChromeNetworkServiceBrowserTest() {
-    scoped_feature_list_.InitAndEnableFeature(
-        network::features::kNetworkService);
-  }
-
- protected:
-  network::mojom::NetworkContextPtr CreateNetworkContext(
-      bool enable_encrypted_cookies) {
-    network::mojom::NetworkContextPtr network_context;
-    network::mojom::NetworkContextParamsPtr context_params =
-        network::mojom::NetworkContextParams::New();
-    context_params->enable_encrypted_cookies = enable_encrypted_cookies;
-    context_params->cookie_path =
-        browser()->profile()->GetPath().Append(FILE_PATH_LITERAL("cookies"));
-    GetNetworkService()->CreateNetworkContext(
-        mojo::MakeRequest(&network_context), std::move(context_params));
-    return network_context;
-  }
-
- private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeNetworkServiceBrowserTest);
-};
-
-IN_PROC_BROWSER_TEST_F(ChromeNetworkServiceBrowserTest, PRE_EncryptedCookies) {
-  // First set a cookie with cookie encryption enabled.
-  network::mojom::NetworkContextPtr context =
-      CreateNetworkContext(/*enable_encrypted_cookies=*/true);
-  network::mojom::CookieManagerPtr cookie_manager;
-  context->GetCookieManager(mojo::MakeRequest(&cookie_manager));
-
-  SetCookie(cookie_manager);
-
-  net::CookieList cookies = GetCookies(cookie_manager);
-  ASSERT_EQ(1u, cookies.size());
-  EXPECT_EQ(kCookieName, cookies[0].Name());
-  EXPECT_EQ(kCookieValue, cookies[0].Value());
-}
-
-IN_PROC_BROWSER_TEST_F(ChromeNetworkServiceBrowserTest, EncryptedCookies) {
-  net::CookieCryptoDelegate* crypto_delegate =
-      cookie_config::GetCookieCryptoDelegate();
-  std::string ciphertext;
-  crypto_delegate->EncryptString(kCookieValue, &ciphertext);
-  // These checks are only valid if crypto is enabled on the platform.
-  if (!crypto_delegate->ShouldEncrypt() || ciphertext == kCookieValue)
-    return;
-
-  // Now attempt to read the cookie with encryption disabled.
-  network::mojom::NetworkContextPtr context =
-      CreateNetworkContext(/*enable_encrypted_cookies=*/false);
-  network::mojom::CookieManagerPtr cookie_manager;
-  context->GetCookieManager(mojo::MakeRequest(&cookie_manager));
-
-  net::CookieList cookies = GetCookies(cookie_manager);
-  ASSERT_EQ(1u, cookies.size());
-  EXPECT_EQ(kCookieName, cookies[0].Name());
-  EXPECT_EQ("", cookies[0].Value());
-}
-
-}  // namespace
-}  // namespace content
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index 9c38c258..4a458dfc 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -414,6 +414,12 @@
   return base::Singleton<CrostiniManager>::get();
 }
 
+bool CrostiniManager::IsVmRunning(Profile* profile, std::string vm_name) {
+  return running_vms_.find(std::make_pair(CryptohomeIdForProfile(profile),
+                                          std::move(vm_name))) !=
+         running_vms_.end();
+}
+
 CrostiniManager::CrostiniManager() : weak_ptr_factory_(this) {
   // Cicerone/ConciergeClient and its observer_list_ will be destroyed together.
   // We add, but don't need to remove the observer. (Doing so would force a
@@ -632,7 +638,8 @@
   GetConciergeClient()->StartTerminaVm(
       request,
       base::BindOnce(&CrostiniManager::OnStartTerminaVm,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+                     weak_ptr_factory_.GetWeakPtr(), request.owner_id(),
+                     request.name(), std::move(callback)));
 }
 
 void CrostiniManager::StopVm(Profile* profile,
@@ -644,13 +651,16 @@
     return;
   }
 
+  std::string owner_id = CryptohomeIdForProfile(profile);
+
   vm_tools::concierge::StopVmRequest request;
-  request.set_owner_id(CryptohomeIdForProfile(profile));
-  request.set_name(std::move(name));
+  request.set_owner_id(owner_id);
+  request.set_name(name);
 
   GetConciergeClient()->StopVm(
       std::move(request),
       base::BindOnce(&CrostiniManager::OnStopVm, weak_ptr_factory_.GetWeakPtr(),
+                     std::move(owner_id), std::move(name),
                      std::move(callback)));
 }
 
@@ -920,6 +930,8 @@
 }
 
 void CrostiniManager::OnStartTerminaVm(
+    std::string owner_id,
+    std::string vm_name,
     StartTerminaVmCallback callback,
     base::Optional<vm_tools::concierge::StartVmResponse> reply) {
   if (!reply.has_value()) {
@@ -934,10 +946,13 @@
     std::move(callback).Run(ConciergeClientResult::VM_START_FAILED);
     return;
   }
+  running_vms_.emplace(std::move(owner_id), std::move(vm_name));
   std::move(callback).Run(ConciergeClientResult::SUCCESS);
 }
 
 void CrostiniManager::OnStopVm(
+    std::string owner_id,
+    std::string vm_name,
     StopVmCallback callback,
     base::Optional<vm_tools::concierge::StopVmResponse> reply) {
   if (!reply.has_value()) {
@@ -960,6 +975,8 @@
       return;
     }
   }
+  // Remove from running_vms_.
+  running_vms_.erase(std::make_pair(std::move(owner_id), std::move(vm_name)));
 
   std::move(callback).Run(ConciergeClientResult::SUCCESS);
 }
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.h b/chrome/browser/chromeos/crostini/crostini_manager.h
index 67ff755..cd7c675 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.h
+++ b/chrome/browser/chromeos/crostini/crostini_manager.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_CROSTINI_CROSTINI_MANAGER_H_
 
 #include <map>
+#include <set>
 #include <string>
 #include <tuple>
 #include <utility>
@@ -276,6 +277,8 @@
   // Returns the singleton instance of CrostiniManager.
   static CrostiniManager* GetInstance();
 
+  bool IsVmRunning(Profile* profile, std::string vm_name);
+
  private:
   friend struct base::DefaultSingletonTraits<CrostiniManager>;
 
@@ -303,12 +306,16 @@
   // Callback for ConciergeClient::StartTerminaVm. Called after the Concierge
   // service method finishes.
   void OnStartTerminaVm(
+      std::string owner_id,
+      std::string vm_name,
       StartTerminaVmCallback callback,
       base::Optional<vm_tools::concierge::StartVmResponse> reply);
 
   // Callback for ConciergeClient::StopVm. Called after the Concierge
   // service method finishes.
-  void OnStopVm(StopVmCallback callback,
+  void OnStopVm(std::string owner_id,
+                std::string vm_name,
+                StopVmCallback callback,
                 base::Optional<vm_tools::concierge::StopVmResponse> reply);
 
   // Callback for CrostiniClient::StartConcierge. Called after the
@@ -367,6 +374,9 @@
                 ShutdownContainerCallback>
       shutdown_container_callbacks_;
 
+  // Running vms as <owner_id, vm_name> pairs.
+  std::set<std::pair<std::string, std::string>> running_vms_;
+
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
   base::WeakPtrFactory<CrostiniManager> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index c28536f9..4ae257a 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -149,6 +149,11 @@
   return profile->GetPrefs()->GetBoolean(crostini::prefs::kCrostiniEnabled);
 }
 
+bool IsCrostiniRunning(Profile* profile) {
+  return crostini::CrostiniManager::GetInstance()->IsVmRunning(
+      profile, kCrostiniDefaultVmName);
+}
+
 void LaunchCrostiniApp(Profile* profile,
                        const std::string& app_id,
                        int64_t display_id) {
diff --git a/chrome/browser/chromeos/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h
index fc56148..971ffdd 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.h
+++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -32,6 +32,9 @@
 // at least once and not deleted it.
 bool IsCrostiniEnabled(Profile* profile);
 
+// Returns whether the default Crostini VM is running for the user.
+bool IsCrostiniRunning(Profile* profile);
+
 // Launches the Crostini app with ID of |app_id| on the display with ID of
 // |display_id|. |app_id| should be a valid Crostini app list id.
 void LaunchCrostiniApp(Profile* profile,
diff --git a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
index 55d76987..d0fe8473 100644
--- a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
+++ b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/chromeos/cryptauth/gcm_device_info_provider_impl.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/common/pref_names.h"
@@ -46,8 +47,7 @@
 std::unique_ptr<cryptauth::CryptAuthClientFactory>
 CreateCryptAuthClientFactoryImpl(Profile* profile) {
   return std::make_unique<cryptauth::CryptAuthClientFactoryImpl>(
-      ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
-      SigninManagerFactory::GetForProfile(profile)->GetAuthenticatedAccountId(),
+      IdentityManagerFactory::GetForProfile(profile),
       profile->GetRequestContext(),
       cryptauth::device_classifier_util::GetDeviceClassifier());
 }
diff --git a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service_factory.cc b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service_factory.cc
index 22bfe39..7365c90 100644
--- a/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service_factory.cc
+++ b/chrome/browser/chromeos/cryptauth/chrome_cryptauth_service_factory.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/chromeos/cryptauth/chrome_cryptauth_service.h"
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chromeos/chromeos_features.h"
@@ -32,6 +33,7 @@
     : BrowserContextKeyedServiceFactory(
           "CryptAuthService",
           BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
   DependsOn(SigninManagerFactory::GetInstance());
   DependsOn(gcm::GCMProfileServiceFactory::GetInstance());
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 5ddb988..6134a90 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -737,6 +737,7 @@
   SET_STRING("SHOW_ALL_ANDROID_FOLDERS_OPTION",
              IDS_FILE_BROWSER_SHOW_ALL_ANDROID_FOLDERS_OPTION);
   SET_STRING("LINUX_FILES_ROOT_LABEL", IDS_FILE_BROWSER_LINUX_FILES_ROOT_LABEL);
+  SET_STRING("MY_FILES_ROOT_LABEL", IDS_FILE_BROWSER_MY_FILES_ROOT_LABEL);
   SET_STRING("MEDIA_ARTIST_COLUMN_LABEL",
              IDS_FILE_BROWSER_MEDIA_ARTIST_COLUMN_LABEL);
   SET_STRING("MEDIA_TITLE_COLUMN_LABEL",
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 080dcafc..ffabcba 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -42,11 +42,17 @@
     return *this;
   }
 
+  TestCase& EnableMyFiles() {
+    enable_new_navigation = true;
+    return *this;
+  }
+
   const char* test_case_name = nullptr;
   GuestMode guest_mode = NOT_IN_GUEST_MODE;
   bool trusted_events = false;
   bool tablet_mode = false;
   bool enable_drivefs = false;
+  bool enable_new_navigation = false;
 };
 
 // EventCase: FilesAppBrowserTest with trusted JS Events.
@@ -77,6 +83,11 @@
     if (GetParam().tablet_mode) {
       command_line->AppendSwitchASCII("force-tablet-mode", "touch_view");
     }
+
+    // If requested, enable the new-files-app-navigation flag.
+    if (GetParam().enable_new_navigation) {
+      command_line->AppendSwitchASCII("new-files-app-navigation", "");
+    }
   }
 
   GuestMode GetGuestMode() const override { return GetParam().guest_mode; }
@@ -122,6 +133,9 @@
   if (test.param.enable_drivefs)
     name.append("_DriveFs");
 
+  if (test.param.enable_new_navigation)
+    name.append("_MyFiles");
+
   return name;
 }
 
@@ -218,6 +232,11 @@
                       TestCase("checkRenameDisabledForReadOnlyDocument"),
                       TestCase("checkRenameDisabledForReadOnlyFile"),
                       TestCase("checkRenameDisabledForReadOnlyFolder"),
+                      TestCase("checkShareEnabledForReadWriteFile"),
+                      TestCase("checkShareEnabledForReadOnlyDocument"),
+                      TestCase("checkShareDisabledForStrictReadOnlyDocument"),
+                      TestCase("checkShareEnabledForReadOnlyFile"),
+                      TestCase("checkShareEnabledForReadOnlyFolder"),
                       TestCase("checkCopyEnabledForReadWriteFile"),
                       TestCase("checkCopyEnabledForReadOnlyDocument"),
                       TestCase("checkCopyDisabledForStrictReadOnlyDocument"),
@@ -456,6 +475,11 @@
     FilesAppBrowserTest,
     ::testing::Values(TestCase("mountCrostiniContainer")));
 
+WRAPPED_INSTANTIATE_TEST_CASE_P(
+    MyFiles, /* my_files.js */
+    FilesAppBrowserTest,
+    ::testing::Values(TestCase("showMyFiles").EnableMyFiles()));
+
 // Structure to describe an account info.
 struct TestAccountInfo {
   const char* const gaia_id;
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index 4d0c56f..5b1fd37 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -209,3 +209,8 @@
   RunTest(base::FilePath(FILE_PATH_LITERAL(
       "foreground/js/ui/file_list_selection_model_unittest.html")));
 }
+
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FilesAppEntryTypes) {
+  RunTest(base::FilePath(
+      FILE_PATH_LITERAL("common/js/files_app_entry_types_unittest.html")));
+}
diff --git a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
index 2b5cf46..485422c 100644
--- a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
@@ -71,9 +71,8 @@
   StartTest();
 }
 
-// Flaky in RELEASE crbug.com/857021
 IN_PROC_BROWSER_TEST_F(GalleryBrowserTest,
-                       DISABLED_CheckAvailabilityOfEditAndPrintButtons) {
+                       CheckAvailabilityOfEditAndPrintButtons) {
   set_test_case_name("checkAvailabilityOfEditAndPrintButtons");
   StartTest();
 }
diff --git a/chrome/browser/consent_auditor/consent_auditor_factory.cc b/chrome/browser/consent_auditor/consent_auditor_factory.cc
index ebaf91c..4c16c5d 100644
--- a/chrome/browser/consent_auditor/consent_auditor_factory.cc
+++ b/chrome/browser/consent_auditor/consent_auditor_factory.cc
@@ -51,7 +51,8 @@
     content::BrowserContext* context) const {
   Profile* profile = static_cast<Profile*>(context);
 
-  std::unique_ptr<syncer::ConsentSyncBridge> bridge;
+  std::unique_ptr<syncer::ConsentSyncBridge> consent_sync_bridge;
+  syncer::UserEventService* user_event_service = nullptr;
   if (base::FeatureList::IsEnabled(switches::kSyncUserConsentSeparateType)) {
     syncer::OnceModelTypeStoreFactory store_factory =
         browser_sync::ProfileSyncService::GetModelTypeStoreFactory(
@@ -61,13 +62,15 @@
             syncer::USER_CONSENTS,
             base::BindRepeating(&syncer::ReportUnrecoverableError,
                                 chrome::GetChannel()));
-    bridge = std::make_unique<syncer::ConsentSyncBridgeImpl>(
+    consent_sync_bridge = std::make_unique<syncer::ConsentSyncBridgeImpl>(
         std::move(store_factory), std::move(change_processor));
+  } else {
+    user_event_service =
+        browser_sync::UserEventServiceFactory::GetForProfile(profile);
   }
-  // TODO(vitaliii): Don't create UserEventService when it won't be used.
+
   return new consent_auditor::ConsentAuditor(
-      profile->GetPrefs(), std::move(bridge),
-      browser_sync::UserEventServiceFactory::GetForProfile(profile),
+      profile->GetPrefs(), std::move(consent_sync_bridge), user_event_service,
       // The browser version and locale do not change runtime, so we can pass
       // them directly.
       version_info::GetVersionNumber(),
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index c8c6ac5..9658230e 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -200,7 +200,7 @@
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
   (*s_whitelist)[::prefs::kSearchSuggestEnabled] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
-  (*s_whitelist)[::prefs::kUnifiedConsentGiven] =
+  (*s_whitelist)[::unified_consent::prefs::kUnifiedConsentGiven] =
       settings_api::PrefType::PREF_TYPE_BOOLEAN;
 
   // Languages page
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index f384d7b..999656cae 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -542,13 +542,6 @@
 const char kEnableMacMaterialDesignDownloadShelfDescription[] =
     "If enabled, the download shelf uses Material Design.";
 
-const char kEnableManualFallbacksFillingName[] =
-    "Manual fallbacks for password manager forms filling";
-const char kEnableManualFallbacksFillingDescription[] =
-    "If enabled, then if user clicks on the password field on a form, popup "
-    "might contain generation fallbacks or 'Show all saved passwords' "
-    "fallback.";
-
 const char kEnablePolicyToolName[] = "Enable policy management page";
 const char kEnablePolicyToolDescription[] =
     "If enabled, the chrome://policy-tool URL loads a page for managing "
@@ -2085,6 +2078,11 @@
     "Enables downloading pages in the background in case page is not yet "
     "loaded in current tab.";
 
+const char kBackgroundTaskComponentUpdateName[] =
+    "Background Task Component Updates";
+const char kBackgroundTaskComponentUpdateDescription[] =
+    "Schedule component updates with BackgroundTaskScheduler";
+
 const char kCCTModuleName[] = "Chrome Custom Tabs Module";
 const char kCCTModuleDescription[] =
     "Enables a dynamically loaded module in Chrome Custom Tabs, on Android.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 5ec8d3a..6505620 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -359,9 +359,6 @@
 extern const char kEnableMacMaterialDesignDownloadShelfName[];
 extern const char kEnableMacMaterialDesignDownloadShelfDescription[];
 
-extern const char kEnableManualFallbacksFillingName[];
-extern const char kEnableManualFallbacksFillingDescription[];
-
 extern const char kEnableMaterialDesignBookmarksName[];
 extern const char kEnableMaterialDesignBookmarksDescription[];
 
@@ -647,9 +644,6 @@
 extern const char kMacViewsAutofillPopupName[];
 extern const char kMacViewsAutofillPopupDescription[];
 
-extern const char kManualPasswordGenerationName[];
-extern const char kManualPasswordGenerationDescription[];
-
 extern const char kMarkHttpAsName[];
 extern const char kMarkHttpAsDescription[];
 extern const char kMarkHttpAsDangerous[];
@@ -1271,6 +1265,9 @@
 extern const char kBackgroundLoaderForDownloadsName[];
 extern const char kBackgroundLoaderForDownloadsDescription[];
 
+extern const char kBackgroundTaskComponentUpdateName[];
+extern const char kBackgroundTaskComponentUpdateDescription[];
+
 extern const char kCCTModuleName[];
 extern const char kCCTModuleDescription[];
 
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index 7aeef806..fe59b997 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -49,13 +49,6 @@
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-#include "chrome/common/chrome_paths_internal.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/grit/chromium_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
-
 namespace {
 
 // Called on IOThread to disable QUIC for HttpNetworkSessions not using the
@@ -438,21 +431,6 @@
   GetStubResolverConfig(&stub_resolver_enabled, &dns_over_https_servers);
   content::GetNetworkService()->ConfigureStubHostResolver(
       stub_resolver_enabled, std::move(dns_over_https_servers));
-
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-
-  // Set up crypt config. This should be kept in sync with the OSCrypt parts of
-  // ChromeBrowserMainPartsLinux::PreProfileInit.
-  network::mojom::CryptConfigPtr config = network::mojom::CryptConfig::New();
-  config->store = command_line.GetSwitchValueASCII(switches::kPasswordStore);
-  config->product_name = l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
-  config->should_use_preference =
-      command_line.HasSwitch(switches::kEnableEncryptionSelection);
-  chrome::GetDefaultUserDataDirectory(&config->user_data_path);
-  content::GetNetworkService()->SetCryptConfig(std::move(config));
-#endif
 }
 
 void SystemNetworkContextManager::DisableQuic() {
diff --git a/chrome/browser/notifications/notification_common.h b/chrome/browser/notifications/notification_common.h
index 29d91600..b02a5dc 100644
--- a/chrome/browser/notifications/notification_common.h
+++ b/chrome/browser/notifications/notification_common.h
@@ -17,13 +17,12 @@
  public:
   // Things as user can do to a notification. Keep in sync with the
   // NotificationOperation enumeration in notification_response_builder_mac.h.
-  // TODO(peter): Prefix these options with OPERATION_.
   enum Operation {
-    CLICK = 0,
-    CLOSE = 1,
-    DISABLE_PERMISSION = 2,
-    SETTINGS = 3,
-    OPERATION_MAX = SETTINGS
+    OPERATION_CLICK = 0,
+    OPERATION_CLOSE = 1,
+    OPERATION_DISABLE_PERMISSION = 2,
+    OPERATION_SETTINGS = 3,
+    OPERATION_MAX = OPERATION_SETTINGS
   };
 
   // A struct that contains extra data about a notification specific to one of
diff --git a/chrome/browser/notifications/notification_display_service_impl.cc b/chrome/browser/notifications/notification_display_service_impl.cc
index 741a087..cef2157 100644
--- a/chrome/browser/notifications/notification_display_service_impl.cc
+++ b/chrome/browser/notifications/notification_display_service_impl.cc
@@ -158,19 +158,19 @@
   base::OnceClosure completed_closure = base::BindOnce(&OperationCompleted);
 
   switch (operation) {
-    case NotificationCommon::CLICK:
+    case NotificationCommon::OPERATION_CLICK:
       handler->OnClick(profile_, origin, notification_id, action_index, reply,
                        std::move(completed_closure));
       break;
-    case NotificationCommon::CLOSE:
+    case NotificationCommon::OPERATION_CLOSE:
       DCHECK(by_user.has_value());
       handler->OnClose(profile_, origin, notification_id, by_user.value(),
                        std::move(completed_closure));
       break;
-    case NotificationCommon::DISABLE_PERMISSION:
+    case NotificationCommon::OPERATION_DISABLE_PERMISSION:
       handler->DisableNotifications(profile_, origin);
       break;
-    case NotificationCommon::SETTINGS:
+    case NotificationCommon::OPERATION_SETTINGS:
       handler->OpenSettings(profile_, origin);
       break;
   }
diff --git a/chrome/browser/notifications/notification_platform_bridge_android.cc b/chrome/browser/notifications/notification_platform_bridge_android.cc
index 258d1f4..1adaea5 100644
--- a/chrome/browser/notifications/notification_platform_bridge_android.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_android.cc
@@ -167,7 +167,7 @@
   profile_manager->LoadProfile(
       profile_id, incognito,
       base::Bind(&NotificationDisplayServiceImpl::ProfileLoadedCallback,
-                 NotificationCommon::CLICK,
+                 NotificationCommon::OPERATION_CLICK,
                  NotificationHandler::Type::WEB_PERSISTENT, origin,
                  notification_id, std::move(action_index), std::move(reply),
                  base::nullopt /* by_user */));
@@ -213,7 +213,7 @@
   profile_manager->LoadProfile(
       profile_id, incognito,
       base::Bind(&NotificationDisplayServiceImpl::ProfileLoadedCallback,
-                 NotificationCommon::CLOSE,
+                 NotificationCommon::OPERATION_CLOSE,
                  NotificationHandler::Type::WEB_PERSISTENT,
                  GURL(ConvertJavaStringToUTF8(env, java_origin)),
                  notification_id, base::nullopt /* action index */,
diff --git a/chrome/browser/notifications/notification_platform_bridge_chromeos.cc b/chrome/browser/notifications/notification_platform_bridge_chromeos.cc
index 672c6c5..e08d0db2 100644
--- a/chrome/browser/notifications/notification_platform_bridge_chromeos.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_chromeos.cc
@@ -126,7 +126,7 @@
   } else {
     NotificationDisplayServiceImpl::GetForProfile(notification->profile())
         ->ProcessNotificationOperation(
-            NotificationCommon::CLOSE, notification->type(),
+            NotificationCommon::OPERATION_CLOSE, notification->type(),
             notification->notification().origin_url(),
             notification->original_id(), base::nullopt, base::nullopt, by_user);
   }
@@ -145,7 +145,7 @@
   } else {
     NotificationDisplayServiceImpl::GetForProfile(notification->profile())
         ->ProcessNotificationOperation(
-            NotificationCommon::CLICK, notification->type(),
+            NotificationCommon::OPERATION_CLICK, notification->type(),
             notification->notification().origin_url(),
             notification->original_id(), base::nullopt, base::nullopt,
             base::nullopt);
@@ -165,7 +165,7 @@
   } else {
     NotificationDisplayServiceImpl::GetForProfile(notification->profile())
         ->ProcessNotificationOperation(
-            NotificationCommon::CLICK, notification->type(),
+            NotificationCommon::OPERATION_CLICK, notification->type(),
             notification->notification().origin_url(),
             notification->original_id(), button_index, reply, base::nullopt);
   }
@@ -182,7 +182,7 @@
   } else {
     NotificationDisplayServiceImpl::GetForProfile(notification->profile())
         ->ProcessNotificationOperation(
-            NotificationCommon::SETTINGS, notification->type(),
+            NotificationCommon::OPERATION_SETTINGS, notification->type(),
             notification->notification().origin_url(),
             notification->original_id(), base::nullopt, base::nullopt,
             base::nullopt);
@@ -197,11 +197,11 @@
 
   DCHECK_NE(NotificationHandler::Type::TRANSIENT, notification->type());
   NotificationDisplayServiceImpl::GetForProfile(notification->profile())
-      ->ProcessNotificationOperation(NotificationCommon::DISABLE_PERMISSION,
-                                     notification->type(),
-                                     notification->notification().origin_url(),
-                                     notification->original_id(), base::nullopt,
-                                     base::nullopt, base::nullopt);
+      ->ProcessNotificationOperation(
+          NotificationCommon::OPERATION_DISABLE_PERMISSION,
+          notification->type(), notification->notification().origin_url(),
+          notification->original_id(), base::nullopt, base::nullopt,
+          base::nullopt);
 }
 
 ProfileNotification* NotificationPlatformBridgeChromeOs::GetProfileNotification(
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc
index 1ab3d22..a5fc6e5 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -787,12 +787,12 @@
       return;
 
     if (action == kDefaultButtonId) {
-      ForwardNotificationOperation(FROM_HERE, data, NotificationCommon::CLICK,
-                                   base::nullopt /* action_index */,
-                                   base::nullopt /* by_user */);
+      ForwardNotificationOperation(
+          FROM_HERE, data, NotificationCommon::OPERATION_CLICK,
+          base::nullopt /* action_index */, base::nullopt /* by_user */);
     } else if (action == kSettingsButtonId) {
       ForwardNotificationOperation(
-          FROM_HERE, data, NotificationCommon::SETTINGS,
+          FROM_HERE, data, NotificationCommon::OPERATION_SETTINGS,
           base::nullopt /* action_index */, base::nullopt /* by_user */);
     } else if (action == kCloseButtonId) {
       CloseOnTaskRunner(data->profile_id, data->notification_id);
@@ -804,7 +804,8 @@
       size_t id_zero_based = id - data->action_start;
       if (id_zero_based >= n_buttons)
         return;
-      ForwardNotificationOperation(FROM_HERE, data, NotificationCommon::CLICK,
+      ForwardNotificationOperation(FROM_HERE, data,
+                                   NotificationCommon::OPERATION_CLICK,
                                    id_zero_based, base::nullopt /* by_user */);
     }
   }
@@ -821,9 +822,9 @@
       return;
 
     // TODO(peter): Can we support |by_user| appropriately here?
-    ForwardNotificationOperation(FROM_HERE, data, NotificationCommon::CLOSE,
-                                 base::nullopt /* action_index */,
-                                 true /* by_user */);
+    ForwardNotificationOperation(
+        FROM_HERE, data, NotificationCommon::OPERATION_CLOSE,
+        base::nullopt /* action_index */, true /* by_user */);
     notifications_.erase(data);
   }
 
diff --git a/chrome/browser/notifications/notification_platform_bridge_message_center.cc b/chrome/browser/notifications/notification_platform_bridge_message_center.cc
index d7707b71..3e06f3e 100644
--- a/chrome/browser/notifications/notification_platform_bridge_message_center.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_message_center.cc
@@ -34,7 +34,7 @@
   void SettingsClick() override {
     NotificationDisplayServiceImpl::GetForProfile(profile_)
         ->ProcessNotificationOperation(
-            NotificationCommon::SETTINGS, notification_type_,
+            NotificationCommon::OPERATION_SETTINGS, notification_type_,
             notification_.origin_url(), notification_.id(), base::nullopt,
             base::nullopt, base::nullopt /* by_user */);
   }
@@ -42,8 +42,8 @@
   void DisableNotification() override {
     NotificationDisplayServiceImpl::GetForProfile(profile_)
         ->ProcessNotificationOperation(
-            NotificationCommon::DISABLE_PERMISSION, notification_type_,
-            notification_.origin_url(), notification_.id(),
+            NotificationCommon::OPERATION_DISABLE_PERMISSION,
+            notification_type_, notification_.origin_url(), notification_.id(),
             base::nullopt /* action_index */, base::nullopt /* reply */,
             base::nullopt /* by_user */);
   }
@@ -51,7 +51,7 @@
   void Close(bool by_user) override {
     NotificationDisplayServiceImpl::GetForProfile(profile_)
         ->ProcessNotificationOperation(
-            NotificationCommon::CLOSE, notification_type_,
+            NotificationCommon::OPERATION_CLOSE, notification_type_,
             notification_.origin_url(), notification_.id(),
             base::nullopt /* action_index */, base::nullopt /* reply */,
             by_user);
@@ -61,7 +61,7 @@
              const base::Optional<base::string16>& reply) override {
     NotificationDisplayServiceImpl::GetForProfile(profile_)
         ->ProcessNotificationOperation(
-            NotificationCommon::CLICK, notification_type_,
+            NotificationCommon::OPERATION_CLICK, notification_type_,
             notification_.origin_url(), notification_.id(), button_index, reply,
             base::nullopt /* by_user */);
   }
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc
index 63318e2..56ddb52 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -691,7 +691,7 @@
       DLOG(ERROR) << "Failed to get toast dismissal reason: " << std::hex << hr;
     }
 
-    HandleEvent(notification, NotificationCommon::CLOSE,
+    HandleEvent(notification, NotificationCommon::OPERATION_CLOSE,
                 /*action_index=*/base::nullopt, by_user);
     return S_OK;
   }
@@ -839,9 +839,9 @@
   if (!inline_reply.empty())
     reply = inline_reply;
 
-  NotificationCommon::Operation operation = launch_id.is_for_context_menu()
-                                                ? NotificationCommon::SETTINGS
-                                                : NotificationCommon::CLICK;
+  NotificationCommon::Operation operation =
+      launch_id.is_for_context_menu() ? NotificationCommon::OPERATION_SETTINGS
+                                      : NotificationCommon::OPERATION_CLICK;
 
   ForwardNotificationOperationOnUiThread(
       operation, launch_id.notification_type(), launch_id.origin_url(),
diff --git a/chrome/browser/notifications/notification_platform_bridge_win_interactive_uitest.cc b/chrome/browser/notifications/notification_platform_bridge_win_interactive_uitest.cc
index 4a18e5a..15fca7e5 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win_interactive_uitest.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win_interactive_uitest.cc
@@ -249,12 +249,12 @@
   // Simulate clicks on the toast.
   NotificationPlatformBridgeWin* bridge = GetBridge();
   ASSERT_TRUE(bridge);
-  bridge->ForwardHandleEventForTesting(NotificationCommon::CLICK, &toast, &args,
-                                       base::nullopt);
+  bridge->ForwardHandleEventForTesting(NotificationCommon::OPERATION_CLICK,
+                                       &toast, &args, base::nullopt);
   run_loop.Run();
 
   // Validate the click values.
-  EXPECT_EQ(NotificationCommon::CLICK, last_operation_);
+  EXPECT_EQ(NotificationCommon::OPERATION_CLICK, last_operation_);
   EXPECT_EQ(NotificationHandler::Type::WEB_PERSISTENT, last_notification_type_);
   EXPECT_EQ(GURL("https://example.com/"), last_origin_);
   EXPECT_EQ("notification_id", last_notification_id_);
@@ -281,7 +281,7 @@
   run_loop.Run();
 
   // Validate the values.
-  EXPECT_EQ(NotificationCommon::CLICK, last_operation_);
+  EXPECT_EQ(NotificationCommon::OPERATION_CLICK, last_operation_);
   EXPECT_EQ(NotificationHandler::Type::WEB_PERSISTENT, last_notification_type_);
   EXPECT_EQ(GURL("https://example.com/"), last_origin_);
   EXPECT_EQ("notification_id", last_notification_id_);
@@ -320,12 +320,12 @@
   // Simulate clicks on the toast.
   NotificationPlatformBridgeWin* bridge = GetBridge();
   ASSERT_TRUE(bridge);
-  bridge->ForwardHandleEventForTesting(NotificationCommon::SETTINGS, &toast,
-                                       &args, base::nullopt);
+  bridge->ForwardHandleEventForTesting(NotificationCommon::OPERATION_SETTINGS,
+                                       &toast, &args, base::nullopt);
   run_loop.Run();
 
   // Validate the click values.
-  EXPECT_EQ(NotificationCommon::SETTINGS, last_operation_);
+  EXPECT_EQ(NotificationCommon::OPERATION_SETTINGS, last_operation_);
   EXPECT_EQ(NotificationHandler::Type::WEB_PERSISTENT, last_notification_type_);
   EXPECT_EQ(GURL("https://example.com/"), last_origin_);
   EXPECT_EQ("notification_id", last_notification_id_);
@@ -476,7 +476,7 @@
   ASSERT_NO_FATAL_FAILURE(ProcessLaunchIdViaCmdLine(kLaunchId, /*reply=*/""));
 
   // Validate the click values.
-  EXPECT_EQ(NotificationCommon::CLICK, last_operation_);
+  EXPECT_EQ(NotificationCommon::OPERATION_CLICK, last_operation_);
   EXPECT_EQ(NotificationHandler::Type::WEB_PERSISTENT, last_notification_type_);
   EXPECT_EQ(GURL("https://example.com/"), last_origin_);
   EXPECT_EQ("notification_id", last_notification_id_);
@@ -494,7 +494,7 @@
       ProcessLaunchIdViaCmdLine(kLaunchIdButtonClick, "Inline reply"));
 
   // Validate the click values.
-  EXPECT_EQ(NotificationCommon::CLICK, last_operation_);
+  EXPECT_EQ(NotificationCommon::OPERATION_CLICK, last_operation_);
   EXPECT_EQ(NotificationHandler::Type::WEB_PERSISTENT, last_notification_type_);
   EXPECT_EQ(GURL("https://example.com/"), last_origin_);
   EXPECT_EQ("notification_id", last_notification_id_);
@@ -511,7 +511,7 @@
       ProcessLaunchIdViaCmdLine(kLaunchIdButtonClick, /*reply=*/""));
 
   // Validate the click values.
-  EXPECT_EQ(NotificationCommon::CLICK, last_operation_);
+  EXPECT_EQ(NotificationCommon::OPERATION_CLICK, last_operation_);
   EXPECT_EQ(NotificationHandler::Type::WEB_PERSISTENT, last_notification_type_);
   EXPECT_EQ(GURL("https://example.com/"), last_origin_);
   EXPECT_EQ("notification_id", last_notification_id_);
@@ -528,7 +528,7 @@
       ProcessLaunchIdViaCmdLine(kLaunchIdSettings, /*reply=*/""));
 
   // Validate the click values.
-  EXPECT_EQ(NotificationCommon::SETTINGS, last_operation_);
+  EXPECT_EQ(NotificationCommon::OPERATION_SETTINGS, last_operation_);
   EXPECT_EQ(NotificationHandler::Type::WEB_PERSISTENT, last_notification_type_);
   EXPECT_EQ(GURL("https://example.com/"), last_origin_);
   EXPECT_EQ("notification_id", last_notification_id_);
diff --git a/chrome/browser/resources/chromeos/chromevox/BUILD.gn b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
index 0ecda6b..840635e5 100644
--- a/chrome/browser/resources/chromeos/chromevox/BUILD.gn
+++ b/chrome/browser/resources/chromeos/chromevox/BUILD.gn
@@ -18,7 +18,7 @@
 }
 
 closure_library_dir =
-    "//chrome/third_party/chromevox/third_party/closure-library/closure/goog"
+    "//third_party/chromevox/third_party/closure-library/closure/goog"
 
 # List of all modules that are included in one or more of the production
 # chromevox scripts.
@@ -239,7 +239,7 @@
     ":chromevox_manifest",
     "//chrome/browser/resources/chromeos/braille_ime:braille_ime_manifest",
     "//chrome/browser/resources/chromeos/chromevox/strings:chromevox_strings",
-    "//chrome/third_party/chromevox:chromevox_third_party_resources",
+    "//third_party/chromevox:chromevox_third_party_resources",
   ]
   if (enable_nacl) {
     deps += [ "//third_party/liblouis" ]
@@ -571,7 +571,7 @@
     # copied one.
     "//chrome/browser/resources/chromeos/chromevox/",
     "//chrome/test/data/webui/test_api.js",
-    "//chrome/third_party/chromevox/",
+    "//third_party/chromevox/",
     "//chrome/third_party/mock4js/",
     "//third_party/accessibility-audit/axs_testing.js",
     "//third_party/chaijs/chai.js",
diff --git a/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni b/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni
index 8a5cfe6..9f309395 100644
--- a/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni
+++ b/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni
@@ -5,7 +5,7 @@
 assert(is_chromeos)
 
 closure_library_dir =
-    "//chrome/third_party/chromevox/third_party/closure-library/closure/goog"
+    "//third_party/chromevox/third_party/closure-library/closure/goog"
 
 jsbundler_modules = rebase_path([
                                   "depstree.py",
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py b/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
index bbf36b3..8434198 100755
--- a/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
+++ b/chrome/browser/resources/chromeos/chromevox/tools/check_chromevox.py
@@ -108,7 +108,7 @@
            os.path.relpath(
                os.path.join(
                    _CHROME_SOURCE_DIR,
-                   'chrome/third_party/chromevox/third_party/closure-library/'
+                   'third_party/chromevox/third_party/closure-library/'
                    'closure/goog'))]
   sources = ReadSources(roots, need_source_text=True,
                         exclude=[re.compile('testing')])
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/find_js_files.py b/chrome/browser/resources/chromeos/chromevox/tools/find_js_files.py
index 6d459a3..246d254 100755
--- a/chrome/browser/resources/chromeos/chromevox/tools/find_js_files.py
+++ b/chrome/browser/resources/chromeos/chromevox/tools/find_js_files.py
@@ -17,7 +17,7 @@
     os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 6))
 sys.path.insert(
     0, os.path.join(
-        _CHROME_SOURCE, ('chrome/third_party/chromevox/third_party/' +
+        _CHROME_SOURCE, ('third_party/chromevox/third_party/' +
                          'closure-library/closure/bin/build')))
 import treescan
 
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/generate_deps.py b/chrome/browser/resources/chromeos/chromevox/tools/generate_deps.py
index 4468b7f9..068131b 100755
--- a/chrome/browser/resources/chromeos/chromevox/tools/generate_deps.py
+++ b/chrome/browser/resources/chromeos/chromevox/tools/generate_deps.py
@@ -18,7 +18,7 @@
 _CHROME_SOURCE = os.path.realpath(
     os.path.join(_SCRIPT_DIR, *[os.path.pardir] * 6))
 sys.path.insert(0, os.path.join(
-    _CHROME_SOURCE, ('chrome/third_party/chromevox/third_party/' +
+    _CHROME_SOURCE, ('third_party/chromevox/third_party/' +
                      'closure-library/closure/bin/build')))
 import source
 
diff --git a/chrome/browser/resources/chromeos/chromevox/tools/jsbundler.py b/chrome/browser/resources/chromeos/chromevox/tools/jsbundler.py
index 9de4564..38c1a84 100755
--- a/chrome/browser/resources/chromeos/chromevox/tools/jsbundler.py
+++ b/chrome/browser/resources/chromeos/chromevox/tools/jsbundler.py
@@ -43,7 +43,7 @@
 sys.path.insert(0, os.path.join(
     _CHROME_SOURCE, 'third_party/blink/renderer/devtools/scripts/build'))
 sys.path.insert(0, os.path.join(
-    _CHROME_SOURCE, ('chrome/third_party/chromevox/third_party/' +
+    _CHROME_SOURCE, ('third_party/chromevox/third_party/' +
                      'closure-library/closure/bin/build')))
 import depstree
 import rjsmin
diff --git a/chrome/browser/resources/chromeos/drive_internals.html b/chrome/browser/resources/chromeos/drive_internals.html
index 3a1ef6f..ee0b852 100644
--- a/chrome/browser/resources/chromeos/drive_internals.html
+++ b/chrome/browser/resources/chromeos/drive_internals.html
@@ -44,9 +44,6 @@
       <span id="reset-status-text"></span>
     </div>
     <ul>
-      <li>Local Start Page Token:
-        <span id="account-start-page-token-local"></span>
-      </li>
       <li>Local Free Space:
         <span id="local-storage-freespace"></span> MB
       </li>
@@ -56,11 +53,18 @@
     <ul>
       <li>Push notification is enabled:
         <span id="push-notification-enabled"></span></li>
-      <li>Last update check time:
-        <span id="last-update-check-time"></span></li>
-      <li>Last update check result:
-        <span id="last-update-check-error"></span></li>
     </ul>
+    <table>
+      <tbody id="delta-update-status">
+        <tr>
+          <th>Source</th>
+          <th>Start Page Token</th>
+          <th>Last Update Check Time</th>
+          <th>Last Update Check Result</th>
+          <th>Refreshing</th>
+        </tr>
+      </tbody>
+    </table>
 
     <h2 id="in-flight-operations-section">In-flight Operations</h2>
     <table>
diff --git a/chrome/browser/resources/chromeos/drive_internals.js b/chrome/browser/resources/chromeos/drive_internals.js
index bab1c00..b606fab 100644
--- a/chrome/browser/resources/chromeos/drive_internals.js
+++ b/chrome/browser/resources/chromeos/drive_internals.js
@@ -185,29 +185,30 @@
   }
 }
 
-/**
- * Updates the local cache information about account metadata.
- * @param {Object} localMetadata Dictionary describing account metadata.
- */
-function updateLocalMetadata(localMetadata) {
-  var startPageToken = localMetadata['account-start-page-token-local'];
-
-  $('account-start-page-token-local').textContent = startPageToken +
-      (startPageToken ? ' (loaded)' : ' (not loaded)') +
-      (localMetadata['account-metadata-refreshing'] ? ' (refreshing)' : '');
-}
-
-/**
+/*
  * Updates the summary about delta update status.
  * @param {Object} deltaUpdateStatus Dictionary describing delta update status.
  */
 function updateDeltaUpdateStatus(deltaUpdateStatus) {
   $('push-notification-enabled').textContent =
       deltaUpdateStatus['push-notification-enabled'];
-  $('last-update-check-time').textContent =
-      deltaUpdateStatus['last-update-check-time'];
-  $('last-update-check-error').textContent =
-      deltaUpdateStatus['last-update-check-error'];
+
+  var itemContainer = $('delta-update-status');
+  for (var i = 0; i < deltaUpdateStatus['items'].length; i++) {
+    var update = deltaUpdateStatus['items'][i];
+    var tr = document.createElement('tr');
+    tr.className = 'delta-update';
+    tr.appendChild(createElementFromText('td', update.id));
+    var startPageToken = update.start_page_token;
+    tr.appendChild(createElementFromText(
+        'td',
+        startPageToken + (startPageToken ? ' (loaded)' : ' (not loaded)')));
+    tr.appendChild(createElementFromText('td', update.last_check_time));
+    tr.appendChild(createElementFromText('td', update.last_check_result));
+    tr.appendChild(createElementFromText('td', update.refreshing));
+
+    itemContainer.appendChild(tr);
+  }
 }
 
 /**
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 0f46e25..bac407f 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -297,6 +297,11 @@
   box-shadow: none;
   margin: 0 auto;
   max-width: 560px;
+  transition: background-color 300ms ease-in-out;
+}
+
+.md #fakebox:hover {
+  background-color: rgb(232, 234, 237);
 }
 
 .non-google-page #fakebox-container {
diff --git a/chrome/browser/resources/print_preview/new/destination_list_item.js b/chrome/browser/resources/print_preview/new/destination_list_item.js
index 1b644f4..a118f06f 100644
--- a/chrome/browser/resources/print_preview/new/destination_list_item.js
+++ b/chrome/browser/resources/print_preview/new/destination_list_item.js
@@ -50,6 +50,10 @@
     // </if>
   },
 
+  hostAttributes: {
+    tabindex: 0,
+  },
+
   observers: [
     'onDestinationPropertiesChange_(' +
         'destination.displayName, destination.isOfflineOrInvalid, ' +
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 0a75ec1..7632f4e4 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -134,7 +134,9 @@
   auto translated_strings = std::make_unique<base::DictionaryValue>();
 
   AddString(translated_strings.get(), "thumbnailRemovedNotification",
-            IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION);
+            features::IsMDIconsEnabled()
+                ? IDS_NTP_CONFIRM_MSG_SHORTCUT_REMOVED
+                : IDS_NEW_TAB_THUMBNAIL_REMOVED_NOTIFICATION);
   AddString(translated_strings.get(), "removeThumbnailTooltip",
             IDS_NEW_TAB_REMOVE_THUMBNAIL_TOOLTIP);
   AddString(translated_strings.get(), "undoThumbnailRemove",
diff --git a/chrome/browser/signin/signin_ui_util.cc b/chrome/browser/signin/signin_ui_util.cc
index e5fa40e..0359ed9 100644
--- a/chrome/browser/signin/signin_ui_util.cc
+++ b/chrome/browser/signin/signin_ui_util.cc
@@ -224,11 +224,11 @@
     GaiaCookieManagerService* cookie_manager_service =
         GaiaCookieManagerServiceFactory::GetForProfile(profile);
     std::vector<gaia::ListedAccount> cookie_accounts;
-    bool gaia_accounts_stale = !cookie_manager_service->ListAccounts(
+    bool cookie_accounts_valid = cookie_manager_service->ListAccounts(
         &cookie_accounts, nullptr, "ProfileChooserView");
     UMA_HISTOGRAM_BOOLEAN("Profile.DiceUI.GaiaAccountsStale",
-                          gaia_accounts_stale);
-    if (!cookie_accounts.empty())
+                          !cookie_accounts_valid);
+    if (cookie_accounts_valid && !cookie_accounts.empty())
       default_account_id = cookie_accounts[0].id;
   }
 
diff --git a/chrome/browser/sync/test/integration/sync_auth_test.cc b/chrome/browser/sync/test/integration/sync_auth_test.cc
index bd243ec5..fb9a746 100644
--- a/chrome/browser/sync/test/integration/sync_auth_test.cc
+++ b/chrome/browser/sync/test/integration/sync_auth_test.cc
@@ -264,7 +264,8 @@
 }
 
 // Verify that ProfileSyncService fetches a new token when an old token expires.
-IN_PROC_BROWSER_TEST_F(SyncAuthTest, TokenExpiry) {
+// Disabled due to flakiness: https://crbug.com/860200
+IN_PROC_BROWSER_TEST_F(SyncAuthTest, DISABLED_TokenExpiry) {
   // Initial sync succeeds with a short lived OAuth2 Token.
   ASSERT_TRUE(SetupClients());
   GetFakeServer()->SetAuthenticated();
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_context_menu.cc b/chrome/browser/ui/app_list/crostini/crostini_app_context_menu.cc
index 5cc8ed2..4e0a278 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_context_menu.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_context_menu.cc
@@ -29,6 +29,8 @@
 
     AddContextMenuOption(menu_model, ash::UNINSTALL,
                          IDS_APP_LIST_UNINSTALL_ITEM);
+    AddContextMenuOption(menu_model, ash::MENU_CLOSE,
+                         IDS_CROSTINI_SHUT_DOWN_LINUX_MENU_ITEM);
   }
 }
 
@@ -37,6 +39,10 @@
     if (app_id() == kCrostiniTerminalId) {
       return IsCrostiniEnabled(profile());
     }
+  } else if (command_id == ash::MENU_CLOSE) {
+    if (app_id() == kCrostiniTerminalId) {
+      return IsCrostiniRunning(profile());
+    }
   }
   return app_list::AppContextMenu::IsCommandIdEnabled(command_id);
 }
@@ -49,6 +55,14 @@
         return;
       }
       break;
+
+    case ash::MENU_CLOSE:
+      if (app_id() == kCrostiniTerminalId) {
+        crostini::CrostiniManager::GetInstance()->StopVm(
+            profile(), kCrostiniDefaultVmName, base::DoNothing());
+        return;
+      }
+      break;
   }
   app_list::AppContextMenu::ExecuteCommand(command_id, event_flags);
 }
diff --git a/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.cc b/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.cc
index 56624c8..a1aa1554 100644
--- a/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.cc
+++ b/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/infobars/core/simple_alert_infobar_delegate.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/common/page_importance_signals.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -41,13 +42,21 @@
   }
 }
 
+void BloatedRendererTabHelper::DidStartNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (state_ == State::kRequestingReload) {
+    saved_navigation_id_ = navigation_handle->GetNavigationId();
+    state_ = State::kStartedNavigation;
+  }
+}
+
 void BloatedRendererTabHelper::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
-  // TODO(ulan): Use nagivation_handle to ensure that the finished navigation
-  // is the same nagivation started by reloading the bloated tab.
-  if (reloading_bloated_renderer_) {
+  if (state_ == State::kStartedNavigation &&
+      saved_navigation_id_ == navigation_handle->GetNavigationId()) {
     ShowInfoBar(InfoBarService::FromWebContents(web_contents()));
-    reloading_bloated_renderer_ = false;
+    state_ = State::kInactive;
+    saved_navigation_id_ = 0;
   }
 }
 
@@ -116,9 +125,12 @@
     if (renderer->FastShutdownIfPossible(expected_page_count,
                                          skip_unload_handlers)) {
       const bool check_for_repost = true;
-      reloading_bloated_renderer_ = true;
+      // Clear the state and the saved navigation id.
+      state_ = State::kRequestingReload;
+      saved_navigation_id_ = 0;
       web_contents()->GetController().Reload(content::ReloadType::NORMAL,
                                              check_for_repost);
+      DCHECK_EQ(State::kStartedNavigation, state_);
       RecordBloatedRendererHandling(
           BloatedRendererHandlingInBrowser::kReloaded);
     } else {
diff --git a/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.h b/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.h
index ca160fa0..290591de 100644
--- a/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.h
+++ b/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.h
@@ -28,6 +28,8 @@
   ~BloatedRendererTabHelper() override = default;
 
   // content::WebContentsObserver:
+  void DidStartNavigation(
+      content::NavigationHandle* navigation_handle) override;
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
   void WebContentsDestroyed() override;
@@ -42,6 +44,8 @@
  private:
   friend class content::WebContentsUserData<BloatedRendererTabHelper>;
   FRIEND_TEST_ALL_PREFIXES(BloatedRendererTabHelperTest, DetectReload);
+  FRIEND_TEST_ALL_PREFIXES(BloatedRendererTabHelperTest,
+                           IgnoreUnrelatedNavigation);
   FRIEND_TEST_ALL_PREFIXES(BloatedRendererTabHelperTest, CanReloadBloatedTab);
   FRIEND_TEST_ALL_PREFIXES(BloatedRendererTabHelperTest,
                            CannotReloadBloatedTabCrashed);
@@ -49,12 +53,31 @@
                            CannotReloadBloatedTabInvalidURL);
   FRIEND_TEST_ALL_PREFIXES(BloatedRendererTabHelperTest,
                            CannotReloadBloatedTabPendingUserInteraction);
+  enum class State { kInactive, kRequestingReload, kStartedNavigation };
 
   explicit BloatedRendererTabHelper(content::WebContents* contents);
 
   bool CanReloadBloatedTab();
 
-  bool reloading_bloated_renderer_ = false;
+  // The state transitions as follows:
+  // - kInactive is the initial state.
+  //
+  // - any state => kRequestingReload transition happens in
+  //   OnRendererIsBloated before invoking NavigationController::Reload.
+  //
+  // - kRequestingReload => kStartedNavigation transition happens in
+  //   NavigationController::Reload when it invokes DidStartNavigation.
+  //
+  // - kStartedNavigation => kInactive transitions happens in
+  //   DidFinishNavigation.
+  State state_ = State::kInactive;
+
+  // The navigation id is saved on DidStartNavigation event when the state is
+  // kRequestingReload. The infobar is shown on the subsequent
+  // DidFinishNavigation only if its navigation id matches the saved id. This
+  // ensures that the infobar is shown only for the reload that was requested
+  // in OnRendererIsBloated event.
+  int64_t saved_navigation_id_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(BloatedRendererTabHelper);
 };
diff --git a/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc b/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc
index bea4fe3..123abbc3 100644
--- a/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc
+++ b/chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/common/page_importance_signals.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -21,10 +22,39 @@
 };
 
 TEST_F(BloatedRendererTabHelperTest, DetectReload) {
-  EXPECT_FALSE(tab_helper_->reloading_bloated_renderer_);
-  tab_helper_->reloading_bloated_renderer_ = true;
-  tab_helper_->DidFinishNavigation(nullptr);
-  EXPECT_FALSE(tab_helper_->reloading_bloated_renderer_);
+  EXPECT_EQ(BloatedRendererTabHelper::State::kInactive, tab_helper_->state_);
+  tab_helper_->state_ = BloatedRendererTabHelper::State::kRequestingReload;
+  auto reload_navigation =
+      content::NavigationHandle::CreateNavigationHandleForTesting(
+          GURL(), web_contents()->GetMainFrame());
+  tab_helper_->DidStartNavigation(reload_navigation.get());
+  EXPECT_EQ(BloatedRendererTabHelper::State::kStartedNavigation,
+            tab_helper_->state_);
+  EXPECT_EQ(reload_navigation->GetNavigationId(),
+            tab_helper_->saved_navigation_id_);
+  tab_helper_->DidFinishNavigation(reload_navigation.get());
+  EXPECT_EQ(BloatedRendererTabHelper::State::kInactive, tab_helper_->state_);
+}
+
+TEST_F(BloatedRendererTabHelperTest, IgnoreUnrelatedNavigation) {
+  EXPECT_EQ(BloatedRendererTabHelper::State::kInactive, tab_helper_->state_);
+  tab_helper_->state_ = BloatedRendererTabHelper::State::kRequestingReload;
+  auto reload_navigation =
+      content::NavigationHandle::CreateNavigationHandleForTesting(
+          GURL(), web_contents()->GetMainFrame());
+  tab_helper_->DidStartNavigation(reload_navigation.get());
+  EXPECT_EQ(BloatedRendererTabHelper::State::kStartedNavigation,
+            tab_helper_->state_);
+  EXPECT_EQ(reload_navigation->GetNavigationId(),
+            tab_helper_->saved_navigation_id_);
+  auto unrelated_navigation =
+      content::NavigationHandle::CreateNavigationHandleForTesting(
+          GURL(), web_contents()->GetMainFrame());
+  tab_helper_->DidFinishNavigation(unrelated_navigation.get());
+  EXPECT_EQ(BloatedRendererTabHelper::State::kStartedNavigation,
+            tab_helper_->state_);
+  EXPECT_EQ(reload_navigation->GetNavigationId(),
+            tab_helper_->saved_navigation_id_);
 }
 
 TEST_F(BloatedRendererTabHelperTest, CanReloadBloatedTab) {
diff --git a/chrome/browser/ui/cocoa/notifications/notification_response_builder_mac_unittest.mm b/chrome/browser/ui/cocoa/notifications/notification_response_builder_mac_unittest.mm
index 768b8e7..5392dbf3 100644
--- a/chrome/browser/ui/cocoa/notifications/notification_response_builder_mac_unittest.mm
+++ b/chrome/browser/ui/cocoa/notifications/notification_response_builder_mac_unittest.mm
@@ -16,11 +16,12 @@
   static_assert(static_cast<int>(a) == static_cast<int>(b), \
                 "mismatching enums: " #a)
 
-STATIC_ASSERT_ENUM(NOTIFICATION_CLICK, NotificationCommon::CLICK);
-STATIC_ASSERT_ENUM(NOTIFICATION_CLOSE, NotificationCommon::CLOSE);
+STATIC_ASSERT_ENUM(NOTIFICATION_CLICK, NotificationCommon::OPERATION_CLICK);
+STATIC_ASSERT_ENUM(NOTIFICATION_CLOSE, NotificationCommon::OPERATION_CLOSE);
 STATIC_ASSERT_ENUM(NOTIFICATION_DISABLE_PERMISSION,
-                   NotificationCommon::DISABLE_PERMISSION);
-STATIC_ASSERT_ENUM(NOTIFICATION_SETTINGS, NotificationCommon::SETTINGS);
+                   NotificationCommon::OPERATION_DISABLE_PERMISSION);
+STATIC_ASSERT_ENUM(NOTIFICATION_SETTINGS,
+                   NotificationCommon::OPERATION_SETTINGS);
 STATIC_ASSERT_ENUM(NOTIFICATION_OPERATION_MAX,
                    NotificationCommon::OPERATION_MAX);
 
diff --git a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
index 04ac214a..f544d303 100644
--- a/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_popup_view_native_views.cc
@@ -490,7 +490,8 @@
         item_id == autofill::PopupItemId::POPUP_ITEM_ID_AUTOFILL_OPTIONS ||
         item_id == autofill::PopupItemId::POPUP_ITEM_ID_SCAN_CREDIT_CARD ||
         item_id ==
-            autofill::PopupItemId::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO) {
+            autofill::PopupItemId::POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO ||
+        item_id == POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY) {
       // This is a footer, so this suggestion will be processed later. Don't
       // increment |line_number|, or else it will be skipped when adding footer
       // rows below.
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view.cc b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
index 4036337..f81006f 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view.cc
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
@@ -248,8 +248,24 @@
   constexpr int kDialogSpacingVertical = 32;
   constexpr gfx::Size kLogoImageSize(32, 32);
 
-  SetLayoutManager(std::make_unique<views::BoxLayout>(
+  views::BoxLayout* layout =
+      SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::kVertical, gfx::Insets(), kDialogSpacingVertical));
+
+  views::View* upper_container_view = new views::View();
+  upper_container_view->SetSize(gfx::Size(
+      kOOBEWindowWidth, kOOBEWindowHeight - kLinuxIllustrationHeight));
+  upper_container_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::kVertical, kDialogInsets, kDialogSpacingVertical));
+  AddChildView(upper_container_view);
+
+  views::View* lower_container_view = new views::View();
+  lower_container_view->SetSize(
+      gfx::Size(kOOBEWindowWidth, kLinuxIllustrationHeight));
+  views::BoxLayout* lower_container_layout =
+      lower_container_view->SetLayoutManager(
+          std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
+  AddChildView(lower_container_view);
 
   logo_image_ = new views::ImageView();
   logo_image_->SetImageSize(kLogoImageSize);
@@ -257,7 +273,7 @@
       ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
           IDR_LOGO_CROSTINI_DEFAULT));
   logo_image_->SetHorizontalAlignment(views::ImageView::LEADING);
-  AddChildView(logo_image_);
+  upper_container_view->AddChildView(logo_image_);
 
   const base::string16 device_type = ui::GetChromeOSDeviceName();
 
@@ -266,7 +282,7 @@
       ash::AshTextContext::CONTEXT_HEADLINE_OVERSIZED);
   big_message_label_->SetMultiLine(true);
   big_message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  AddChildView(big_message_label_);
+  upper_container_view->AddChildView(big_message_label_);
 
   // TODO(timloh): Descenders in the message appear to be clipped, re-visit once
   // the UI has been fleshed out more.
@@ -278,11 +294,11 @@
   message_label_ = new views::Label(message);
   message_label_->SetMultiLine(true);
   message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  AddChildView(message_label_);
+  upper_container_view->AddChildView(message_label_);
 
   // Make a slot for the progress bar, but it's not initially visible.
   progress_bar_ = new views::ProgressBar();
-  AddChildView(progress_bar_);
+  upper_container_view->AddChildView(progress_bar_);
   progress_bar_->SetVisible(false);
 
   big_image_ = new views::ImageView();
@@ -291,7 +307,12 @@
   big_image_->SetImage(
       ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
           IDR_LINUX_ILLUSTRATION));
-  AddChildView(big_image_);
+  lower_container_view->AddChildView(big_image_);
+
+  // Make sure the lower_container_view is pinned to the bottom of the dialog.
+  lower_container_layout->set_main_axis_alignment(
+      views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
+  layout->SetFlexForView(lower_container_view, 1, true);
 
   chrome::RecordDialogCreation(chrome::DialogIdentifier::CROSTINI_INSTALLER);
 }
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 501a5a5..7bce001 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -267,7 +267,6 @@
   // Cancel any pending tab transition.
   hover_tab_selector_.CancelTabTransition();
 
-  tabstrip_->PrepareForCloseAt(model_index, source);
   model_->CloseWebContentsAt(model_index,
                              TabStripModel::CLOSE_USER_GESTURE |
                              TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
@@ -427,7 +426,7 @@
   // Cancel any pending tab transition.
   hover_tab_selector_.CancelTabTransition();
 
-  tabstrip_->RemoveTabAt(contents, model_index);
+  tabstrip_->RemoveTabAt(contents, model_index, was_active);
 }
 
 void BrowserTabStripController::ActiveTabChanged(
diff --git a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
index fac0e0f2..3abace6 100644
--- a/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.cc
@@ -33,12 +33,14 @@
 
 void FakeBaseTabStripController::RemoveTab(int index) {
   num_tabs_--;
-  tab_strip_->RemoveTabAt(nullptr, index);
+  // RemoveTabAt() expects the controller state to have been updated already.
+  const bool was_active = index == active_index_;
   if (active_index_ > index) {
     --active_index_;
   } else if (active_index_ == index) {
     SetActiveIndex(std::min(active_index_, num_tabs_ - 1));
   }
+  tab_strip_->RemoveTabAt(nullptr, index, was_active);
 }
 
 const ui::ListSelectionModel&
@@ -89,7 +91,6 @@
 }
 
 void FakeBaseTabStripController::CloseTab(int index, CloseTabSource source) {
-  tab_strip_->PrepareForCloseAt(index, source);
   RemoveTab(index);
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index 5cb9858..7f4c489 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -545,7 +545,44 @@
     observer.OnTabMoved(from_model_index, to_model_index);
 }
 
-void TabStrip::RemoveTabAt(content::WebContents* contents, int model_index) {
+void TabStrip::RemoveTabAt(content::WebContents* contents,
+                           int model_index,
+                           bool was_active) {
+  const int model_count = GetModelCount();
+  if (in_tab_close_ && model_count > 0 && model_index != model_count) {
+    // The user closed a tab other than the last tab. Set
+    // available_width_for_tabs_ so that as the user closes tabs with the mouse
+    // a tab continues to fall under the mouse.
+    int next_active_index = controller_->GetActiveIndex();
+    DCHECK(IsValidModelIndex(next_active_index));
+    if (model_index <= next_active_index) {
+      // At this point, model's internal state has already been updated.
+      // |contents| has been detached from model and the active index has been
+      // updated. But the tab for |contents| isn't removed yet. Thus, we need to
+      // fix up next_active_index based on it.
+      next_active_index++;
+    }
+    Tab* next_active_tab = tab_at(next_active_index);
+    Tab* tab_being_removed = tab_at(model_index);
+
+    int size_delta = tab_being_removed->width();
+    if (!tab_being_removed->data().pinned && was_active &&
+        current_active_width_ > current_inactive_width_) {
+      // When removing an active, non-pinned tab, an inactive tab will be made
+      // active and thus given the active width. Thus the width being removed
+      // from the strip is really the current width of whichever inactive tab
+      // will be made active.
+      size_delta = next_active_tab->width();
+    }
+
+    available_width_for_tabs_ = ideal_bounds(model_count).right() -
+                                TabStartX() - size_delta + Tab::GetOverlap();
+    if (model_index == 0 && tab_being_removed->data().pinned &&
+        !tab_at(1)->data().pinned) {
+      available_width_for_tabs_ -= GetPinnedToNonPinnedOffset();
+    }
+  }
+
   const bool first_unpinned_tab = model_index == GetPinnedTabCount();
 
   if (!touch_layout_)
@@ -696,54 +733,6 @@
          tabstrip_right;
 }
 
-void TabStrip::PrepareForCloseAt(int model_index, CloseTabSource source) {
-  if (!in_tab_close_ && IsAnimating()) {
-    // Cancel any current animations. We do this as remove uses the current
-    // ideal bounds and we need to know ideal bounds is in a good state.
-    StopAnimating(true);
-  }
-
-  if (!GetWidget())
-    return;
-
-  int model_count = GetModelCount();
-  if (model_count > 1 && model_index != model_count - 1) {
-    // The user is about to close a tab other than the last tab. Set
-    // available_width_for_tabs_ so that as the user closes tabs with the mouse
-    // a tab continues to fall under the mouse.
-    Tab* tab_being_removed = tab_at(model_index);
-    int size_delta = tab_being_removed->width();
-    if (!tab_being_removed->data().pinned && tab_being_removed->IsActive()) {
-      // When removing an active, non-pinned tab, an inactive tab will be made
-      // active and thus given the active width. Thus the width being removed
-      // from the strip is really the current width of whichever inactive tab
-      // will be made active. This could be either |current_inactive_width_| or
-      // (current_inactive_width_ + 1) (if layout has apportioned extra space to
-      // the initial tabs in the strip). Unfortunately, the next active tab has
-      // not yet been chosen, so it's impossible to know which of these is
-      // correct; using the narrower value is more conservative.
-      // TODO(sky): https://crbug.com/856289 Refactor so this happens after
-      // another tab has been activated.
-      size_delta = current_inactive_width_;
-    }
-
-    available_width_for_tabs_ = ideal_bounds(model_count - 1).right() -
-                                TabStartX() - size_delta + Tab::GetOverlap();
-    if (model_index == 0 && tab_being_removed->data().pinned &&
-        !tab_at(1)->data().pinned) {
-      available_width_for_tabs_ -= GetPinnedToNonPinnedOffset();
-    }
-  }
-
-  in_tab_close_ = true;
-  resize_layout_timer_.Stop();
-  if (source == CLOSE_TAB_FROM_TOUCH) {
-    StartResizeLayoutTabsFromTouchTimer();
-  } else {
-    AddMessageLoopObserver();
-  }
-}
-
 void TabStrip::SetSelection(const ui::ListSelectionModel& new_selection) {
   if (selected_tabs_.active() != new_selection.active()) {
     if (selected_tabs_.active() >= 0)
@@ -923,18 +912,33 @@
 }
 
 void TabStrip::CloseTab(Tab* tab, CloseTabSource source) {
+  int model_index = GetModelIndexOfTab(tab);
   if (tab->closing()) {
     // If the tab is already closing, close the next tab. We do this so that the
     // user can rapidly close tabs by clicking the close button and not have
     // the animations interfere with that.
-    const int closed_tab_index = FindClosingTab(tab).first->first;
-    if (closed_tab_index < GetModelCount())
-      controller_->CloseTab(closed_tab_index, source);
-    return;
+    model_index = FindClosingTab(tab).first->first;
   }
-  int model_index = GetModelIndexOfTab(tab);
-  if (IsValidModelIndex(model_index))
-    controller_->CloseTab(model_index, source);
+
+  if (!IsValidModelIndex(model_index))
+    return;
+
+  if (!in_tab_close_ && IsAnimating()) {
+    // Cancel any current animations. We do this as remove uses the current
+    // ideal bounds and we need to know ideal bounds is in a good state.
+    StopAnimating(true);
+  }
+
+  if (GetWidget()) {
+    in_tab_close_ = true;
+    resize_layout_timer_.Stop();
+    if (source == CLOSE_TAB_FROM_TOUCH)
+      StartResizeLayoutTabsFromTouchTimer();
+    else
+      AddMessageLoopObserver();
+  }
+
+  controller_->CloseTab(model_index, source);
 }
 
 void TabStrip::ToggleTabAudioMute(Tab* tab) {
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index db3b95a..21cfc30 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -155,7 +155,9 @@
 
   // Removes a tab at the specified index. If the tab with |contents| is being
   // dragged then the drag is completed.
-  void RemoveTabAt(content::WebContents* contents, int model_index);
+  void RemoveTabAt(content::WebContents* contents,
+                   int model_index,
+                   bool was_active);
 
   // Sets the tab data at the specified model index.
   void SetTabData(int model_index, TabRendererData data);
@@ -167,12 +169,6 @@
   // to clip).
   bool ShouldTabBeVisible(const Tab* tab) const;
 
-  // Invoked from the controller when the close initiates from the TabController
-  // (the user clicked the tab close button or middle clicked the tab). This is
-  // invoked from Close. Because of unload handlers Close is not always
-  // immediately followed by RemoveTabAt.
-  void PrepareForCloseAt(int model_index, CloseTabSource source);
-
   // Invoked when the selection is updated.
   void SetSelection(const ui::ListSelectionModel& new_selection);
 
diff --git a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
index 2c21697..96bb982 100644
--- a/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip_unittest.cc
@@ -252,7 +252,7 @@
 }
 
 TEST_P(TabStripTest, AccessibilityEvents) {
-  // When adding tabs, SetSelection() is called after RemoveTabAt(), as
+  // When adding tabs, SetSelection() is called after AddTabAt(), as
   // otherwise the index would not be meaningful.
   tab_strip_->AddTabAt(0, TabRendererData(), false);
   tab_strip_->AddTabAt(1, TabRendererData(), true);
@@ -266,7 +266,7 @@
   // otherwise the index would not be meaningful.
   selection.SetSelectedIndex(0);
   tab_strip_->SetSelection(selection);
-  tab_strip_->RemoveTabAt(nullptr, 1);
+  tab_strip_->RemoveTabAt(nullptr, 1, true);
   EXPECT_EQ(2, test_views_delegate_->add_count());
   EXPECT_EQ(1, test_views_delegate_->remove_count());
 }
diff --git a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
index ea895ff..1eb51520 100644
--- a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
@@ -246,8 +246,6 @@
       drive::DriveServiceInterface* drive_service);
   void UpdateAppListSection(
       drive::DriveServiceInterface* drive_service);
-  void UpdateLocalMetadataSection(
-      drive::DebugInfoCollector* debug_info_collector);
   void UpdateDeltaUpdateStatusSection(
       drive::DebugInfoCollector* debug_info_collector);
   void UpdateInFlightOperationsSection(drive::JobListInterface* job_list);
@@ -290,10 +288,6 @@
   void OnGetAppList(google_apis::DriveApiErrorCode status,
                     std::unique_ptr<google_apis::AppList> app_list);
 
-  // Callback for DebugInfoCollector::GetMetadata for local update.
-  void OnGetFilesystemMetadataForLocal(
-      const drive::FileSystemMetadata& metadata);
-
   // Callback for DebugInfoCollector::GetMetadata for delta update.
   void OnGetFilesystemMetadataForDeltaUpdate(
       const drive::FileSystemMetadata& metadata);
@@ -450,7 +444,6 @@
   drive::DebugInfoCollector* debug_info_collector =
       integration_service->debug_info_collector();
   if (debug_info_collector) {
-    UpdateLocalMetadataSection(debug_info_collector);
     UpdateDeltaUpdateStatusSection(debug_info_collector);
     UpdateCacheContentsSection(debug_info_collector);
   }
@@ -547,27 +540,6 @@
                  weak_ptr_factory_.GetWeakPtr()));
 }
 
-void DriveInternalsWebUIHandler::UpdateLocalMetadataSection(
-    drive::DebugInfoCollector* debug_info_collector) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(debug_info_collector);
-
-  debug_info_collector->GetMetadata(
-      base::Bind(&DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void DriveInternalsWebUIHandler::OnGetFilesystemMetadataForLocal(
-    const drive::FileSystemMetadata& metadata) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  base::DictionaryValue local_metadata;
-  local_metadata.SetString("account-start-page-token-local",
-                           metadata.start_page_token);
-  local_metadata.SetBoolean("account-metadata-refreshing", metadata.refreshing);
-  web_ui()->CallJavascriptFunctionUnsafe("updateLocalMetadata", local_metadata);
-}
-
 void DriveInternalsWebUIHandler::ClearAccessToken(const base::ListValue* args) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -636,13 +608,24 @@
   delta_update_status.SetBoolean(
       "push-notification-enabled",
       drive_notification_manager->push_notification_enabled());
-  delta_update_status.SetString(
-      "last-update-check-time",
-      google_apis::util::FormatTimeAsStringLocaltime(
-          metadata.last_update_check_time));
-  delta_update_status.SetString(
-      "last-update-check-error",
+
+  auto items = std::make_unique<base::ListValue>();
+  // Users default corpus first.
+  auto app_data = std::make_unique<base::DictionaryValue>();
+  app_data->SetString("id", "default corpus");
+  app_data->SetString("start_page_token", metadata.start_page_token);
+  app_data->SetString("last_check_time",
+                      google_apis::util::FormatTimeAsStringLocaltime(
+                          metadata.last_update_check_time));
+  app_data->SetString(
+      "last_check_result",
       drive::FileErrorToString(metadata.last_update_check_error));
+  app_data->SetString("refreshing", metadata.refreshing ? "Yes" : "No");
+
+  items->Append(std::move(app_data));
+
+  // TODO(slangley): Add data for each team drive.
+  delta_update_status.Set("items", std::move(items));
 
   web_ui()->CallJavascriptFunctionUnsafe("updateDeltaUpdateStatus",
                                          delta_update_status);
diff --git a/chrome/browser/ui/webui/signin/login_ui_service_unittest.cc b/chrome/browser/ui/webui/signin/login_ui_service_unittest.cc
index 9948ae4..23cd90f 100644
--- a/chrome/browser/ui/webui/signin/login_ui_service_unittest.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_service_unittest.cc
@@ -16,12 +16,15 @@
 
 #if !defined(OS_CHROMEOS)
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/common/extension_builder.h"
 #endif
 
 class LoginUIServiceTest : public testing::Test {
@@ -112,6 +115,11 @@
 };
 
 TEST_F(LoginUIServiceLoginPopupTest, ShowLoginPop) {
+  extensions::TestExtensionSystem* extension_system =
+      static_cast<extensions::TestExtensionSystem*>(
+          extensions::ExtensionSystem::Get(profile()));
+  extension_system->CreateExtensionService(
+      base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
   service_->ShowLoginPopup();
   EXPECT_EQ(1, model_->count());
 }
diff --git a/chrome/browser/unified_consent/chrome_unified_consent_service_client.h b/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
index fb212f4..58848294 100644
--- a/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
+++ b/chrome/browser/unified_consent/chrome_unified_consent_service_client.h
@@ -10,7 +10,8 @@
 
 class PrefService;
 
-class ChromeUnifiedConsentServiceClient : public UnifiedConsentServiceClient {
+class ChromeUnifiedConsentServiceClient
+    : public unified_consent::UnifiedConsentServiceClient {
  public:
   explicit ChromeUnifiedConsentServiceClient(PrefService* pref_service);
   ~ChromeUnifiedConsentServiceClient() override = default;
diff --git a/chrome/browser/unified_consent/unified_consent_service_factory.cc b/chrome/browser/unified_consent/unified_consent_service_factory.cc
index 2c61a60..b47208c 100644
--- a/chrome/browser/unified_consent/unified_consent_service_factory.cc
+++ b/chrome/browser/unified_consent/unified_consent_service_factory.cc
@@ -27,9 +27,9 @@
 UnifiedConsentServiceFactory::~UnifiedConsentServiceFactory() = default;
 
 // static
-UnifiedConsentService* UnifiedConsentServiceFactory::GetForProfile(
-    Profile* profile) {
-  return static_cast<UnifiedConsentService*>(
+unified_consent::UnifiedConsentService*
+UnifiedConsentServiceFactory::GetForProfile(Profile* profile) {
+  return static_cast<unified_consent::UnifiedConsentService*>(
       GetInstance()->GetServiceForBrowserContext(profile, true));
 }
 
@@ -40,7 +40,7 @@
 
 void UnifiedConsentServiceFactory::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
-  UnifiedConsentService::RegisterPrefs(registry);
+  unified_consent::UnifiedConsentService::RegisterPrefs(registry);
 }
 
 KeyedService* UnifiedConsentServiceFactory::BuildServiceInstanceFor(
@@ -50,7 +50,7 @@
   if (!IsUnifiedConsentEnabled(profile))
     return nullptr;
 
-  return new UnifiedConsentService(
+  return new unified_consent::UnifiedConsentService(
       new ChromeUnifiedConsentServiceClient(profile->GetPrefs()),
       profile->GetPrefs(), IdentityManagerFactory::GetForProfile(profile),
       ProfileSyncServiceFactory::GetSyncServiceForBrowserContext(profile));
diff --git a/chrome/browser/unified_consent/unified_consent_service_factory.h b/chrome/browser/unified_consent/unified_consent_service_factory.h
index 57507521..1f453f6 100644
--- a/chrome/browser/unified_consent/unified_consent_service_factory.h
+++ b/chrome/browser/unified_consent/unified_consent_service_factory.h
@@ -10,7 +10,9 @@
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
 class Profile;
+namespace unified_consent {
 class UnifiedConsentService;
+}
 
 class UnifiedConsentServiceFactory : public BrowserContextKeyedServiceFactory {
  public:
@@ -18,7 +20,8 @@
   // (creating one if none exists). Returns nullptr if this profile cannot have
   // a UnifiedConsentService (e.g. UnifiedConsent is not enabled for |profile|
   // or |profile| is incognito).
-  static UnifiedConsentService* GetForProfile(Profile* profile);
+  static unified_consent::UnifiedConsentService* GetForProfile(
+      Profile* profile);
 
   // Returns an instance of the factory singleton.
   static UnifiedConsentServiceFactory* GetInstance();
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 55c4d1a..df2aafaf 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -136,6 +136,8 @@
     "gesture_detector.h",
     "graphics_delegate.cc",
     "graphics_delegate.h",
+    "input_event.cc",
+    "input_event.h",
     "keyboard_delegate.h",
     "keyboard_ui_interface.h",
     "macros.h",
@@ -308,6 +310,7 @@
     "fps_meter_unittest.cc",
     "gesture_detector_unittest.cc",
     "model/text_input_info_unittest.cc",
+    "platform_ui_input_delegate_unittest.cc",
     "pose_util_unittest.cc",
     "service/vr_device_manager_unittest.cc",
     "sliding_average_unittest.cc",
diff --git a/chrome/browser/vr/content_input_delegate.cc b/chrome/browser/vr/content_input_delegate.cc
index c5dbdfd..fc144651c 100644
--- a/chrome/browser/vr/content_input_delegate.cc
+++ b/chrome/browser/vr/content_input_delegate.cc
@@ -8,8 +8,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/vr/platform_controller.h"
 #include "chrome/browser/vr/platform_input_handler.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
-#include "third_party/blink/public/platform/web_mouse_event.h"
 
 namespace vr {
 
@@ -48,26 +46,21 @@
 }
 
 void ContentInputDelegate::SendGestureToTarget(
-    std::unique_ptr<blink::WebInputEvent> event) {
-  if (!event || !input_handler() || ContentGestureIsLocked(event->GetType()))
+    std::unique_ptr<InputEvent> event) {
+  if (!event || !input_handler() || ContentGestureIsLocked(event->type()))
     return;
 
   input_handler()->ForwardEventToContent(std::move(event), content_id_);
 }
 
-bool ContentInputDelegate::ContentGestureIsLocked(
-    blink::WebInputEvent::Type type) {
-  // TODO (asimjour) create a new MouseEnter event when we swap webcontents and
+bool ContentInputDelegate::ContentGestureIsLocked(InputEvent::Type type) {
+  // TODO (asimjour) create a new HoverEnter event when we swap webcontents and
   // pointer is on the content quad.
-  if (type == blink::WebInputEvent::kGestureScrollBegin ||
-      type == blink::WebInputEvent::kMouseMove ||
-      type == blink::WebInputEvent::kMouseDown ||
-      type == blink::WebInputEvent::kMouseEnter)
+  if (type == InputEvent::kScrollBegin || type == InputEvent::kHoverMove ||
+      type == InputEvent::kButtonDown || type == InputEvent::kHoverEnter)
     locked_content_id_ = content_id_;
 
-  if (locked_content_id_ != content_id_)
-    return true;
-  return false;
+  return locked_content_id_ != content_id_;
 }
 
 void ContentInputDelegate::OnWebInputIndicesChanged(
diff --git a/chrome/browser/vr/content_input_delegate.h b/chrome/browser/vr/content_input_delegate.h
index eca2763..3f2ad8a 100644
--- a/chrome/browser/vr/content_input_delegate.h
+++ b/chrome/browser/vr/content_input_delegate.h
@@ -16,7 +16,6 @@
 #include "chrome/browser/vr/platform_ui_input_delegate.h"
 #include "chrome/browser/vr/text_edit_action.h"
 #include "chrome/browser/vr/vr_export.h"
-#include "third_party/blink/public/platform/web_input_event.h"
 
 namespace vr {
 
@@ -54,8 +53,7 @@
   void ClearTextInputState();
 
  protected:
-  void SendGestureToTarget(
-      std::unique_ptr<blink::WebInputEvent> event) override;
+  void SendGestureToTarget(std::unique_ptr<InputEvent> event) override;
 
  private:
   enum TextRequestState {
@@ -63,7 +61,7 @@
     kRequested,
     kResponseReceived,
   };
-  bool ContentGestureIsLocked(blink::WebInputEvent::Type type);
+  bool ContentGestureIsLocked(InputEvent::Type type);
   void OnWebInputTextChanged(const base::string16& text);
 
   int content_id_ = 0;
diff --git a/chrome/browser/vr/elements/content_element.cc b/chrome/browser/vr/elements/content_element.cc
index e41b43b5..01bbf156 100644
--- a/chrome/browser/vr/elements/content_element.cc
+++ b/chrome/browser/vr/elements/content_element.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/vr/text_input_delegate.h"
 #include "chrome/browser/vr/ui_scene_constants.h"
 #include "chrome/browser/vr/vr_gl_util.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace vr {
diff --git a/chrome/browser/vr/elements/content_element_unittest.cc b/chrome/browser/vr/elements/content_element_unittest.cc
index df73ba4..7326748 100644
--- a/chrome/browser/vr/elements/content_element_unittest.cc
+++ b/chrome/browser/vr/elements/content_element_unittest.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/vr/text_edit_action.h"
 #include "chrome/browser/vr/ui_scene.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/platform/web_input_event.h"
 
 using ::testing::_;
 using ::testing::InSequence;
@@ -53,10 +52,8 @@
   TestPlatformInputHandler() {}
   ~TestPlatformInputHandler() override {}
 
-  void ForwardEventToPlatformUi(
-      std::unique_ptr<blink::WebInputEvent>) override {}
-  void ForwardEventToContent(std::unique_ptr<blink::WebInputEvent>,
-                             int) override {}
+  void ForwardEventToPlatformUi(std::unique_ptr<InputEvent>) override {}
+  void ForwardEventToContent(std::unique_ptr<InputEvent>, int) override {}
 
   void ClearFocusedElement() override { clear_focus_called_ = true; }
   void OnWebInputEdited(const TextEdits& edits) override { edits_ = edits; }
diff --git a/chrome/browser/vr/elements/paged_scroll_view.cc b/chrome/browser/vr/elements/paged_scroll_view.cc
index ace45fa4..1cca5fe 100644
--- a/chrome/browser/vr/elements/paged_scroll_view.cc
+++ b/chrome/browser/vr/elements/paged_scroll_view.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/vr/elements/paged_scroll_view.h"
 
+#include "chrome/browser/vr/input_event.h"
 #include "chrome/browser/vr/target_property.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 
 namespace vr {
 
@@ -23,23 +23,19 @@
 
 PagedScrollView::~PagedScrollView() {}
 
-void PagedScrollView::OnScrollBegin(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
+void PagedScrollView::OnScrollBegin(std::unique_ptr<InputEvent> gesture,
+                                    const gfx::PointF& position) {
   animation().RemoveKeyframeModelsWithProperty(SCROLL_OFFSET);
   scroll_drag_delta_ = 0.0f;
 }
 
-void PagedScrollView::OnScrollUpdate(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
-  scroll_drag_delta_ +=
-      gesture->data.scroll_update.delta_x * kScrollScaleFactor;
+void PagedScrollView::OnScrollUpdate(std::unique_ptr<InputEvent> gesture,
+                                     const gfx::PointF& position) {
+  scroll_drag_delta_ += gesture->scroll_data.delta_x * kScrollScaleFactor;
 }
 
-void PagedScrollView::OnScrollEnd(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
+void PagedScrollView::OnScrollEnd(std::unique_ptr<InputEvent> gesture,
+                                  const gfx::PointF& position) {
   size_t next_page = current_page_;
   if (next_page + 1 < NumPages() && scroll_drag_delta_ < -kScrollThreshold) {
     next_page++;
diff --git a/chrome/browser/vr/elements/paged_scroll_view.h b/chrome/browser/vr/elements/paged_scroll_view.h
index d6102ef..0c2506b9 100644
--- a/chrome/browser/vr/elements/paged_scroll_view.h
+++ b/chrome/browser/vr/elements/paged_scroll_view.h
@@ -19,11 +19,11 @@
   ~PagedScrollView() override;
 
   // UiElement overrides.
-  void OnScrollBegin(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollBegin(std::unique_ptr<InputEvent> gesture,
                      const gfx::PointF& position) override;
-  void OnScrollUpdate(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollUpdate(std::unique_ptr<InputEvent> gesture,
                       const gfx::PointF& position) override;
-  void OnScrollEnd(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollEnd(std::unique_ptr<InputEvent> gesture,
                    const gfx::PointF& position) override;
   void NotifyClientFloatAnimated(float value,
                                  int target_property_id,
diff --git a/chrome/browser/vr/elements/platform_ui_element.cc b/chrome/browser/vr/elements/platform_ui_element.cc
index b0a3fdb..19dd704b 100644
--- a/chrome/browser/vr/elements/platform_ui_element.cc
+++ b/chrome/browser/vr/elements/platform_ui_element.cc
@@ -5,7 +5,6 @@
 #include "chrome/browser/vr/elements/content_element.h"
 
 #include "chrome/browser/vr/platform_ui_input_delegate.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace vr {
@@ -61,32 +60,28 @@
     delegate_->OnTouchMove(position, timestamp);
 }
 
-void PlatformUiElement::OnFlingCancel(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
+void PlatformUiElement::OnFlingCancel(std::unique_ptr<InputEvent> gesture,
+                                      const gfx::PointF& position) {
   if (delegate_)
-    delegate_->OnFlingCancel(std::move(gesture), position);
+    delegate_->OnInputEvent(std::move(gesture), position);
 }
 
-void PlatformUiElement::OnScrollBegin(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
+void PlatformUiElement::OnScrollBegin(std::unique_ptr<InputEvent> gesture,
+                                      const gfx::PointF& position) {
   if (delegate_)
-    delegate_->OnScrollBegin(std::move(gesture), position);
+    delegate_->OnInputEvent(std::move(gesture), position);
 }
 
-void PlatformUiElement::OnScrollUpdate(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
+void PlatformUiElement::OnScrollUpdate(std::unique_ptr<InputEvent> gesture,
+                                       const gfx::PointF& position) {
   if (delegate_)
-    delegate_->OnScrollUpdate(std::move(gesture), position);
+    delegate_->OnInputEvent(std::move(gesture), position);
 }
 
-void PlatformUiElement::OnScrollEnd(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
+void PlatformUiElement::OnScrollEnd(std::unique_ptr<InputEvent> gesture,
+                                    const gfx::PointF& position) {
   if (delegate_)
-    delegate_->OnScrollEnd(std::move(gesture), position);
+    delegate_->OnInputEvent(std::move(gesture), position);
 }
 
 void PlatformUiElement::SetTextureId(unsigned int texture_id) {
diff --git a/chrome/browser/vr/elements/platform_ui_element.h b/chrome/browser/vr/elements/platform_ui_element.h
index 425bf0d..62d24140 100644
--- a/chrome/browser/vr/elements/platform_ui_element.h
+++ b/chrome/browser/vr/elements/platform_ui_element.h
@@ -33,13 +33,13 @@
                   base::TimeTicks timestamp) override;
   void OnTouchMove(const gfx::PointF& position,
                    base::TimeTicks timestamp) override;
-  void OnFlingCancel(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnFlingCancel(std::unique_ptr<InputEvent> gesture,
                      const gfx::PointF& position) override;
-  void OnScrollBegin(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollBegin(std::unique_ptr<InputEvent> gesture,
                      const gfx::PointF& position) override;
-  void OnScrollUpdate(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollUpdate(std::unique_ptr<InputEvent> gesture,
                       const gfx::PointF& position) override;
-  void OnScrollEnd(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollEnd(std::unique_ptr<InputEvent> gesture,
                    const gfx::PointF& position) override;
 
   void Render(UiElementRenderer* renderer,
diff --git a/chrome/browser/vr/elements/scrollable_element.cc b/chrome/browser/vr/elements/scrollable_element.cc
index 14858924..60be192 100644
--- a/chrome/browser/vr/elements/scrollable_element.cc
+++ b/chrome/browser/vr/elements/scrollable_element.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/vr/elements/scrollable_element.h"
 
 #include "base/numerics/ranges.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "chrome/browser/vr/input_event.h"
 
 namespace vr {
 
@@ -98,30 +98,26 @@
   inner_element_->AddChild(std::move(child));
 }
 
-void ScrollableElement::OnScrollBegin(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
+void ScrollableElement::OnScrollBegin(std::unique_ptr<InputEvent> gesture,
+                                      const gfx::PointF& position) {
   cached_transition_ = animation().transition();
   animation().set_transition(Transition());
 }
 
-void ScrollableElement::OnScrollUpdate(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
-  const auto& update = gesture->data.scroll_update;
+void ScrollableElement::OnScrollUpdate(std::unique_ptr<InputEvent> gesture,
+                                       const gfx::PointF& position) {
   float half_scroll_span = ComputeScrollSpan() / 2.0f;
   if (orientation_ == kHorizontal) {
-    scroll_offset_ -= update.delta_x * kScrollScaleFactor;
+    scroll_offset_ -= gesture->scroll_data.delta_x * kScrollScaleFactor;
   } else {
-    scroll_offset_ -= update.delta_y * kScrollScaleFactor;
+    scroll_offset_ -= gesture->scroll_data.delta_y * kScrollScaleFactor;
   }
   scroll_offset_ =
       base::ClampToRange(scroll_offset_, -half_scroll_span, half_scroll_span);
 }
 
-void ScrollableElement::OnScrollEnd(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& position) {
+void ScrollableElement::OnScrollEnd(std::unique_ptr<InputEvent> gesture,
+                                    const gfx::PointF& position) {
   animation().set_transition(cached_transition_);
 }
 
diff --git a/chrome/browser/vr/elements/scrollable_element.h b/chrome/browser/vr/elements/scrollable_element.h
index 0c2b5ba..5141a36 100644
--- a/chrome/browser/vr/elements/scrollable_element.h
+++ b/chrome/browser/vr/elements/scrollable_element.h
@@ -39,11 +39,11 @@
 
   void SetScrollAnchoring(LayoutAlignment anchoring);
 
-  void OnScrollBegin(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollBegin(std::unique_ptr<InputEvent> gesture,
                      const gfx::PointF& position) override;
-  void OnScrollUpdate(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollUpdate(std::unique_ptr<InputEvent> gesture,
                       const gfx::PointF& position) override;
-  void OnScrollEnd(std::unique_ptr<blink::WebGestureEvent> gesture,
+  void OnScrollEnd(std::unique_ptr<InputEvent> gesture,
                    const gfx::PointF& position) override;
 
  private:
diff --git a/chrome/browser/vr/elements/scrollable_element_unittest.cc b/chrome/browser/vr/elements/scrollable_element_unittest.cc
index 16ee6c4..afaacb79 100644
--- a/chrome/browser/vr/elements/scrollable_element_unittest.cc
+++ b/chrome/browser/vr/elements/scrollable_element_unittest.cc
@@ -6,19 +6,17 @@
 
 #include "base/stl_util.h"
 #include "cc/test/geometry_test_utils.h"
+#include "chrome/browser/vr/input_event.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 
 namespace vr {
 
 namespace {
 
-std::unique_ptr<blink::WebGestureEvent> CreateScrollUpdate(float delta_x,
-                                                           float delta_y) {
-  auto gesture = std::make_unique<blink::WebGestureEvent>();
-  gesture->SetType(blink::WebGestureEvent::kGestureScrollBegin);
-  gesture->data.scroll_update.delta_x = delta_x;
-  gesture->data.scroll_update.delta_y = delta_y;
+std::unique_ptr<InputEvent> CreateScrollUpdate(float delta_x, float delta_y) {
+  auto gesture = std::make_unique<InputEvent>(InputEvent::kScrollBegin);
+  gesture->scroll_data.delta_x = delta_x;
+  gesture->scroll_data.delta_y = delta_y;
   return gesture;
 }
 
diff --git a/chrome/browser/vr/elements/text_input_unittest.cc b/chrome/browser/vr/elements/text_input_unittest.cc
index b2d16695..99a6871 100644
--- a/chrome/browser/vr/elements/text_input_unittest.cc
+++ b/chrome/browser/vr/elements/text_input_unittest.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/vr/ui_scene_constants.h"
 #include "chrome/browser/vr/ui_scene_creator.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 #include "ui/gfx/render_text.h"
 
 using ::testing::_;
diff --git a/chrome/browser/vr/elements/ui_element.cc b/chrome/browser/vr/elements/ui_element.cc
index d97e8f1..59efded 100644
--- a/chrome/browser/vr/elements/ui_element.cc
+++ b/chrome/browser/vr/elements/ui_element.cc
@@ -12,9 +12,9 @@
 #include "base/strings/string_split.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
+#include "chrome/browser/vr/input_event.h"
 #include "chrome/browser/vr/model/camera_model.h"
 #include "chrome/browser/vr/vr_gl_util.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 #include "third_party/skia/include/core/SkRRect.h"
 #include "third_party/skia/include/core/SkRect.h"
 #include "ui/gfx/geometry/angle_conversions.h"
@@ -225,13 +225,13 @@
   }
 }
 
-void UiElement::OnFlingCancel(std::unique_ptr<blink::WebGestureEvent> gesture,
+void UiElement::OnFlingCancel(std::unique_ptr<InputEvent> gesture,
                               const gfx::PointF& position) {}
-void UiElement::OnScrollBegin(std::unique_ptr<blink::WebGestureEvent> gesture,
+void UiElement::OnScrollBegin(std::unique_ptr<InputEvent> gesture,
                               const gfx::PointF& position) {}
-void UiElement::OnScrollUpdate(std::unique_ptr<blink::WebGestureEvent> gesture,
+void UiElement::OnScrollUpdate(std::unique_ptr<InputEvent> gesture,
                                const gfx::PointF& position) {}
-void UiElement::OnScrollEnd(std::unique_ptr<blink::WebGestureEvent> gesture,
+void UiElement::OnScrollEnd(std::unique_ptr<InputEvent> gesture,
                             const gfx::PointF& position) {}
 
 void UiElement::OnFocusChanged(bool focused) {
diff --git a/chrome/browser/vr/elements/ui_element.h b/chrome/browser/vr/elements/ui_element.h
index 877e0066..b121e2ff 100644
--- a/chrome/browser/vr/elements/ui_element.h
+++ b/chrome/browser/vr/elements/ui_element.h
@@ -38,15 +38,12 @@
 class TimeTicks;
 }
 
-namespace blink {
-class WebGestureEvent;
-}
-
 namespace vr {
 
 class KeyframeModel;
 class SkiaSurfaceProvider;
 class UiElementRenderer;
+class InputEvent;
 struct CameraModel;
 struct EditedText;
 
@@ -160,13 +157,13 @@
                           base::TimeTicks timestamp);
   virtual void OnTouchMove(const gfx::PointF& position,
                            base::TimeTicks timestamp);
-  virtual void OnFlingCancel(std::unique_ptr<blink::WebGestureEvent> gesture,
+  virtual void OnFlingCancel(std::unique_ptr<InputEvent> gesture,
                              const gfx::PointF& position);
-  virtual void OnScrollBegin(std::unique_ptr<blink::WebGestureEvent> gesture,
+  virtual void OnScrollBegin(std::unique_ptr<InputEvent> gesture,
                              const gfx::PointF& position);
-  virtual void OnScrollUpdate(std::unique_ptr<blink::WebGestureEvent> gesture,
+  virtual void OnScrollUpdate(std::unique_ptr<InputEvent> gesture,
                               const gfx::PointF& position);
-  virtual void OnScrollEnd(std::unique_ptr<blink::WebGestureEvent> gesture,
+  virtual void OnScrollEnd(std::unique_ptr<InputEvent> gesture,
                            const gfx::PointF& position);
 
   // Whether the point (relative to the origin of the element), should be
diff --git a/chrome/browser/vr/gesture_detector.cc b/chrome/browser/vr/gesture_detector.cc
index acaa914e..ee7a321 100644
--- a/chrome/browser/vr/gesture_detector.cc
+++ b/chrome/browser/vr/gesture_detector.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/vr/gesture_detector.h"
 
 #include "base/numerics/math_constants.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
+#include "chrome/browser/vr/input_event.h"
 
 namespace vr {
 
@@ -39,7 +39,7 @@
 }
 GestureDetector::~GestureDetector() = default;
 
-std::unique_ptr<GestureList> GestureDetector::DetectGestures(
+std::unique_ptr<InputEventList> GestureDetector::DetectGestures(
     const TouchInfo& input_touch_info,
     base::TimeTicks current_timestamp,
     bool force_cancel) {
@@ -49,51 +49,57 @@
   if (touch_position_changed_)
     UpdateOverallVelocity(touch_info);
 
-  auto gesture_list = std::make_unique<GestureList>();
+  auto gesture_list = std::make_unique<InputEventList>();
   auto gesture = GetGestureFromTouchInfo(touch_info, force_cancel);
-  gesture->SetSourceDevice(blink::kWebGestureDeviceTouchpad);
 
-  if (gesture->GetType() == blink::WebInputEvent::kGestureScrollEnd)
+  if (!gesture)
+    return gesture_list;
+
+  if (gesture->type() == InputEvent::kScrollEnd)
     Reset();
 
-  if (gesture->GetType() != blink::WebInputEvent::kUndefined)
+  if (gesture->type() != InputEvent::kTypeUndefined)
     gesture_list->push_back(std::move(gesture));
+
   return gesture_list;
 }
 
-std::unique_ptr<blink::WebGestureEvent>
-GestureDetector::GetGestureFromTouchInfo(const TouchInfo& touch_info,
-                                         bool force_cancel) {
-  auto gesture = std::make_unique<blink::WebGestureEvent>();
-  gesture->SetTimeStamp(touch_info.touch_point.timestamp);
+std::unique_ptr<InputEvent> GestureDetector::GetGestureFromTouchInfo(
+    const TouchInfo& touch_info,
+    bool force_cancel) {
+  std::unique_ptr<InputEvent> gesture;
 
   switch (state_->label) {
     // User has not put finger on touch pad.
     case WAITING:
-      HandleWaitingState(touch_info, gesture.get());
+      gesture = HandleWaitingState(touch_info);
       break;
     // User has not started a gesture (by moving out of slop).
     case TOUCHING:
-      HandleDetectingState(touch_info, force_cancel, gesture.get());
+      gesture = HandleDetectingState(touch_info, force_cancel);
       break;
     // User is scrolling on touchpad
     case SCROLLING:
-      HandleScrollingState(touch_info, force_cancel, gesture.get());
+      gesture = HandleScrollingState(touch_info, force_cancel);
       break;
     // The user has finished scrolling, but we'll hallucinate a few points
     // before really finishing.
     case POST_SCROLL:
-      HandlePostScrollingState(touch_info, force_cancel, gesture.get());
+      gesture = HandlePostScrollingState(touch_info, force_cancel);
       break;
     default:
       NOTREACHED();
       break;
   }
+
+  if (gesture)
+    gesture->set_time_stamp(touch_info.touch_point.timestamp);
+
   return gesture;
 }
 
-void GestureDetector::HandleWaitingState(const TouchInfo& touch_info,
-                                         blink::WebGestureEvent* gesture) {
+std::unique_ptr<InputEvent> GestureDetector::HandleWaitingState(
+    const TouchInfo& touch_info) {
   // User puts finger on touch pad (or when the touch down for current gesture
   // is missed, initiate gesture from current touch point).
   if (touch_info.touch_down || touch_info.is_touching) {
@@ -103,18 +109,18 @@
     state_->cur_touch_point = touch_info.touch_point;
     state_->label = TOUCHING;
 
-    gesture->SetType(blink::WebInputEvent::kGestureFlingCancel);
-    gesture->data.fling_cancel.prevent_boosting = false;
+    return std::make_unique<InputEvent>(InputEvent::kFlingCancel);
   }
+  return nullptr;
 }
 
-void GestureDetector::HandleDetectingState(const TouchInfo& touch_info,
-                                           bool force_cancel,
-                                           blink::WebGestureEvent* gesture) {
+std::unique_ptr<InputEvent> GestureDetector::HandleDetectingState(
+    const TouchInfo& touch_info,
+    bool force_cancel) {
   // User lifts up finger from touch pad.
   if (touch_info.touch_up || !touch_info.is_touching) {
     Reset();
-    return;
+    return nullptr;
   }
 
   // Touch position is changed, the touch point moves outside of slop,
@@ -122,54 +128,51 @@
   if (touch_position_changed_ && touch_info.is_touching &&
       !InSlop(touch_info.touch_point.position) && !force_cancel) {
     state_->label = SCROLLING;
-    gesture->SetType(blink::WebInputEvent::kGestureScrollBegin);
+    auto gesture = std::make_unique<InputEvent>(InputEvent::kScrollBegin);
     UpdateGestureParameters(touch_info);
-    gesture->data.scroll_begin.delta_x_hint =
-        state_->displacement.x() * kDisplacementScaleFactor;
-    gesture->data.scroll_begin.delta_y_hint =
-        state_->displacement.y() * kDisplacementScaleFactor;
-    gesture->data.scroll_begin.delta_hint_units =
-        blink::WebGestureEvent::ScrollUnits::kPrecisePixels;
+    UpdateGestureWithScrollDelta(gesture.get());
+    return gesture;
   }
+  return nullptr;
 }
 
-void GestureDetector::HandleScrollingState(const TouchInfo& touch_info,
-                                           bool force_cancel,
-                                           blink::WebGestureEvent* gesture) {
+std::unique_ptr<InputEvent> GestureDetector::HandleScrollingState(
+    const TouchInfo& touch_info,
+    bool force_cancel) {
   if (force_cancel) {
-    gesture->SetType(blink::WebInputEvent::kGestureScrollEnd);
     UpdateGestureParameters(touch_info);
-    return;
+    return std::make_unique<InputEvent>(InputEvent::kScrollEnd);
   }
   if (touch_info.touch_up || !(touch_info.is_touching)) {
     state_->label = POST_SCROLL;
   }
   if (touch_position_changed_) {
-    gesture->SetType(blink::WebInputEvent::kGestureScrollUpdate);
+    auto gesture = std::make_unique<InputEvent>(InputEvent::kScrollUpdate);
     UpdateGestureParameters(touch_info);
-    UpdateGestureWithScrollDelta(gesture);
+    UpdateGestureWithScrollDelta(gesture.get());
+    return gesture;
   }
+  return nullptr;
 }
 
-void GestureDetector::HandlePostScrollingState(
+std::unique_ptr<InputEvent> GestureDetector::HandlePostScrollingState(
     const TouchInfo& touch_info,
-    bool force_cancel,
-    blink::WebGestureEvent* gesture) {
+    bool force_cancel) {
   if (extrapolated_touch_ == 0 || force_cancel) {
-    gesture->SetType(blink::WebInputEvent::kGestureScrollEnd);
     UpdateGestureParameters(touch_info);
+    return std::make_unique<InputEvent>(InputEvent::kScrollEnd);
   } else {
-    gesture->SetType(blink::WebInputEvent::kGestureScrollUpdate);
+    auto gesture = std::make_unique<InputEvent>(InputEvent::kScrollUpdate);
     UpdateGestureParameters(touch_info);
-    UpdateGestureWithScrollDelta(gesture);
+    UpdateGestureWithScrollDelta(gesture.get());
+    return gesture;
   }
 }
 
-void GestureDetector::UpdateGestureWithScrollDelta(
-    blink::WebGestureEvent* gesture) {
-  gesture->data.scroll_update.delta_x =
+void GestureDetector::UpdateGestureWithScrollDelta(InputEvent* gesture) {
+  gesture->scroll_data.delta_x =
       state_->displacement.x() * kDisplacementScaleFactor;
-  gesture->data.scroll_update.delta_y =
+  gesture->scroll_data.delta_y =
       state_->displacement.y() * kDisplacementScaleFactor;
 }
 
diff --git a/chrome/browser/vr/gesture_detector.h b/chrome/browser/vr/gesture_detector.h
index 07df080..16579452 100644
--- a/chrome/browser/vr/gesture_detector.h
+++ b/chrome/browser/vr/gesture_detector.h
@@ -12,13 +12,11 @@
 #include "chrome/browser/vr/vr_export.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 
-namespace blink {
-class WebGestureEvent;
-}
-
 namespace vr {
 
-using GestureList = std::vector<std::unique_ptr<blink::WebGestureEvent>>;
+class InputEvent;
+
+using InputEventList = std::vector<std::unique_ptr<InputEvent>>;
 
 struct TouchPoint {
   gfx::Vector2dF position;
@@ -37,9 +35,10 @@
   GestureDetector();
   virtual ~GestureDetector();
 
-  std::unique_ptr<GestureList> DetectGestures(const TouchInfo& touch_info,
-                                              base::TimeTicks current_timestamp,
-                                              bool force_cancel);
+  std::unique_ptr<InputEventList> DetectGestures(
+      const TouchInfo& touch_info,
+      base::TimeTicks current_timestamp,
+      bool force_cancel);
 
  private:
   enum GestureDetectorStateLabel {
@@ -60,23 +59,20 @@
     gfx::Vector2dF displacement;
   };
 
-  std::unique_ptr<blink::WebGestureEvent> GetGestureFromTouchInfo(
+  std::unique_ptr<InputEvent> GetGestureFromTouchInfo(
       const TouchInfo& input_touch_info,
       bool force_cancel);
 
-  void HandleWaitingState(const TouchInfo& touch_info,
-                          blink::WebGestureEvent* gesture);
-  void HandleDetectingState(const TouchInfo& touch_info,
-                            bool force_cancel,
-                            blink::WebGestureEvent* gesture);
-  void HandleScrollingState(const TouchInfo& touch_info,
-                            bool force_cancel,
-                            blink::WebGestureEvent* gesture);
-  void HandlePostScrollingState(const TouchInfo& touch_info,
-                                bool force_cancel,
-                                blink::WebGestureEvent* gesture);
+  std::unique_ptr<InputEvent> HandleWaitingState(const TouchInfo& touch_info);
+  std::unique_ptr<InputEvent> HandleDetectingState(const TouchInfo& touch_info,
+                                                   bool force_cancel);
+  std::unique_ptr<InputEvent> HandleScrollingState(const TouchInfo& touch_info,
+                                                   bool force_cancel);
+  std::unique_ptr<InputEvent> HandlePostScrollingState(
+      const TouchInfo& touch_info,
+      bool force_cancel);
 
-  void UpdateGestureWithScrollDelta(blink::WebGestureEvent* gesture);
+  void UpdateGestureWithScrollDelta(InputEvent* gesture);
 
   // If the user is touching the touch pad and the touch point is different from
   // before, update the touch point and return true. Otherwise, return false.
diff --git a/chrome/browser/vr/gesture_detector_unittest.cc b/chrome/browser/vr/gesture_detector_unittest.cc
index d7ea291..4de4c2cc0 100644
--- a/chrome/browser/vr/gesture_detector_unittest.cc
+++ b/chrome/browser/vr/gesture_detector_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/vr/gesture_detector.h"
 
+#include "chrome/browser/vr/input_event.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 
 namespace {
 constexpr float kDelta = 0.001f;
@@ -34,8 +34,7 @@
       .is_touching = true,
   };
   auto gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureFlingCancel);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kFlingCancel);
 
   // A small move doesn't trigger scrolling yet.
   timestamp += base::TimeDelta::FromMilliseconds(1);
@@ -70,11 +69,10 @@
       .is_touching = true,
   };
   auto gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollBegin);
-  auto* gesture = gestures->front().get();
-  EXPECT_GT(gesture->data.scroll_update.delta_x, 0.0f);
-  EXPECT_EQ(gesture->data.scroll_update.delta_y, 0.0f);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollBegin);
+  auto* gesture = static_cast<InputEvent*>(gestures->front().get());
+  EXPECT_GT(gesture->scroll_data.delta_x, 0.0f);
+  EXPECT_EQ(gesture->scroll_data.delta_y, 0.0f);
 
   // Move slightly up.
   timestamp += base::TimeDelta::FromMilliseconds(1);
@@ -85,31 +83,27 @@
       .is_touching = true,
   };
   gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollUpdate);
-  gesture = gestures->front().get();
-  EXPECT_EQ(gesture->data.scroll_update.delta_x, 0.0f);
-  EXPECT_GT(gesture->data.scroll_update.delta_y, 0.0f);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollUpdate);
+  gesture = static_cast<InputEvent*>(gestures->front().get());
+  EXPECT_EQ(gesture->scroll_data.delta_x, 0.0f);
+  EXPECT_GT(gesture->scroll_data.delta_y, 0.0f);
 
   // Release touch. Scroll is extrapolated for 2 frames.
   touch_info.touch_up = true;
   touch_info.is_touching = false;
   timestamp += base::TimeDelta::FromMilliseconds(1);
   gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollUpdate);
-  gesture = gestures->front().get();
-  EXPECT_GT(gesture->data.scroll_update.delta_x, 0.0f);
-  EXPECT_GT(gesture->data.scroll_update.delta_y, 0.0f);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollUpdate);
+  gesture = static_cast<InputEvent*>(gestures->front().get());
+  EXPECT_GT(gesture->scroll_data.delta_x, 0.0f);
+  EXPECT_GT(gesture->scroll_data.delta_y, 0.0f);
   touch_info.touch_up = false;
   timestamp += base::TimeDelta::FromMilliseconds(1);
   gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollUpdate);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollUpdate);
   timestamp += base::TimeDelta::FromMilliseconds(1);
   gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollEnd);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollEnd);
 }
 
 TEST(GestureDetector, CancelDuringScrolling) {
@@ -133,13 +127,11 @@
       .is_touching = true,
   };
   auto gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollBegin);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollBegin);
 
   // Cancel.
   gestures = detector.DetectGestures(touch_info, timestamp, true);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollEnd);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollEnd);
 }
 
 TEST(GestureDetector, CancelDuringPostScrolling) {
@@ -163,21 +155,18 @@
       .is_touching = true,
   };
   auto gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollBegin);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollBegin);
 
   // Release touch. We should see extrapolated scrolling.
   touch_info.touch_up = true;
   touch_info.is_touching = false;
   gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollUpdate);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollUpdate);
 
   // Cancel.
   touch_info.touch_up = false;
   gestures = detector.DetectGestures(touch_info, timestamp, true);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollEnd);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollEnd);
 }
 
 TEST(GestureDetector, CancelAndTouchDuringPostScrolling) {
@@ -201,16 +190,14 @@
       .is_touching = true,
   };
   auto gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollBegin);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollBegin);
 
   // Release touch. We should see extrapolated scrolling.
   timestamp += base::TimeDelta::FromMilliseconds(1);
   touch_info.touch_up = true;
   touch_info.is_touching = false;
   gestures = detector.DetectGestures(touch_info, timestamp, false);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollUpdate);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollUpdate);
 
   // Cancel and touch.
   timestamp += base::TimeDelta::FromMilliseconds(1);
@@ -218,8 +205,7 @@
   touch_info.touch_down = true;
   touch_info.is_touching = true;
   gestures = detector.DetectGestures(touch_info, timestamp, true);
-  EXPECT_EQ(gestures->front()->GetType(),
-            blink::WebInputEvent::kGestureScrollEnd);
+  EXPECT_EQ(gestures->front()->type(), InputEvent::kScrollEnd);
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/input_event.cc b/chrome/browser/vr/input_event.cc
new file mode 100644
index 0000000..3832caa
--- /dev/null
+++ b/chrome/browser/vr/input_event.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 "chrome/browser/vr/input_event.h"
+
+namespace vr {
+
+InputEvent::InputEvent(Type type) : type_(type) {}
+
+InputEvent::~InputEvent() = default;
+
+}  // namespace vr
diff --git a/chrome/browser/vr/input_event.h b/chrome/browser/vr/input_event.h
new file mode 100644
index 0000000..f76ba26
--- /dev/null
+++ b/chrome/browser/vr/input_event.h
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VR_INPUT_EVENT_H_
+#define CHROME_BROWSER_VR_INPUT_EVENT_H_
+
+#include "base/time/time.h"
+#include "chrome/browser/vr/vr_export.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace vr {
+
+class VR_EXPORT InputEvent {
+ public:
+  enum Type {
+    kTypeUndefined = -1,
+
+    kHoverEnter,
+    kTypeFirst = kHoverEnter,
+    kHoverLeave,
+    kHoverMove,
+    kButtonDown,
+    kButtonUp,
+    kMove,
+    kFlingCancel,
+    kScrollBegin,
+    kScrollTypeFirst = kScrollBegin,
+    kScrollUpdate,
+    kScrollEnd,
+    kScrollTypeLast = kScrollEnd,
+
+    kNumVrInputEventTypes
+  };
+
+  explicit InputEvent(Type type);
+  virtual ~InputEvent();
+
+  Type type() const { return type_; }
+
+  base::TimeTicks time_stamp() const { return time_stamp_; }
+
+  void set_time_stamp(base::TimeTicks time_stamp) { time_stamp_ = time_stamp; }
+
+  gfx::PointF position_in_widget() const { return position_in_widget_; }
+
+  void set_position_in_widget(const gfx::PointF& position) {
+    position_in_widget_ = position;
+  }
+
+  void SetPositionInWidget(float x, float y) {
+    position_in_widget_ = gfx::PointF(x, y);
+  }
+
+  static bool IsScrollEventType(InputEvent::Type type) {
+    return kScrollTypeFirst <= type && type <= kScrollTypeLast;
+  }
+
+  struct {
+    float delta_x;
+    float delta_y;
+  } scroll_data;
+
+ private:
+  Type type_;
+  base::TimeTicks time_stamp_;
+  gfx::PointF position_in_widget_;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_INPUT_EVENT_H_
diff --git a/chrome/browser/vr/platform_input_handler.h b/chrome/browser/vr/platform_input_handler.h
index f16919f..40503d9f 100644
--- a/chrome/browser/vr/platform_input_handler.h
+++ b/chrome/browser/vr/platform_input_handler.h
@@ -7,10 +7,11 @@
 
 #include "base/callback.h"
 #include "chrome/browser/vr/text_edit_action.h"
-#include "third_party/blink/public/platform/web_input_event.h"
 
 namespace vr {
 
+class InputEvent;
+
 typedef typename base::OnceCallback<void(const base::string16&)>
     TextStateUpdateCallback;
 
@@ -19,11 +20,9 @@
 class PlatformInputHandler {
  public:
   virtual ~PlatformInputHandler() {}
-  virtual void ForwardEventToPlatformUi(
-      std::unique_ptr<blink::WebInputEvent> event) = 0;
-  virtual void ForwardEventToContent(
-      std::unique_ptr<blink::WebInputEvent> event,
-      int content_id) = 0;
+  virtual void ForwardEventToPlatformUi(std::unique_ptr<InputEvent> event) = 0;
+  virtual void ForwardEventToContent(std::unique_ptr<InputEvent> event,
+                                     int content_id) = 0;
 
   // Text input specific.
   virtual void ClearFocusedElement() = 0;
diff --git a/chrome/browser/vr/platform_ui_input_delegate.cc b/chrome/browser/vr/platform_ui_input_delegate.cc
index ab9f596..601273cc4 100644
--- a/chrome/browser/vr/platform_ui_input_delegate.cc
+++ b/chrome/browser/vr/platform_ui_input_delegate.cc
@@ -8,9 +8,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/vr/platform_controller.h"
 #include "chrome/browser/vr/platform_input_handler.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
-#include "third_party/blink/public/platform/web_mouse_event.h"
-#include "third_party/blink/public/platform/web_touch_event.h"
 
 namespace vr {
 
@@ -30,136 +27,80 @@
 void PlatformUiInputDelegate::OnHoverEnter(
     const gfx::PointF& normalized_hit_point,
     base::TimeTicks timestamp) {
-  SendGestureToTarget(MakeMouseEvent(blink::WebInputEvent::kMouseEnter,
-                                     normalized_hit_point, timestamp));
+  SendGestureToTarget(
+      MakeInputEvent(InputEvent::kHoverEnter, normalized_hit_point, timestamp));
 }
 
 void PlatformUiInputDelegate::OnHoverLeave(base::TimeTicks timestamp) {
-  // Note that we send an out of bounds mouse leave event. With blink feature
+  // Note that we send an out of bounds hover leave event. With blink feature
   // UpdateHoverPostLayout turned on, a MouseMove event will dispatched post a
   // Layout. Sending a mouse leave event at 0,0 will result continuous
   // MouseMove events sent to the content if the content keeps relayout itself.
   // See https://crbug.com/762573 for details.
-  SendGestureToTarget(MakeMouseEvent(blink::WebInputEvent::kMouseLeave,
-                                     kOutOfBoundsPoint, timestamp));
+  SendGestureToTarget(
+      MakeInputEvent(InputEvent::kHoverLeave, kOutOfBoundsPoint, timestamp));
 }
 
 void PlatformUiInputDelegate::OnHoverMove(
     const gfx::PointF& normalized_hit_point,
     base::TimeTicks timestamp) {
-  SendGestureToTarget(MakeMouseEvent(blink::WebInputEvent::kMouseMove,
-                                     normalized_hit_point, timestamp));
+  SendGestureToTarget(
+      MakeInputEvent(InputEvent::kHoverMove, normalized_hit_point, timestamp));
 }
 
 void PlatformUiInputDelegate::OnButtonDown(
     const gfx::PointF& normalized_hit_point,
     base::TimeTicks timestamp) {
-  SendGestureToTarget(MakeTouchEvent(blink::WebInputEvent::kTouchStart,
-                                     normalized_hit_point, timestamp));
+  SendGestureToTarget(
+      MakeInputEvent(InputEvent::kButtonDown, normalized_hit_point, timestamp));
 }
 
 void PlatformUiInputDelegate::OnButtonUp(
     const gfx::PointF& normalized_hit_point,
     base::TimeTicks timestamp) {
-  SendGestureToTarget(MakeTouchEvent(blink::WebInputEvent::kTouchEnd,
-                                     normalized_hit_point, timestamp));
+  SendGestureToTarget(
+      MakeInputEvent(InputEvent::kButtonUp, normalized_hit_point, timestamp));
 }
 
 void PlatformUiInputDelegate::OnTouchMove(
     const gfx::PointF& normalized_hit_point,
     base::TimeTicks timestamp) {
-  SendGestureToTarget(MakeTouchEvent(blink::WebInputEvent::kTouchMove,
-                                     normalized_hit_point, timestamp));
+  SendGestureToTarget(
+      MakeInputEvent(InputEvent::kMove, normalized_hit_point, timestamp));
 }
 
-void PlatformUiInputDelegate::OnFlingCancel(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
+void PlatformUiInputDelegate::OnInputEvent(
+    std::unique_ptr<InputEvent> event,
     const gfx::PointF& normalized_hit_point) {
-  UpdateGesture(normalized_hit_point, *gesture);
-  SendGestureToTarget(std::move(gesture));
-}
-
-void PlatformUiInputDelegate::OnScrollBegin(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& normalized_hit_point) {
-  UpdateGesture(normalized_hit_point, *gesture);
-  SendGestureToTarget(std::move(gesture));
-}
-
-void PlatformUiInputDelegate::OnScrollUpdate(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& normalized_hit_point) {
-  UpdateGesture(normalized_hit_point, *gesture);
-  SendGestureToTarget(std::move(gesture));
-}
-
-void PlatformUiInputDelegate::OnScrollEnd(
-    std::unique_ptr<blink::WebGestureEvent> gesture,
-    const gfx::PointF& normalized_hit_point) {
-  UpdateGesture(normalized_hit_point, *gesture);
-  SendGestureToTarget(std::move(gesture));
+  UpdateGesture(normalized_hit_point, event.get());
+  SendGestureToTarget(std::move(event));
 }
 
 void PlatformUiInputDelegate::UpdateGesture(
     const gfx::PointF& normalized_content_hit_point,
-    blink::WebGestureEvent& gesture) {
-  gesture.SetPositionInWidget(
+    InputEvent* gesture) {
+  gesture->set_position_in_widget(
       ScalePoint(normalized_content_hit_point, size_.width(), size_.height()));
 }
 
 void PlatformUiInputDelegate::SendGestureToTarget(
-    std::unique_ptr<blink::WebInputEvent> event) {
+    std::unique_ptr<InputEvent> event) {
   if (!event || !input_handler_)
     return;
 
   input_handler_->ForwardEventToPlatformUi(std::move(event));
 }
 
-std::unique_ptr<blink::WebMouseEvent> PlatformUiInputDelegate::MakeMouseEvent(
-    blink::WebInputEvent::Type type,
+std::unique_ptr<InputEvent> PlatformUiInputDelegate::MakeInputEvent(
+    InputEvent::Type type,
     const gfx::PointF& normalized_web_content_location,
-    base::TimeTicks timestamp) const {
+    base::TimeTicks time_stamp) const {
   gfx::Point location = CalculateLocation(normalized_web_content_location);
 
-  auto mouse_event = std::make_unique<blink::WebMouseEvent>(
-      type, blink::WebInputEvent::kNoModifiers, timestamp);
-  mouse_event->pointer_type = blink::WebPointerProperties::PointerType::kMouse;
-  mouse_event->button = blink::WebPointerProperties::Button::kLeft;
-  mouse_event->SetPositionInWidget(location.x(), location.y());
-  mouse_event->click_count = 1;
-  return mouse_event;
-}
-
-std::unique_ptr<blink::WebTouchEvent> PlatformUiInputDelegate::MakeTouchEvent(
-    blink::WebInputEvent::Type type,
-    const gfx::PointF& normalized_web_content_location,
-    base::TimeTicks timestamp) const {
-  gfx::Point location = CalculateLocation(normalized_web_content_location);
-  blink::WebInputEvent::Modifiers modifiers =
-      blink::WebInputEvent::kNoModifiers;
-
-  blink::WebTouchPoint::State touch_state =
-      blink::WebTouchPoint::kStateUndefined;
-  switch (type) {
-    case blink::WebInputEvent::kTouchStart:
-      touch_state = blink::WebTouchPoint::kStatePressed;
-      break;
-    case blink::WebInputEvent::kTouchEnd:
-      touch_state = blink::WebTouchPoint::kStateReleased;
-      break;
-    case blink::WebInputEvent::kTouchMove:
-      touch_state = blink::WebTouchPoint::kStateMoved;
-      break;
-    default:
-      NOTREACHED();
-  }
-
-  auto touch_event =
-      std::make_unique<blink::WebTouchEvent>(type, modifiers, timestamp);
-  touch_event->touches_length = 1;
-  touch_event->touches[0].state = touch_state;
-  touch_event->touches[0].SetPositionInWidget(location.x(), location.y());
-  return touch_event;
+  auto event = std::make_unique<InputEvent>(type);
+  event->set_time_stamp(time_stamp);
+  event->SetPositionInWidget(location.x(), location.y());
+  return event;
 }
 
 gfx::Point PlatformUiInputDelegate::CalculateLocation(
diff --git a/chrome/browser/vr/platform_ui_input_delegate.h b/chrome/browser/vr/platform_ui_input_delegate.h
index a2857f7..77e5d395 100644
--- a/chrome/browser/vr/platform_ui_input_delegate.h
+++ b/chrome/browser/vr/platform_ui_input_delegate.h
@@ -11,23 +11,17 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/macros.h"
+#include "chrome/browser/vr/input_event.h"
 #include "chrome/browser/vr/macros.h"
 #include "chrome/browser/vr/model/text_input_info.h"
 #include "chrome/browser/vr/text_edit_action.h"
 #include "chrome/browser/vr/vr_export.h"
-#include "third_party/blink/public/platform/web_input_event.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace base {
 class TimeTicks;
 }  // namespace base
 
-namespace blink {
-class WebGestureEvent;
-class WebMouseEvent;
-class WebTouchEvent;
-}  // namespace blink
-
 namespace gfx {
 class PointF;
 }  // namespace gfx
@@ -59,18 +53,8 @@
                                     base::TimeTicks timestamp);
   VIRTUAL_FOR_MOCKS void OnTouchMove(const gfx::PointF& normalized_hit_point,
                                      base::TimeTicks timestamp);
-  VIRTUAL_FOR_MOCKS void OnFlingCancel(
-      std::unique_ptr<blink::WebGestureEvent> gesture,
-      const gfx::PointF& normalized_hit_point);
-  VIRTUAL_FOR_MOCKS void OnScrollBegin(
-      std::unique_ptr<blink::WebGestureEvent> gesture,
-      const gfx::PointF& normalized_hit_point);
-  VIRTUAL_FOR_MOCKS void OnScrollUpdate(
-      std::unique_ptr<blink::WebGestureEvent> gesture,
-      const gfx::PointF& normalized_hit_point);
-  VIRTUAL_FOR_MOCKS void OnScrollEnd(
-      std::unique_ptr<blink::WebGestureEvent> gesture,
-      const gfx::PointF& normalized_hit_point);
+  VIRTUAL_FOR_MOCKS void OnInputEvent(std::unique_ptr<InputEvent> event,
+                                      const gfx::PointF& normalized_hit_point);
 
   void SetSize(int width, int height) { size_ = {width, height}; }
   void SetPlatformInputHandlerForTest(PlatformInputHandler* input_handler) {
@@ -78,20 +62,16 @@
   }
 
  protected:
-  virtual void SendGestureToTarget(std::unique_ptr<blink::WebInputEvent> event);
+  virtual void SendGestureToTarget(std::unique_ptr<InputEvent> event);
   PlatformInputHandler* input_handler() const { return input_handler_; }
 
  private:
   void UpdateGesture(const gfx::PointF& normalized_content_hit_point,
-                     blink::WebGestureEvent& gesture);
-  std::unique_ptr<blink::WebMouseEvent> MakeMouseEvent(
-      blink::WebInputEvent::Type type,
+                     InputEvent* gesture);
+  std::unique_ptr<InputEvent> MakeInputEvent(
+      InputEvent::Type type,
       const gfx::PointF& normalized_web_content_location,
-      base::TimeTicks timestamp) const;
-  std::unique_ptr<blink::WebTouchEvent> MakeTouchEvent(
-      blink::WebInputEvent::Type type,
-      const gfx::PointF& normalized_web_content_location,
-      base::TimeTicks timestamp) const;
+      base::TimeTicks time_stamp) const;
   gfx::Point CalculateLocation(
       const gfx::PointF& normalized_web_content_location) const;
 
diff --git a/chrome/browser/vr/platform_ui_input_delegate_unittest.cc b/chrome/browser/vr/platform_ui_input_delegate_unittest.cc
new file mode 100644
index 0000000..a10a4226
--- /dev/null
+++ b/chrome/browser/vr/platform_ui_input_delegate_unittest.cc
@@ -0,0 +1,90 @@
+// 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/platform_ui_input_delegate.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::AllOf;
+using ::testing::Property;
+using ::testing::Ref;
+
+namespace vr {
+
+class PlatformUiInputDelegateTest : public PlatformUiInputDelegate {
+ public:
+  MOCK_METHOD1(FwdSendGestureToTarget, void(const InputEvent& event));
+
+  void SendGestureToTarget(std::unique_ptr<InputEvent> event) override;
+};
+
+void PlatformUiInputDelegateTest::SendGestureToTarget(
+    std::unique_ptr<InputEvent> event) {
+  FwdSendGestureToTarget(*event);
+}
+
+TEST(PlatformUiInputDelegateTest, OnHoverEvents) {
+  PlatformUiInputDelegateTest delegate;
+  delegate.SetSize(40.0f, 30.0f);
+
+  EXPECT_CALL(delegate,
+              FwdSendGestureToTarget(
+                  AllOf(Property(&InputEvent::type, InputEvent::kHoverEnter),
+                        Property(&InputEvent::position_in_widget,
+                                 gfx::PointF(20.0f, 15.0f)))));
+  delegate.OnHoverEnter({0.5f, 0.5f}, base::TimeTicks());
+
+  EXPECT_CALL(
+      delegate,
+      FwdSendGestureToTarget(AllOf(
+          Property(&InputEvent::type, InputEvent::kHoverMove),
+          Property(&InputEvent::position_in_widget, gfx::PointF(4.0f, 6.0f)))));
+  delegate.OnHoverMove({0.1f, 0.2f}, base::TimeTicks());
+
+  EXPECT_CALL(delegate, FwdSendGestureToTarget(Property(
+                            &InputEvent::type, InputEvent::kHoverLeave)));
+  delegate.OnHoverLeave(base::TimeTicks());
+}
+
+TEST(PlatformUiInputDelegateTest, OnButtonEvents) {
+  PlatformUiInputDelegateTest delegate;
+  delegate.SetSize(40.0f, 30.0f);
+
+  EXPECT_CALL(
+      delegate,
+      FwdSendGestureToTarget(AllOf(
+          Property(&InputEvent::type, InputEvent::kButtonDown),
+          Property(&InputEvent::position_in_widget, gfx::PointF(4.0f, 3.0f)))));
+  delegate.OnButtonDown({0.1f, 0.1f}, base::TimeTicks());
+
+  EXPECT_CALL(
+      delegate,
+      FwdSendGestureToTarget(AllOf(
+          Property(&InputEvent::type, InputEvent::kMove),
+          Property(&InputEvent::position_in_widget, gfx::PointF(8.0f, 3.0f)))));
+  delegate.OnTouchMove({0.2f, 0.1f}, base::TimeTicks());
+
+  EXPECT_CALL(
+      delegate,
+      FwdSendGestureToTarget(AllOf(
+          Property(&InputEvent::type, InputEvent::kButtonUp),
+          Property(&InputEvent::position_in_widget, gfx::PointF(0.0f, 3.0f)))));
+  delegate.OnButtonUp({0.0f, 0.1f}, base::TimeTicks());
+}
+
+TEST(PlatformUiInputDelegateTest, OnInputEvent) {
+  PlatformUiInputDelegateTest delegate;
+  delegate.SetSize(40.0f, 30.0f);
+
+  auto event = std::make_unique<InputEvent>(InputEvent::kTypeUndefined);
+  EXPECT_CALL(delegate,
+              FwdSendGestureToTarget(
+                  AllOf(Ref(*event), Property(&InputEvent::position_in_widget,
+                                              gfx::PointF(4.0f, 3.0f)))));
+  delegate.OnInputEvent(std::move(event), {0.1f, 0.1f});
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/test/mock_content_input_delegate.cc b/chrome/browser/vr/test/mock_content_input_delegate.cc
index 2d88332..07cf6e4 100644
--- a/chrome/browser/vr/test/mock_content_input_delegate.cc
+++ b/chrome/browser/vr/test/mock_content_input_delegate.cc
@@ -4,9 +4,6 @@
 
 #include "chrome/browser/vr/test/mock_content_input_delegate.h"
 
-#include "third_party/blink/public/platform/web_gesture_event.h"
-#include "ui/gfx/geometry/point_f.h"
-
 namespace vr {
 
 MockContentInputDelegate::MockContentInputDelegate()
diff --git a/chrome/browser/vr/test/mock_content_input_delegate.h b/chrome/browser/vr/test/mock_content_input_delegate.h
index d644b60..dfbed93 100644
--- a/chrome/browser/vr/test/mock_content_input_delegate.h
+++ b/chrome/browser/vr/test/mock_content_input_delegate.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "chrome/browser/vr/content_input_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 
 namespace vr {
 
@@ -33,34 +32,13 @@
 
   // As move-only parameters aren't supported by mock methods, we will override
   // the functions explicitly and fwd the calls to the mocked functions.
-  MOCK_METHOD2(FwdContentFlingCancel,
-               void(std::unique_ptr<blink::WebGestureEvent>& gesture,
-                    const gfx::PointF& normalized_hit_point));
-  MOCK_METHOD2(FwdContentScrollBegin,
-               void(std::unique_ptr<blink::WebGestureEvent>& gesture,
-                    const gfx::PointF& normalized_hit_point));
-  MOCK_METHOD2(FwdContentScrollUpdate,
-               void(std::unique_ptr<blink::WebGestureEvent>& gesture,
-                    const gfx::PointF& normalized_hit_point));
-  MOCK_METHOD2(FwdContentScrollEnd,
-               void(std::unique_ptr<blink::WebGestureEvent>& gesture,
+  MOCK_METHOD2(FwdContentInputEvent,
+               void(std::unique_ptr<InputEvent>& gesture,
                     const gfx::PointF& normalized_hit_point));
 
-  void OnFlingCancel(std::unique_ptr<blink::WebGestureEvent> gesture,
-                     const gfx::PointF& normalized_hit_point) override {
-    FwdContentFlingCancel(gesture, normalized_hit_point);
-  }
-  void OnScrollBegin(std::unique_ptr<blink::WebGestureEvent> gesture,
-                     const gfx::PointF& normalized_hit_point) override {
-    FwdContentScrollBegin(gesture, normalized_hit_point);
-  }
-  void OnScrollUpdate(std::unique_ptr<blink::WebGestureEvent> gesture,
-                      const gfx::PointF& normalized_hit_point) override {
-    FwdContentScrollUpdate(gesture, normalized_hit_point);
-  }
-  void OnScrollEnd(std::unique_ptr<blink::WebGestureEvent> gesture,
-                   const gfx::PointF& normalized_hit_point) override {
-    FwdContentScrollEnd(gesture, normalized_hit_point);
+  void OnInputEvent(std::unique_ptr<InputEvent> gesture,
+                    const gfx::PointF& normalized_hit_point) override {
+    FwdContentInputEvent(gesture, normalized_hit_point);
   }
 };
 
diff --git a/chrome/browser/vr/test/ui_pixel_test.cc b/chrome/browser/vr/test/ui_pixel_test.cc
index 536b09c..3a395ab 100644
--- a/chrome/browser/vr/test/ui_pixel_test.cc
+++ b/chrome/browser/vr/test/ui_pixel_test.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/vr/ui_input_manager.h"
 #include "chrome/browser/vr/ui_renderer.h"
 #include "chrome/browser/vr/ui_scene.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 #include "third_party/skia/include/core/SkImageEncoder.h"
 #include "third_party/skia/include/core/SkStream.h"
 #include "ui/gl/gl_bindings.h"
@@ -91,12 +90,12 @@
                                          frame_buffer_size_.height()};
   render_info.right_eye_model.viewport = {0, 0, 0, 0};
 
-  GestureList gesture_list;
+  InputEventList input_event_list;
   ReticleModel reticle_model;
   EXPECT_TRUE(
       ui_->scene()->OnBeginFrame(base::TimeTicks(), render_info.head_pose));
   ui_->input_manager()->HandleInput(MsToTicks(1), render_info, controller_model,
-                                    &reticle_model, &gesture_list);
+                                    &reticle_model, &input_event_list);
   ui_->OnControllerUpdated(controller_model, reticle_model);
   ui_->ui_renderer()->Draw(render_info);
 
diff --git a/chrome/browser/vr/test/ui_test.cc b/chrome/browser/vr/test/ui_test.cc
index b5e450f..a46beca 100644
--- a/chrome/browser/vr/test/ui_test.cc
+++ b/chrome/browser/vr/test/ui_test.cc
@@ -12,7 +12,6 @@
 #include "chrome/browser/vr/ui_renderer.h"
 #include "chrome/browser/vr/ui_scene.h"
 #include "chrome/browser/vr/ui_scene_creator.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 #include "ui/gfx/geometry/vector3d_f.h"
 
 namespace vr {
@@ -251,7 +250,7 @@
 
   RenderInfo render_info;
   ReticleModel reticle_model;
-  GestureList gesture_list;
+  InputEventList input_event_list;
   ControllerModel controller_model;
   controller_model.laser_direction = direction;
   controller_model.laser_origin = origin;
@@ -259,13 +258,13 @@
   controller_model.touchpad_button_state = UiInputManager::ButtonState::DOWN;
   ui_->input_manager()->HandleInput(current_time_, render_info,
                                     controller_model, &reticle_model,
-                                    &gesture_list);
+                                    &input_event_list);
   OnBeginFrame();
 
   controller_model.touchpad_button_state = UiInputManager::ButtonState::UP;
   ui_->input_manager()->HandleInput(current_time_, render_info,
                                     controller_model, &reticle_model,
-                                    &gesture_list);
+                                    &input_event_list);
   OnBeginFrame();
 }
 
diff --git a/chrome/browser/vr/testapp/BUILD.gn b/chrome/browser/vr/testapp/BUILD.gn
index 00b222e..53673df 100644
--- a/chrome/browser/vr/testapp/BUILD.gn
+++ b/chrome/browser/vr/testapp/BUILD.gn
@@ -24,14 +24,16 @@
   deps = [
     ":assets_component_version_header",
     ":vr_testapp_pak",
-    "//chrome/browser/vr:vr_gl_test_support",
-    "//chrome/browser/vr:vr_test_support",
+    "//chrome/browser/vr:vr_common",
     "//components:components_tests_pak",
+    "//components/security_state/core",
+    "//components/toolbar:vector_icons",
     "//components/tracing:startup_tracing",
     "//ui/display/types",
     "//ui/events",
     "//ui/events:dom_keycode_converter",
     "//ui/events/ozone:events_ozone_layout",
+    "//ui/gl/init",
     "//ui/ozone",
     "//ui/platform_window",
   ]
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index 49745f6..917d6a0d 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -33,7 +33,6 @@
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/security_state/core/security_state.h"
 #include "components/toolbar/vector_icons.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -80,19 +79,19 @@
       out_image->get());
 }
 
-GestureList CreateScrollGestureEventList(blink::WebGestureEvent::Type type) {
-  auto gesture = std::make_unique<blink::WebGestureEvent>();
-  gesture->SetType(type);
-  GestureList list;
+InputEventList CreateScrollGestureEventList(InputEvent::Type type) {
+  std::unique_ptr<InputEvent> gesture = std::make_unique<InputEvent>(type);
+  InputEventList list;
   list.push_back(std::move(gesture));
   return list;
 }
 
-GestureList CreateScrollGestureEventList(blink::WebGestureEvent::Type type,
-                                         const gfx::Vector2dF& delta) {
+InputEventList CreateScrollGestureEventList(InputEvent::Type type,
+                                            const gfx::Vector2dF& delta) {
   auto list = CreateScrollGestureEventList(type);
-  list.front()->data.scroll_update.delta_x = delta.x();
-  list.front()->data.scroll_update.delta_y = delta.y();
+  InputEvent* event = static_cast<InputEvent*>(list.front().get());
+  event->scroll_data.delta_x = delta.x();
+  event->scroll_data.delta_y = delta.y();
   return list;
 }
 
@@ -302,8 +301,8 @@
           touchpad_touch_position_.y() + kTouchpadPositionDelta * direction,
           0.0f, 1.0f));
     } else {
-      gesture_lists_.push(CreateScrollGestureEventList(
-          blink::WebGestureEvent::kGestureScrollBegin));
+      input_event_lists_.push(
+          CreateScrollGestureEventList(InputEvent::kScrollBegin));
 
       auto offset = gfx::Vector2dF(event->AsMouseWheelEvent()->offset());
       if (event->IsShiftDown()) {
@@ -312,11 +311,11 @@
       } else {
         offset.Scale(kVerticalScrollScaleFactor);
       }
-      gesture_lists_.push(CreateScrollGestureEventList(
-          blink::WebGestureEvent::kGestureScrollUpdate, offset));
+      input_event_lists_.push(
+          CreateScrollGestureEventList(InputEvent::kScrollUpdate, offset));
 
-      gesture_lists_.push(CreateScrollGestureEventList(
-          blink::WebGestureEvent::kGestureScrollEnd));
+      input_event_lists_.push(
+          CreateScrollGestureEventList(InputEvent::kScrollEnd));
     }
     return;
   }
@@ -420,13 +419,14 @@
   RotateToward(controller_model.laser_direction, &controller_model.transform);
 
   // Hit testing is done in terms of this synthesized controller model.
-  if (gesture_lists_.empty()) {
-    gesture_lists_.push(GestureList());
+  if (input_event_lists_.empty()) {
+    input_event_lists_.push(InputEventList());
   }
   ReticleModel reticle_model;
   ui_->input_manager()->HandleInput(current_time, render_info, controller_model,
-                                    &reticle_model, &gesture_lists_.front());
-  gesture_lists_.pop();
+                                    &reticle_model,
+                                    &input_event_lists_.front());
+  input_event_lists_.pop();
 
   // Now that we have accurate hit information, we use this to construct a
   // controller model for display.
diff --git a/chrome/browser/vr/testapp/vr_test_context.h b/chrome/browser/vr/testapp/vr_test_context.h
index b1174f17..79059137 100644
--- a/chrome/browser/vr/testapp/vr_test_context.h
+++ b/chrome/browser/vr/testapp/vr_test_context.h
@@ -125,7 +125,7 @@
 
   PlatformController::Handedness handedness_ = PlatformController::kRightHanded;
 
-  std::queue<GestureList> gesture_lists_;
+  std::queue<InputEventList> input_event_lists_;
 
   DISALLOW_COPY_AND_ASSIGN(VrTestContext);
 };
diff --git a/chrome/browser/vr/ui_input_manager.cc b/chrome/browser/vr/ui_input_manager.cc
index dcaca409..fd57134 100644
--- a/chrome/browser/vr/ui_input_manager.cc
+++ b/chrome/browser/vr/ui_input_manager.cc
@@ -8,15 +8,14 @@
 
 #include "base/containers/adapters.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "chrome/browser/vr/elements/ui_element.h"
+#include "chrome/browser/vr/input_event.h"
 #include "chrome/browser/vr/model/controller_model.h"
 #include "chrome/browser/vr/model/reticle_model.h"
 #include "chrome/browser/vr/model/text_input_info.h"
 #include "chrome/browser/vr/ui_renderer.h"
 #include "chrome/browser/vr/ui_scene.h"
-// TODO(tiborg): Remove include once we use a generic type to pass scroll/fling
-// gestures.
-#include "third_party/blink/public/platform/web_gesture_event.h"
 
 namespace vr {
 
@@ -42,19 +41,14 @@
   return o.x() > -1.0f && o.x() < 1.0f && o.y() > -1.0f && o.y() < 1.0f;
 }
 
-bool IsScrollEvent(const GestureList& list) {
+bool IsScrollOrFling(const InputEventList& list) {
   if (list.empty()) {
     return false;
   }
   // We assume that we only need to consider the first gesture in the list.
-  blink::WebInputEvent::Type type = list.front()->GetType();
-  if (type == blink::WebInputEvent::kGestureScrollBegin ||
-      type == blink::WebInputEvent::kGestureScrollEnd ||
-      type == blink::WebInputEvent::kGestureScrollUpdate ||
-      type == blink::WebInputEvent::kGestureFlingCancel) {
-    return true;
-  }
-  return false;
+  auto type = list.front()->type();
+  return InputEvent::IsScrollEventType(type) ||
+         type == InputEvent::kFlingCancel;
 }
 
 void HitTestElements(UiScene* scene,
@@ -91,13 +85,13 @@
                                  const RenderInfo& render_info,
                                  const ControllerModel& controller_model,
                                  ReticleModel* reticle_model,
-                                 GestureList* gesture_list) {
+                                 InputEventList* input_event_list) {
   UpdateQuiescenceState(current_time, controller_model);
   UpdateControllerFocusState(current_time, render_info, controller_model);
   reticle_model->target_element_id = 0;
   reticle_model->target_local_point = kInvalidTargetPoint;
   UiElement* target_element =
-      GetTargetElement(controller_model, reticle_model, *gesture_list);
+      GetTargetElement(controller_model, reticle_model, *input_event_list);
 
   auto element_local_point = reticle_model->target_local_point;
   if (input_capture_element_id_)
@@ -105,8 +99,8 @@
         GetCapturedElementHitPoint(reticle_model->target_point);
 
   // Sending end and cancel events.
-  SendFlingCancel(gesture_list, element_local_point);
-  SendScrollEnd(gesture_list, element_local_point,
+  SendFlingCancel(input_event_list, element_local_point);
+  SendScrollEnd(input_event_list, element_local_point,
                 controller_model.touchpad_button_state);
   SendButtonUp(element_local_point, controller_model.touchpad_button_state,
                controller_model.last_button_timestamp);
@@ -114,7 +108,7 @@
 
   // Sending update events.
   if (in_scroll_) {
-    SendScrollUpdate(gesture_list, element_local_point);
+    SendScrollUpdate(input_event_list, element_local_point);
   } else if (in_click_) {
     SendTouchMove(element_local_point,
                   controller_model.last_orientation_timestamp);
@@ -126,7 +120,7 @@
   // Sending begin events.
   SendHoverEnter(target_element, reticle_model->target_local_point,
                  controller_model.last_orientation_timestamp);
-  SendScrollBegin(target_element, gesture_list, element_local_point);
+  SendScrollBegin(target_element, input_event_list, element_local_point);
   SendButtonDown(target_element, reticle_model->target_local_point,
                  controller_model.touchpad_button_state,
                  controller_model.last_button_timestamp);
@@ -143,13 +137,13 @@
   }
 }
 
-void UiInputManager::SendFlingCancel(GestureList* gesture_list,
+void UiInputManager::SendFlingCancel(InputEventList* input_event_list,
                                      const gfx::PointF& target_point) {
   if (!fling_target_id_) {
     return;
   }
-  if (gesture_list->empty() || (gesture_list->front()->GetType() !=
-                                blink::WebInputEvent::kGestureFlingCancel)) {
+  if (input_event_list->empty() ||
+      (input_event_list->front()->type() != InputEvent::kFlingCancel)) {
     return;
   }
 
@@ -157,13 +151,13 @@
   UiElement* element = scene_->GetUiElementById(fling_target_id_);
   if (element) {
     DCHECK(element->scrollable());
-    element->OnFlingCancel(std::move(gesture_list->front()), target_point);
+    element->OnFlingCancel(std::move(input_event_list->front()), target_point);
   }
-  gesture_list->erase(gesture_list->begin());
+  input_event_list->erase(input_event_list->begin());
   fling_target_id_ = 0;
 }
 
-void UiInputManager::SendScrollEnd(GestureList* gesture_list,
+void UiInputManager::SendScrollEnd(InputEventList* input_event_list,
                                    const gfx::PointF& target_point,
                                    ButtonState button_state) {
   if (!in_scroll_) {
@@ -174,53 +168,52 @@
 
   if (previous_button_state_ != button_state &&
       button_state == ButtonState::DOWN) {
-    DCHECK_GT(gesture_list->size(), 0LU);
-    DCHECK_EQ(gesture_list->front()->GetType(),
-              blink::WebInputEvent::kGestureScrollEnd);
+    DCHECK_GT(input_event_list->size(), 0LU);
+    DCHECK_EQ(input_event_list->front()->type(), InputEvent::kScrollEnd);
   }
   DCHECK(!element || element->scrollable());
-  if (gesture_list->empty() || gesture_list->front()->GetType() !=
-                                   blink::WebInputEvent::kGestureScrollEnd) {
+  if (input_event_list->empty() ||
+      input_event_list->front()->type() != InputEvent::kScrollEnd) {
     return;
   }
-  DCHECK_LE(gesture_list->size(), 1LU);
+  DCHECK_LE(input_event_list->size(), 1LU);
   fling_target_id_ = input_capture_element_id_;
-  element->OnScrollEnd(std::move(gesture_list->front()), target_point);
-  gesture_list->erase(gesture_list->begin());
+  element->OnScrollEnd(std::move(input_event_list->front()), target_point);
+  input_event_list->erase(input_event_list->begin());
   input_capture_element_id_ = 0;
   in_scroll_ = false;
 }
 
 void UiInputManager::SendScrollBegin(UiElement* target,
-                                     GestureList* gesture_list,
+                                     InputEventList* input_event_list,
                                      const gfx::PointF& target_point) {
   if (in_scroll_ || !target || !target->scrollable())
     return;
 
-  if (gesture_list->empty() || (gesture_list->front()->GetType() !=
-                                blink::WebInputEvent::kGestureScrollBegin)) {
+  if (input_event_list->empty() ||
+      input_event_list->front()->type() != InputEvent::kScrollBegin) {
     return;
   }
   input_capture_element_id_ = target->id();
   in_scroll_ = true;
-  target->OnScrollBegin(std::move(gesture_list->front()), target_point);
-  gesture_list->erase(gesture_list->begin());
+  target->OnScrollBegin(std::move(input_event_list->front()), target_point);
+  input_event_list->erase(input_event_list->begin());
 }
 
-void UiInputManager::SendScrollUpdate(GestureList* gesture_list,
+void UiInputManager::SendScrollUpdate(InputEventList* input_event_list,
                                       const gfx::PointF& target_point) {
   DCHECK(input_capture_element_id_);
-  if (gesture_list->empty() || (gesture_list->front()->GetType() !=
-                                blink::WebInputEvent::kGestureScrollUpdate)) {
+  if (input_event_list->empty() ||
+      (input_event_list->front()->type() != InputEvent::kScrollUpdate)) {
     return;
   }
   // Scrolling currently only supported on content window.
   UiElement* element = scene_->GetUiElementById(input_capture_element_id_);
   if (element) {
     DCHECK(element->scrollable());
-    element->OnScrollUpdate(std::move(gesture_list->front()), target_point);
+    element->OnScrollUpdate(std::move(input_event_list->front()), target_point);
   }
-  gesture_list->erase(gesture_list->begin());
+  input_event_list->erase(input_event_list->begin());
 }
 
 void UiInputManager::SendHoverLeave(UiElement* current_target,
@@ -302,7 +295,7 @@
 UiElement* UiInputManager::GetTargetElement(
     const ControllerModel& controller_model,
     ReticleModel* reticle_model,
-    const GestureList& gesture_list) const {
+    const InputEventList& input_event_list) const {
   // If we place the reticle based on elements intersecting the controller beam,
   // we can end up with the reticle hiding behind elements, or jumping laterally
   // in the field of view. This is physically correct, but hard to use. For
@@ -347,7 +340,7 @@
   UiElement* target_element =
       scene_->GetUiElementById(reticle_model->target_element_id);
   if (target_element) {
-    if (IsScrollEvent(gesture_list) && !input_capture_element_id_) {
+    if (IsScrollOrFling(input_event_list) && !input_capture_element_id_) {
       DCHECK(!in_scroll_ && !in_click_);
       UiElement* ancestor = target_element;
       while (!ancestor->scrollable() && ancestor->parent())
diff --git a/chrome/browser/vr/ui_input_manager.h b/chrome/browser/vr/ui_input_manager.h
index ea214e4..1043ab30 100644
--- a/chrome/browser/vr/ui_input_manager.h
+++ b/chrome/browser/vr/ui_input_manager.h
@@ -15,20 +15,17 @@
 #include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/gfx/transform.h"
 
-namespace blink {
-class WebGestureEvent;
-}
-
 namespace vr {
 
 class UiScene;
 class UiElement;
+class InputEvent;
 struct ControllerModel;
 struct RenderInfo;
 struct ReticleModel;
 struct EditedText;
 
-using GestureList = std::vector<std::unique_ptr<blink::WebGestureEvent>>;
+using InputEventList = std::vector<std::unique_ptr<InputEvent>>;
 
 // Based on controller input finds the hit UI element and determines the
 // interaction with UI elements and the web contents.
@@ -50,12 +47,11 @@
 
   explicit UiInputManager(UiScene* scene);
   ~UiInputManager();
-  // TODO(tiborg): Use generic gesture type instead of blink::WebGestureEvent.
   void HandleInput(base::TimeTicks current_time,
                    const RenderInfo& render_info,
                    const ControllerModel& controller_model,
                    ReticleModel* reticle_model,
-                   GestureList* gesture_list);
+                   InputEventList* input_event_list);
 
   void OnPause();
 
@@ -76,15 +72,15 @@
   }
 
  private:
-  void SendFlingCancel(GestureList* gesture_list,
+  void SendFlingCancel(InputEventList* input_event_list,
                        const gfx::PointF& target_point);
-  void SendScrollEnd(GestureList* gesture_list,
+  void SendScrollEnd(InputEventList* input_event_list,
                      const gfx::PointF& target_point,
                      ButtonState button_state);
   void SendScrollBegin(UiElement* target,
-                       GestureList* gesture_list,
+                       InputEventList* input_event_list,
                        const gfx::PointF& target_point);
-  void SendScrollUpdate(GestureList* gesture_list,
+  void SendScrollUpdate(InputEventList* input_event_list,
                         const gfx::PointF& target_point);
 
   void SendHoverLeave(UiElement* current_target, base::TimeTicks timestamp);
@@ -107,7 +103,7 @@
 
   UiElement* GetTargetElement(const ControllerModel& controller_model,
                               ReticleModel* reticle_model,
-                              const GestureList& gesture_list) const;
+                              const InputEventList& input_event_list) const;
   void UpdateQuiescenceState(base::TimeTicks current_time,
                              const ControllerModel& controller_model);
   void UpdateControllerFocusState(base::TimeTicks current_time,
diff --git a/chrome/browser/vr/ui_input_manager_unittest.cc b/chrome/browser/vr/ui_input_manager_unittest.cc
index f5b7287..ad61c33 100644
--- a/chrome/browser/vr/ui_input_manager_unittest.cc
+++ b/chrome/browser/vr/ui_input_manager_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/vr/elements/invisible_hit_target.h"
 #include "chrome/browser/vr/elements/rect.h"
 #include "chrome/browser/vr/elements/ui_element.h"
+#include "chrome/browser/vr/input_event.h"
 #include "chrome/browser/vr/model/model.h"
 #include "chrome/browser/vr/test/animation_utils.h"
 #include "chrome/browser/vr/test/constants.h"
@@ -24,7 +25,6 @@
 #include "chrome/browser/vr/ui_scene_creator.h"
 #include "chrome/browser/vr/ui_unsupported_mode.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 
 using ::testing::_;
 using ::testing::InSequence;
@@ -57,14 +57,11 @@
   MOCK_METHOD2(OnTouchMove,
                void(const gfx::PointF& position, base::TimeTicks timestamp));
   MOCK_METHOD2(OnScrollBegin,
-               void(std::unique_ptr<blink::WebGestureEvent>,
-                    const gfx::PointF&));
+               void(std::unique_ptr<InputEvent>, const gfx::PointF&));
   MOCK_METHOD2(OnScrollUpdate,
-               void(std::unique_ptr<blink::WebGestureEvent>,
-                    const gfx::PointF&));
+               void(std::unique_ptr<InputEvent>, const gfx::PointF&));
   MOCK_METHOD2(OnScrollEnd,
-               void(std::unique_ptr<blink::WebGestureEvent>,
-                    const gfx::PointF&));
+               void(std::unique_ptr<InputEvent>, const gfx::PointF&));
   MOCK_METHOD0(MockedOnScrollBegin, void());
   MOCK_METHOD1(OnFocusChanged, void(bool));
   MOCK_METHOD1(OnInputEdited, void(const EditedText&));
@@ -134,9 +131,8 @@
                                 &reticle_model_, &gesture_list_);
   }
 
-  void AddGesture(blink::WebGestureEvent::Type type) {
-    auto gesture = std::make_unique<blink::WebGestureEvent>();
-    gesture->SetType(type);
+  void AddGesture(InputEvent::Type type) {
+    auto gesture = std::make_unique<InputEvent>(type);
     gesture_list_.push_back(std::move(gesture));
   }
 
@@ -145,7 +141,7 @@
   std::unique_ptr<UiInputManager> input_manager_;
   ReticleModel reticle_model_;
   ControllerModel controller_model_;
-  GestureList gesture_list_;
+  InputEventList gesture_list_;
   InSequence inSequence;
 };
 
@@ -268,15 +264,15 @@
   controller_model.laser_origin = {0, 0, 0};
   controller_model.touchpad_button_state = kUp;
   ReticleModel reticle_model;
-  GestureList gesture_list;
+  InputEventList input_event_list;
 
   input_manager_->HandleInput(MsToTicks(1), RenderInfo(), controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
   EXPECT_EQ(0, reticle_model.target_element_id);
 
   controller_model.laser_direction = kForwardVector;
   input_manager_->HandleInput(MsToTicks(1), RenderInfo(), controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
   EXPECT_EQ(p_element->id(), reticle_model.target_element_id);
   EXPECT_NEAR(-1.0, reticle_model.target_point.z(), kEpsilon);
 }
@@ -377,25 +373,25 @@
   p_back_element->set_scrollable(true);
 
   // Scroll on an element.
-  AddGesture(blink::WebGestureEvent::kGestureScrollBegin);
+  AddGesture(InputEvent::kScrollBegin);
   EXPECT_CALL(*p_front_element, OnHoverEnter(_, _));
   EXPECT_CALL(*p_front_element, OnScrollBegin(_, _));
   HandleInput(kForwardVector, kUp);
   EXPECT_TRUE(gesture_list_.empty());
-  AddGesture(blink::WebGestureEvent::kGestureScrollUpdate);
+  AddGesture(InputEvent::kScrollUpdate);
   EXPECT_CALL(*p_front_element, OnScrollUpdate(_, _));
   HandleInput(kForwardVector, kUp);
   EXPECT_TRUE(gesture_list_.empty());
 
   // Move away.
-  AddGesture(blink::WebGestureEvent::kGestureScrollUpdate);
+  AddGesture(InputEvent::kScrollUpdate);
   EXPECT_CALL(*p_front_element, OnHoverLeave(_));
   EXPECT_CALL(*p_front_element, OnScrollUpdate(_, _));
   HandleInput(kBackwardVector, kUp);
   EXPECT_TRUE(gesture_list_.empty());
 
   // Release scroll.
-  AddGesture(blink::WebGestureEvent::kGestureScrollEnd);
+  AddGesture(InputEvent::kScrollEnd);
   EXPECT_CALL(*p_front_element, OnScrollEnd(_, _));
   EXPECT_CALL(*p_back_element, OnHoverEnter(_, _));
   HandleInput(kBackwardVector, kUp);
@@ -403,7 +399,7 @@
 
   // Start scrolling on a new element.
   EXPECT_CALL(*p_back_element, OnHoverMove(_, _));
-  AddGesture(blink::WebGestureEvent::kGestureScrollBegin);
+  AddGesture(InputEvent::kScrollBegin);
   EXPECT_CALL(*p_back_element, OnScrollBegin(_, _));
   HandleInput(kBackwardVector, kUp);
   EXPECT_TRUE(gesture_list_.empty());
@@ -421,7 +417,7 @@
   child->set_focusable(true);
   p_element->AddChild(std::move(child));
 
-  AddGesture(blink::WebGestureEvent::kGestureScrollBegin);
+  AddGesture(InputEvent::kScrollBegin);
   EXPECT_CALL(*p_element, OnHoverEnter(_, _));
   EXPECT_CALL(*p_element, OnScrollBegin(_, _));
   EXPECT_CALL(*p_child, OnScrollBegin(_, _)).Times(0);
@@ -508,9 +504,9 @@
   controller_model.laser_origin = origin;
   controller_model.touchpad_button_state = UiInputManager::ButtonState::DOWN;
   ReticleModel reticle_model;
-  GestureList gesture_list;
+  InputEventList input_event_list;
   input_manager_->HandleInput(MsToTicks(1), RenderInfo(), controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
 
   // We should have hit the content quad if our math was correct.
   ASSERT_NE(0, reticle_model.target_element_id);
@@ -522,7 +518,7 @@
   EXPECT_CALL(*content_input_delegate_, OnHoverMove(_, _)).Times(0);
 
   input_manager_->HandleInput(MsToTicks(1), RenderInfo(), controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
 }
 
 TEST_F(UiInputManagerContentTest, AudioPermissionPromptHitTesting) {
@@ -539,9 +535,9 @@
   controller_model.laser_origin = origin;
   controller_model.touchpad_button_state = UiInputManager::ButtonState::DOWN;
   ReticleModel reticle_model;
-  GestureList gesture_list;
+  InputEventList input_event_list;
   input_manager_->HandleInput(MsToTicks(1), RenderInfo(), controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
 
   // Even if the reticle is over the URL bar, the backplane should be in front
   // and should be hit.
@@ -565,9 +561,9 @@
   controller_model.laser_origin = origin;
   controller_model.touchpad_button_state = UiInputManager::ButtonState::DOWN;
   ReticleModel reticle_model;
-  GestureList gesture_list;
+  InputEventList input_event_list;
   input_manager_->HandleInput(MsToTicks(1), RenderInfo(), controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
 
   // We should have hit the content quad if our math was correct.
   ASSERT_NE(0, reticle_model.target_element_id);
@@ -578,7 +574,7 @@
   OnBeginFrame();
 
   input_manager_->HandleInput(MsToTicks(1), RenderInfo(), controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
 
   // We should have hit the content quad even though, geometrically, it stacks
   // behind the backplane.
@@ -598,14 +594,14 @@
       controller_center.x(), controller_center.y(), controller_center.z());
   controller_model.laser_origin = controller_center;
   ReticleModel reticle_model;
-  GestureList gesture_list;
+  InputEventList input_event_list;
   RenderInfo render_info = CreateRenderInfo();
 
   // The controller is initially not in the viewport.
   EXPECT_FALSE(input_manager_->controller_resting_in_viewport());
 
   input_manager_->HandleInput(MsToTicks(1), render_info, controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
   ui_->OnControllerUpdated(controller_model, reticle_model);
   scene_->OnBeginFrame(base::TimeTicks(), head_pose_);
 
@@ -614,7 +610,7 @@
   EXPECT_FALSE(input_manager_->controller_resting_in_viewport());
 
   input_manager_->HandleInput(MsToTicks(50000), render_info, controller_model,
-                              &reticle_model, &gesture_list);
+                              &reticle_model, &input_event_list);
   ui_->OnControllerUpdated(controller_model, reticle_model);
   scene_->OnBeginFrame(base::TimeTicks(), head_pose_);
 
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc
index be436ce..d3ee3c7 100644
--- a/chrome/browser/vr/ui_unittest.cc
+++ b/chrome/browser/vr/ui_unittest.cc
@@ -32,7 +32,6 @@
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/web_gesture_event.h"
 
 namespace vr {
 
diff --git a/chrome/chrome_cleaner/constants/BUILD.gn b/chrome/chrome_cleaner/constants/BUILD.gn
index f582818a..cbd10bf 100644
--- a/chrome/chrome_cleaner/constants/BUILD.gn
+++ b/chrome/chrome_cleaner/constants/BUILD.gn
@@ -3,6 +3,45 @@
 # found in the LICENSE file.
 
 import("//build/config/chrome_build.gni")
+import("//build/util/process_version.gni")
+
+declare_args() {
+  reporter_branding_path = "REPORTER_BRANDING"
+  cleaner_branding_path = "CLEANER_BRANDING"
+  version_path = "VERSION"
+  lastchange_path = "//build/util/LASTCHANGE"
+}
+
+process_version("version_header") {
+  sources = [
+    cleaner_branding_path,
+    lastchange_path,
+    version_path,
+  ]
+
+  template_file = "version.h.in"
+  output = "$target_gen_dir/version.h"
+}
+
+process_version("chrome_cleanup_tool_branding_header") {
+  sources = [
+    cleaner_branding_path,
+  ]
+
+  template_file = "branding.h.in"
+
+  output = "$target_gen_dir/chrome_cleanup_tool_branding.h"
+}
+
+process_version("software_reporter_tool_branding_header") {
+  sources = [
+    reporter_branding_path,
+  ]
+
+  template_file = "branding.h.in"
+
+  output = "$target_gen_dir/software_reporter_tool_branding.h"
+}
 
 source_set("common_strings") {
   sources = [
diff --git a/chrome/chrome_cleaner/constants/CLEANER_BRANDING b/chrome/chrome_cleaner/constants/CLEANER_BRANDING
new file mode 100644
index 0000000..be44837
--- /dev/null
+++ b/chrome/chrome_cleaner/constants/CLEANER_BRANDING
@@ -0,0 +1,7 @@
+COMPANY_FULLNAME=The Chromium Authors
+COMPANY_SHORTNAME=The Chromium Authors
+PRODUCT_FULLNAME=Chrome Cleanup Tool
+PRODUCT_SHORTNAME=Chrome Cleanup Tool
+PRODUCT_INSTALLER_FULLNAME=Chrome Cleanup Tool Installer
+PRODUCT_INSTALLER_SHORTNAME=Chrome Cleanup Tool Installer
+COPYRIGHT=Copyright 2015 Google Inc. All Rights Reserved.
diff --git a/chrome/chrome_cleaner/constants/REPORTER_BRANDING b/chrome/chrome_cleaner/constants/REPORTER_BRANDING
new file mode 100644
index 0000000..ce00d89f
--- /dev/null
+++ b/chrome/chrome_cleaner/constants/REPORTER_BRANDING
@@ -0,0 +1,7 @@
+COMPANY_FULLNAME=The Chromium Authors
+COMPANY_SHORTNAME=The Chromium Authors
+PRODUCT_FULLNAME=Software Reporter Tool
+PRODUCT_SHORTNAME=Software Reporter Tool
+PRODUCT_INSTALLER_FULLNAME=Software Reporter Tool Installer
+PRODUCT_INSTALLER_SHORTNAME=Software Reporter Tool Installer
+COPYRIGHT=Copyright 2015 Google Inc. All Rights Reserved.
diff --git a/chrome/chrome_cleaner/constants/VERSION b/chrome/chrome_cleaner/constants/VERSION
new file mode 100644
index 0000000..3895a61
--- /dev/null
+++ b/chrome/chrome_cleaner/constants/VERSION
@@ -0,0 +1,4 @@
+MAJOR=0
+MINOR=0
+BUILD=0
+PATCH=0
diff --git a/chrome/chrome_cleaner/constants/branding.h.in b/chrome/chrome_cleaner/constants/branding.h.in
new file mode 100644
index 0000000..b68df2b
--- /dev/null
+++ b/chrome/chrome_cleaner/constants/branding.h.in
@@ -0,0 +1,9 @@
+// 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.
+
+// chrome_cleanup_tool_branding.h and software_reporter_tool_branding.h are
+// generated from branding.h.in. Edit the source!
+
+#define PRODUCT_FULLNAME_STRING L"@PRODUCT_FULLNAME@"
+#define PRODUCT_SHORTNAME_STRING L"@PRODUCT_SHORTNAME@"
diff --git a/chrome/chrome_cleaner/constants/version.h.in b/chrome/chrome_cleaner/constants/version.h.in
new file mode 100644
index 0000000..a4943f7
--- /dev/null
+++ b/chrome/chrome_cleaner/constants/version.h.in
@@ -0,0 +1,25 @@
+// 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.
+
+// version.h is generated from version.h.in.  Edit the source!
+
+// See also software_reporter_tool_branding.h and
+// chrome_cleanup_tool_branding.h for branding that varies by executable.
+
+// Version Information
+
+#define CHROME_VERSION @MAJOR@,@MINOR@,@BUILD@
+#define CHROME_VERSION_STRING L"@MAJOR@.@MINOR@.@BUILD@"
+#define CHROME_VERSION_UTF8_STRING "@MAJOR@.@MINOR@.@BUILD@"
+
+// Branding Information
+
+#define COMPANY_FULLNAME_STRING L"@COMPANY_FULLNAME@"
+#define COMPANY_SHORTNAME_STRING L"@COMPANY_SHORTNAME@"
+#define COPYRIGHT_STRING L"@COPYRIGHT@"
+#define OFFICIAL_BUILD_STRING L"@OFFICIAL_BUILD@"
+
+// Changelist Information
+
+#define LASTCHANGE_STRING L"@LASTCHANGE@"
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index 9cd4c88..4caceebd 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -3424,8 +3424,9 @@
   SimulateUserInputChangeForElement(&confirmation_password, "");
   EXPECT_EQ(0, fake_driver_.called_show_manual_fallback_for_saving_count());
 }
-// Tests that information about Gaia reauthentication form is not sent to the
-// browser, nor on load nor on user click.
+
+// Tests that information about Gaia reauthentication form is sent to the
+// browser with information that the password should not be saved.
 TEST_F(PasswordAutofillAgentTest, GaiaReauthenticationFormIgnored) {
   // HTML is already loaded in test SetUp method, so information about password
   // forms was already sent to the |fake_drive_|. Hence it should be reset.
@@ -3447,9 +3448,12 @@
   // Simulate a user clicking on the password element.
   autofill_agent_->FormControlElementClicked(password_element_, false);
 
-  // Check that no information about Gaia reauthentication is not sent.
-  EXPECT_FALSE(fake_driver_.called_password_forms_parsed());
-  EXPECT_FALSE(fake_driver_.called_password_forms_rendered());
+  // Check that information about Gaia reauthentication is sent to the browser.
+  ASSERT_TRUE(fake_driver_.called_password_forms_parsed());
+  const std::vector<autofill::PasswordForm>& parsed_forms =
+      fake_driver_.password_forms_parsed().value();
+  ASSERT_EQ(1u, parsed_forms.size());
+  EXPECT_TRUE(parsed_forms[0].is_gaia_with_skip_save_password_form);
 }
 
 // Tests that "Show all saved passwords" option is shown on a password field.
diff --git a/chrome/renderer/pepper/pepper_flash_font_file_host.cc b/chrome/renderer/pepper/pepper_flash_font_file_host.cc
index 4313c6a..981e54e3 100644
--- a/chrome/renderer/pepper/pepper_flash_font_file_host.cc
+++ b/chrome/renderer/pepper/pepper_flash_font_file_host.cc
@@ -13,12 +13,38 @@
 #include "ppapi/host/ppapi_host.h"
 #include "ppapi/proxy/ppapi_messages.h"
 #include "ppapi/proxy/serialized_structs.h"
-
-#if defined(OS_LINUX) || defined(OS_OPENBSD)
-#include "content/public/child/child_process_sandbox_support_linux.h"
-#include "content/public/common/common_sandbox_support_linux.h"
-#elif defined(OS_WIN)
 #include "third_party/skia/include/core/SkFontMgr.h"
+
+#if !defined(OS_WIN)
+namespace {
+
+SkFontStyle::Weight PepperWeightToSkWeight(int pepper_weight) {
+  switch (pepper_weight) {
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_100:
+      return SkFontStyle::kThin_Weight;
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_200:
+      return SkFontStyle::kExtraLight_Weight;
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_300:
+      return SkFontStyle::kLight_Weight;
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_400:
+      return SkFontStyle::kNormal_Weight;
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_500:
+      return SkFontStyle::kMedium_Weight;
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_600:
+      return SkFontStyle::kSemiBold_Weight;
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_700:
+      return SkFontStyle::kBold_Weight;
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_800:
+      return SkFontStyle::kExtraBold_Weight;
+    case PP_BROWSERFONT_TRUSTED_WEIGHT_900:
+      return SkFontStyle::kBlack_Weight;
+    default:
+      NOTREACHED();
+      return SkFontStyle::kInvisible_Weight;
+  }
+}
+
+}  // namespace
 #endif
 
 PepperFlashFontFileHost::PepperFlashFontFileHost(
@@ -28,24 +54,23 @@
     const ppapi::proxy::SerializedFontDescription& description,
     PP_PrivateFontCharset charset)
     : ResourceHost(host->GetPpapiHost(), instance, resource) {
-#if defined(OS_LINUX) || defined(OS_OPENBSD)
-  fd_.reset(content::MatchFontWithFallback(
-      description.face,
-      description.weight >= PP_BROWSERFONT_TRUSTED_WEIGHT_BOLD,
-      description.italic,
-      charset,
-      PP_BROWSERFONT_TRUSTED_FAMILY_DEFAULT));
-#elif defined(OS_WIN)
-  int weight = description.weight;
+  int weight;
+#if defined(OS_WIN)
+  // TODO(https://crbug.com/857388): Figure out why this diverges from the
+  // #else block.
+  weight = description.weight;
   if (weight == FW_DONTCARE)
     weight = SkFontStyle::kNormal_Weight;
+#else
+  weight = PepperWeightToSkWeight(description.weight);
+#endif
   SkFontStyle style(weight, SkFontStyle::kNormal_Width,
                     description.italic ? SkFontStyle::kItalic_Slant
                                        : SkFontStyle::kUpright_Slant);
   sk_sp<SkFontMgr> font_mgr(SkFontMgr::RefDefault());
+
   typeface_ = sk_sp<SkTypeface>(
       font_mgr->matchFamilyStyle(description.face.c_str(), style));
-#endif  // defined(OS_LINUX) || defined(OS_OPENBSD)
 }
 
 PepperFlashFontFileHost::~PepperFlashFontFileHost() {}
@@ -64,12 +89,6 @@
                                           void* buffer,
                                           size_t* length) {
   bool result = false;
-#if defined(OS_LINUX) || defined(OS_OPENBSD)
-  int fd = fd_.get();
-  if (fd != -1)
-    result = content::GetFontTable(fd, table, 0 /* offset */,
-                                   reinterpret_cast<uint8_t*>(buffer), length);
-#elif defined(OS_WIN)
   if (typeface_) {
     table = base::ByteSwap(table);
     if (buffer == NULL) {
@@ -82,7 +101,6 @@
         result = true;
     }
   }
-#endif
   return result;
 }
 
diff --git a/chrome/renderer/pepper/pepper_flash_font_file_host.h b/chrome/renderer/pepper/pepper_flash_font_file_host.h
index 3e9ba7d..6b67a7c 100644
--- a/chrome/renderer/pepper/pepper_flash_font_file_host.h
+++ b/chrome/renderer/pepper/pepper_flash_font_file_host.h
@@ -14,12 +14,8 @@
 #include "ppapi/c/private/pp_private_font_charset.h"
 #include "ppapi/host/resource_host.h"
 
-#if defined(OS_LINUX) || defined(OS_OPENBSD)
-#include "base/files/scoped_file.h"
-#elif defined(OS_WIN)
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "third_party/skia/include/core/SkTypeface.h"
-#endif
 
 namespace content {
 class RendererPpapiHost;
@@ -50,11 +46,7 @@
                          uint32_t table);
   bool GetFontData(uint32_t table, void* buffer, size_t* length);
 
-#if defined(OS_LINUX) || defined(OS_OPENBSD)
-  base::ScopedFD fd_;
-#elif defined(OS_WIN)
   sk_sp<SkTypeface> typeface_;
-#endif
 
   DISALLOW_COPY_AND_ASSIGN(PepperFlashFontFileHost);
 };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 41079e8..d5417c5c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -503,7 +503,6 @@
       "../browser/chrome_find_request_manager_browsertest.cc",
       "../browser/chrome_main_browsertest.cc",
       "../browser/chrome_navigation_browsertest.cc",
-      "../browser/chrome_network_service_browsertest.cc",
       "../browser/chrome_network_service_restart_browsertest.cc",
       "../browser/chrome_origin_trials_browsertest.cc",
       "../browser/chrome_plugin_browsertest.cc",
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index ff14588..732de74 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -199,6 +199,10 @@
   if (is_android || enable_extensions) {
     deps += [ "//chrome/services/media_gallery_util:lib" ]
   }
+
+  if (is_linux && !is_android) {
+    deps += [ "//components/services/font:lib" ]
+  }
 }
 
 if (!is_android) {
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 3ba9532..0fa8be5 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -201,6 +201,7 @@
 
     deps += [
       "//components/metrics:serialization",
+      "//components/services/font:lib",
       "//third_party/fontconfig",
     ]
   }
diff --git a/chromecast/browser/DEPS b/chromecast/browser/DEPS
index aea8f3b..225a17d1 100644
--- a/chromecast/browser/DEPS
+++ b/chromecast/browser/DEPS
@@ -16,6 +16,7 @@
   "+components/prefs",
   "+components/pref_registry",
   "+components/proxy_config",
+  "+components/services/font",
   "+components/storage_monitor",
   "+components/user_prefs",
   "+components/version_info",
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 05b22d807..2d914a59 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -76,6 +76,11 @@
 #include "media/mojo/services/media_service.h"      // nogncheck
 #endif  // ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS
 
+#if defined(OS_LINUX)
+#include "components/services/font/font_service_app.h"  // nogncheck
+#include "components/services/font/public/interfaces/constants.mojom.h"  // nogncheck
+#endif
+
 #if defined(OS_LINUX) || defined(OS_ANDROID)
 #include "components/crash/content/app/breakpad_linux.h"
 #include "components/crash/content/browser/crash_handler_host_linux.h"
@@ -683,6 +688,14 @@
 #endif
 }
 
+void CastContentBrowserClient::RegisterOutOfProcessServices(
+    OutOfProcessServiceMap* services) {
+#if defined(OS_LINUX)
+  (*services)[font_service::mojom::kServiceName] =
+      base::BindRepeating(&base::ASCIIToUTF16, "Font Service");
+#endif
+}
+
 std::unique_ptr<base::Value>
 CastContentBrowserClient::GetServiceManifestOverlay(
     base::StringPiece service_name) {
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index 8f9502c..a61ea2db 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -183,6 +183,7 @@
   void RegisterInProcessServices(
       StaticServiceMap* services,
       content::ServiceManagerConnection* connection) override;
+  void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) override;
   std::unique_ptr<base::Value> GetServiceManifestOverlay(
       base::StringPiece service_name) override;
   void GetAdditionalMappedFilesForChildProcess(
diff --git a/chromeos/services/device_sync/BUILD.gn b/chromeos/services/device_sync/BUILD.gn
index c61a797..2ead21f 100644
--- a/chromeos/services/device_sync/BUILD.gn
+++ b/chromeos/services/device_sync/BUILD.gn
@@ -10,12 +10,8 @@
 
 static_library("device_sync") {
   sources = [
-    "cryptauth_client_factory_impl.cc",
-    "cryptauth_client_factory_impl.h",
     "cryptauth_enroller_factory_impl.cc",
     "cryptauth_enroller_factory_impl.h",
-    "cryptauth_token_fetcher_impl.cc",
-    "cryptauth_token_fetcher_impl.h",
     "device_sync_base.cc",
     "device_sync_base.h",
     "device_sync_impl.cc",
@@ -75,7 +71,6 @@
   testonly = true
 
   sources = [
-    "cryptauth_token_fetcher_impl_unittest.cc",
     "device_sync_service_unittest.cc",
   ]
 
diff --git a/chromeos/services/device_sync/cryptauth_client_factory_impl.cc b/chromeos/services/device_sync/cryptauth_client_factory_impl.cc
deleted file mode 100644
index 29ca54f..0000000
--- a/chromeos/services/device_sync/cryptauth_client_factory_impl.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/services/device_sync/cryptauth_client_factory_impl.h"
-
-#include "chromeos/services/device_sync/cryptauth_token_fetcher_impl.h"
-#include "components/cryptauth/cryptauth_client_impl.h"
-
-namespace chromeos {
-
-namespace device_sync {
-
-CryptAuthClientFactoryImpl::CryptAuthClientFactoryImpl(
-    identity::IdentityManager* identity_manager,
-    scoped_refptr<net::URLRequestContextGetter> url_request_context,
-    const cryptauth::DeviceClassifier& device_classifier)
-    : identity_manager_(identity_manager),
-      url_request_context_(std::move(url_request_context)),
-      device_classifier_(device_classifier) {}
-
-CryptAuthClientFactoryImpl::~CryptAuthClientFactoryImpl() = default;
-
-std::unique_ptr<cryptauth::CryptAuthClient>
-CryptAuthClientFactoryImpl::CreateInstance() {
-  return std::make_unique<cryptauth::CryptAuthClientImpl>(
-      std::make_unique<cryptauth::CryptAuthApiCallFlow>(),
-      std::make_unique<CryptAuthAccessTokenFetcherImpl>(identity_manager_),
-      url_request_context_, device_classifier_);
-}
-
-}  // namespace device_sync
-
-}  // namespace chromeos
diff --git a/chromeos/services/device_sync/cryptauth_client_factory_impl.h b/chromeos/services/device_sync/cryptauth_client_factory_impl.h
deleted file mode 100644
index 9786627..0000000
--- a/chromeos/services/device_sync/cryptauth_client_factory_impl.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_CLIENT_FACTORY_IMPL_H_
-#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_CLIENT_FACTORY_IMPL_H_
-
-#include "base/memory/ref_counted.h"
-#include "components/cryptauth/cryptauth_client.h"
-#include "components/cryptauth/proto/cryptauth_api.pb.h"
-
-namespace identity {
-class IdentityManager;
-}  // namespace identity
-
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
-
-namespace chromeos {
-
-namespace device_sync {
-
-// CryptAuthClientFactory implementation which utilizes IdentityManager.
-class CryptAuthClientFactoryImpl : public cryptauth::CryptAuthClientFactory {
- public:
-  CryptAuthClientFactoryImpl(
-      identity::IdentityManager* identity_manager,
-      scoped_refptr<net::URLRequestContextGetter> url_request_context,
-      const cryptauth::DeviceClassifier& device_classifier);
-  ~CryptAuthClientFactoryImpl() override;
-
-  // cryptauth::CryptAuthClientFactory:
-  std::unique_ptr<cryptauth::CryptAuthClient> CreateInstance() override;
-
- private:
-  identity::IdentityManager* identity_manager_;
-  const scoped_refptr<net::URLRequestContextGetter> url_request_context_;
-  const cryptauth::DeviceClassifier device_classifier_;
-};
-
-}  // namespace device_sync
-
-}  // namespace chromeos
-
-#endif  // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_CLIENT_FACTORY_IMPL_H_
diff --git a/chromeos/services/device_sync/cryptauth_token_fetcher_impl.cc b/chromeos/services/device_sync/cryptauth_token_fetcher_impl.cc
deleted file mode 100644
index 32bc5ea..0000000
--- a/chromeos/services/device_sync/cryptauth_token_fetcher_impl.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/services/device_sync/cryptauth_token_fetcher_impl.h"
-
-#include <set>
-
-#include "services/identity/public/cpp/identity_manager.h"
-
-namespace chromeos {
-
-namespace device_sync {
-
-namespace {
-
-const char kIdentityManagerConsumerName[] = "multi_device_service";
-const char kCryptAuthApiScope[] = "https://www.googleapis.com/auth/cryptauth";
-
-}  // namespace
-
-CryptAuthAccessTokenFetcherImpl::CryptAuthAccessTokenFetcherImpl(
-    identity::IdentityManager* identity_manager)
-    : identity_manager_(identity_manager), weak_ptr_factory_(this) {}
-
-CryptAuthAccessTokenFetcherImpl::~CryptAuthAccessTokenFetcherImpl() {
-  // If any callbacks are still pending when the object is deleted, run them
-  // now, passing an empty string to indicate failure. This ensures that no
-  // callbacks are left hanging forever.
-  InvokeThenClearPendingCallbacks(std::string());
-}
-
-void CryptAuthAccessTokenFetcherImpl::FetchAccessToken(
-    const AccessTokenCallback& callback) {
-  pending_callbacks_.emplace_back(callback);
-
-  // If the token is already being fetched, continue waiting for it.
-  if (access_token_fetcher_)
-    return;
-
-  const OAuth2TokenService::ScopeSet kScopes{kCryptAuthApiScope};
-  access_token_fetcher_ =
-      identity_manager_->CreateAccessTokenFetcherForPrimaryAccount(
-          kIdentityManagerConsumerName, kScopes,
-          base::BindOnce(&CryptAuthAccessTokenFetcherImpl::OnAccessTokenFetched,
-                         weak_ptr_factory_.GetWeakPtr()),
-          identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
-}
-
-void CryptAuthAccessTokenFetcherImpl::InvokeThenClearPendingCallbacks(
-    const std::string& access_token) {
-  for (auto& callback : pending_callbacks_)
-    callback.Run(access_token);
-
-  pending_callbacks_.clear();
-}
-
-void CryptAuthAccessTokenFetcherImpl::OnAccessTokenFetched(
-    GoogleServiceAuthError error,
-    std::string access_token) {
-  access_token_fetcher_.reset();
-  InvokeThenClearPendingCallbacks(
-      error == GoogleServiceAuthError::AuthErrorNone() ? access_token
-                                                       : std::string());
-}
-
-}  // namespace device_sync
-
-}  // namespace chromeos
diff --git a/chromeos/services/device_sync/cryptauth_token_fetcher_impl.h b/chromeos/services/device_sync/cryptauth_token_fetcher_impl.h
deleted file mode 100644
index 69d52d6..0000000
--- a/chromeos/services/device_sync/cryptauth_token_fetcher_impl.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_TOKEN_FETCHER_IMPL_H_
-#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_TOKEN_FETCHER_IMPL_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
-#include "components/cryptauth/cryptauth_access_token_fetcher.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-
-namespace identity {
-class IdentityManager;
-class PrimaryAccountAccessTokenFetcher;
-}  // namespace identity
-
-namespace chromeos {
-
-namespace device_sync {
-
-// CryptAuthAccessTokenFetcher implementation which utilizes IdentityManager.
-class CryptAuthAccessTokenFetcherImpl
-    : public cryptauth::CryptAuthAccessTokenFetcher {
- public:
-  explicit CryptAuthAccessTokenFetcherImpl(
-      identity::IdentityManager* identity_manager);
-
-  ~CryptAuthAccessTokenFetcherImpl() override;
-
-  // cryptauth::CryptAuthAccessTokenFetcher:
-  void FetchAccessToken(const AccessTokenCallback& callback) override;
-
- private:
-  void InvokeThenClearPendingCallbacks(const std::string& access_token);
-  void OnAccessTokenFetched(GoogleServiceAuthError error,
-                            std::string access_token);
-
-  identity::IdentityManager* identity_manager_;
-
-  std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
-      access_token_fetcher_;
-  std::vector<AccessTokenCallback> pending_callbacks_;
-
-  base::WeakPtrFactory<CryptAuthAccessTokenFetcherImpl> weak_ptr_factory_;
-};
-
-}  // namespace device_sync
-
-}  // namespace chromeos
-
-#endif  // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_TOKEN_FETCHER_IMPL_H_
diff --git a/chromeos/services/device_sync/cryptauth_token_fetcher_impl_unittest.cc b/chromeos/services/device_sync/cryptauth_token_fetcher_impl_unittest.cc
deleted file mode 100644
index 2ef43210..0000000
--- a/chromeos/services/device_sync/cryptauth_token_fetcher_impl_unittest.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/services/device_sync/cryptauth_token_fetcher_impl.h"
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/run_loop.h"
-#include "base/test/scoped_task_environment.h"
-#include "services/identity/public/cpp/identity_test_environment.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace chromeos {
-
-namespace device_sync {
-
-namespace {
-
-const char kAccessToken[] = "access_token";
-const char kTestEmail[] = "example@gmail.com";
-
-}  // namespace
-
-class DeviceSyncCryptAuthAccessTokenFetcherImplTest : public testing::Test {
- protected:
-  DeviceSyncCryptAuthAccessTokenFetcherImplTest() {}
-
-  void SetUp() override {
-    identity_test_environment_ =
-        std::make_unique<identity::IdentityTestEnvironment>();
-    identity_test_environment_->MakePrimaryAccountAvailable(kTestEmail);
-
-    token_fetcher_ = std::make_unique<CryptAuthAccessTokenFetcherImpl>(
-        identity_test_environment_->identity_manager());
-  }
-
-  void TearDown() override {
-    // Deleting the object should not result in any additional tokens provided.
-    token_fetcher_.reset();
-    EXPECT_EQ(nullptr, GetTokenAndReset());
-
-    EXPECT_TRUE(on_access_token_received_callback_.is_null());
-  }
-
-  void set_on_access_token_received_callback(
-      base::OnceClosure on_access_token_received_callback) {
-    EXPECT_TRUE(on_access_token_received_callback_.is_null());
-    on_access_token_received_callback_ =
-        std::move(on_access_token_received_callback);
-  }
-
-  void StartFetchingAccessToken() {
-    token_fetcher_->FetchAccessToken(base::Bind(
-        &DeviceSyncCryptAuthAccessTokenFetcherImplTest::OnAccessTokenFetched,
-        base::Unretained(this)));
-  }
-
-  void OnAccessTokenFetched(const std::string& access_token) {
-    last_access_token_ = std::make_unique<std::string>(access_token);
-    if (!on_access_token_received_callback_.is_null())
-      std::move(on_access_token_received_callback_).Run();
-  }
-
-  std::unique_ptr<std::string> GetTokenAndReset() {
-    return std::move(last_access_token_);
-  }
-
-  const base::test::ScopedTaskEnvironment scoped_task_environment_;
-
-  std::unique_ptr<std::string> last_access_token_;
-  base::OnceClosure on_access_token_received_callback_;
-
-  std::unique_ptr<identity::IdentityTestEnvironment> identity_test_environment_;
-  std::unique_ptr<CryptAuthAccessTokenFetcherImpl> token_fetcher_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DeviceSyncCryptAuthAccessTokenFetcherImplTest);
-};
-
-TEST_F(DeviceSyncCryptAuthAccessTokenFetcherImplTest, TestSuccess) {
-  base::RunLoop run_loop;
-  set_on_access_token_received_callback(run_loop.QuitClosure());
-
-  // Start fetching the token. Nothing should be returned yet since the message
-  // loop has not been run.
-  StartFetchingAccessToken();
-  EXPECT_EQ(nullptr, GetTokenAndReset());
-
-  identity_test_environment_
-      ->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
-          kAccessToken, base::Time::Max() /* expiration */);
-
-  // Run the request and confirm that the access token was returned.
-  run_loop.Run();
-  EXPECT_EQ(kAccessToken, *GetTokenAndReset());
-}
-
-TEST_F(DeviceSyncCryptAuthAccessTokenFetcherImplTest, TestFailure) {
-  base::RunLoop run_loop;
-  set_on_access_token_received_callback(run_loop.QuitClosure());
-
-  // Start fetching the token. Nothing should be returned yet since the message
-  // loop has not been run.
-  StartFetchingAccessToken();
-  EXPECT_EQ(nullptr, GetTokenAndReset());
-
-  identity_test_environment_
-      ->WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
-          GoogleServiceAuthError(
-              GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS));
-
-  // Run the request and confirm that an empty string was returned, signifying a
-  // failure to fetch the token.
-  run_loop.Run();
-  EXPECT_EQ(std::string(), *GetTokenAndReset());
-}
-
-TEST_F(DeviceSyncCryptAuthAccessTokenFetcherImplTest,
-       TestDeletedBeforeOperationFinished) {
-  StartFetchingAccessToken();
-  EXPECT_EQ(nullptr, GetTokenAndReset());
-
-  // Deleting the object should result in the callback being invoked with an
-  // empty string (indicating failure).
-  token_fetcher_.reset();
-  EXPECT_EQ(std::string(), *GetTokenAndReset());
-}
-
-}  // namespace device_sync
-
-}  // namespace chromeos
diff --git a/chromeos/services/device_sync/device_sync_impl.cc b/chromeos/services/device_sync/device_sync_impl.cc
index 22a6ea5c..ea2ff50 100644
--- a/chromeos/services/device_sync/device_sync_impl.cc
+++ b/chromeos/services/device_sync/device_sync_impl.cc
@@ -9,8 +9,8 @@
 #include "base/optional.h"
 #include "base/time/default_clock.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
-#include "chromeos/services/device_sync/cryptauth_client_factory_impl.h"
 #include "chromeos/services/device_sync/cryptauth_enroller_factory_impl.h"
+#include "components/cryptauth/cryptauth_client_impl.h"
 #include "components/cryptauth/cryptauth_device_manager_impl.h"
 #include "components/cryptauth/cryptauth_enrollment_manager_impl.h"
 #include "components/cryptauth/cryptauth_gcm_manager_impl.h"
@@ -324,9 +324,10 @@
           gcm_driver_, pref_service_.get());
   cryptauth_gcm_manager_->StartListening();
 
-  cryptauth_client_factory_ = std::make_unique<CryptAuthClientFactoryImpl>(
-      identity_manager_, url_request_context_,
-      cryptauth::device_classifier_util::GetDeviceClassifier());
+  cryptauth_client_factory_ =
+      std::make_unique<cryptauth::CryptAuthClientFactoryImpl>(
+          identity_manager_, url_request_context_,
+          cryptauth::device_classifier_util::GetDeviceClassifier());
 
   // Initialize |crypauth_device_manager_| and start observing. Start() is not
   // called yet since the device has not completed enrollment.
diff --git a/components/autofill/content/common/autofill_types.mojom b/components/autofill/content/common/autofill_types.mojom
index 71e5244..2b0820e 100644
--- a/components/autofill/content/common/autofill_types.mojom
+++ b/components/autofill/content/common/autofill_types.mojom
@@ -247,6 +247,7 @@
   bool is_affiliation_based_match;
   PasswordFormSubmissionIndicatorEvent submission_event;
   bool only_for_fallback_saving;
+  bool is_gaia_with_skip_save_password_form;
 };
 
 // TODO(leonhsl): Use map directly after http://crbug.com/628104 solved.
diff --git a/components/autofill/content/common/autofill_types_struct_traits.cc b/components/autofill/content/common/autofill_types_struct_traits.cc
index f0cb980..f1d14d1 100644
--- a/components/autofill/content/common/autofill_types_struct_traits.cc
+++ b/components/autofill/content/common/autofill_types_struct_traits.cc
@@ -795,6 +795,8 @@
   out->is_public_suffix_match = data.is_public_suffix_match();
   out->is_affiliation_based_match = data.is_affiliation_based_match();
   out->only_for_fallback_saving = data.only_for_fallback_saving();
+  out->is_gaia_with_skip_save_password_form =
+      data.is_gaia_with_skip_save_password_form();
 
   return true;
 }
diff --git a/components/autofill/content/common/autofill_types_struct_traits.h b/components/autofill/content/common/autofill_types_struct_traits.h
index 2f4cdc23..da498a2 100644
--- a/components/autofill/content/common/autofill_types_struct_traits.h
+++ b/components/autofill/content/common/autofill_types_struct_traits.h
@@ -628,6 +628,11 @@
     return r.only_for_fallback_saving;
   }
 
+  static bool is_gaia_with_skip_save_password_form(
+      const autofill::PasswordForm& r) {
+    return r.is_gaia_with_skip_save_password_form;
+  }
+
   static bool Read(autofill::mojom::PasswordFormDataView data,
                    autofill::PasswordForm* out);
 };
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index f0b3f67..80390a44 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1152,16 +1152,6 @@
 
   std::vector<PasswordForm> password_forms;
   for (const blink::WebFormElement& form : forms) {
-    if (IsGaiaReauthenticationForm(form)) {
-      // Bail if this is a GAIA passwords site reauthentication form, so that
-      // page will be ignored.
-      return;
-    }
-    if (IsGaiaWithSkipSavePasswordForm(form)) {
-      // Bail if this is a GAIA enable Chrome sync flow, so that page will be
-      // ignored.
-      return;
-    }
     if (only_visible) {
       bool is_form_visible = form_util::AreFormContentsVisible(form);
       if (logger) {
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index ba246c3..9325b8a5 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -924,6 +924,9 @@
   password_form->action = form_util::GetCanonicalActionForForm(web_form);
   if (!password_form->action.is_valid())
     return nullptr;
+  password_form->is_gaia_with_skip_save_password_form =
+      IsGaiaWithSkipSavePasswordForm(web_form) ||
+      IsGaiaReauthenticationForm(web_form);
 
   blink::WebVector<blink::WebFormControlElement> control_elements;
   web_form.GetFormControlElements(control_elements);
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 55ae4594..8b59c49 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -170,6 +170,8 @@
     "webdata/autofill_profile_data_type_controller.h",
     "webdata/autofill_profile_sync_bridge.cc",
     "webdata/autofill_profile_sync_bridge.h",
+    "webdata/autofill_profile_sync_difference_tracker.cc",
+    "webdata/autofill_profile_sync_difference_tracker.h",
     "webdata/autofill_profile_syncable_service.cc",
     "webdata/autofill_profile_syncable_service.h",
     "webdata/autofill_table.cc",
@@ -444,6 +446,7 @@
     "validation_unittest.cc",
     "webdata/autocomplete_sync_bridge_unittest.cc",
     "webdata/autofill_profile_sync_bridge_unittest.cc",
+    "webdata/autofill_profile_sync_difference_tracker_unittest.cc",
     "webdata/autofill_profile_syncable_service_unittest.cc",
     "webdata/autofill_table_unittest.cc",
     "webdata/autofill_wallet_metadata_syncable_service_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index dc16ff8..f96dba386 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -254,14 +254,14 @@
 }
 
 AutofillProfile& AutofillProfile::operator=(const AutofillProfile& profile) {
+  if (this == &profile)
+    return *this;
+
   set_use_count(profile.use_count());
   set_use_date(profile.use_date());
   set_previous_use_date(profile.previous_use_date());
   set_modification_date(profile.modification_date());
 
-  if (this == &profile)
-    return *this;
-
   set_guid(profile.guid());
   set_origin(profile.origin());
 
@@ -465,6 +465,30 @@
   return true;
 }
 
+void AutofillProfile::OverwriteDataFrom(const AutofillProfile& profile) {
+  // Verified profiles should never be overwritten with unverified data.
+  DCHECK(!IsVerified() || profile.IsVerified());
+  DCHECK_EQ(guid(), profile.guid());
+
+  // Some fields should not got overwritten by empty values; back-up the
+  // values.
+  std::string language_code_value = language_code();
+  std::string origin_value = origin();
+  int validity_bitfield_value = GetValidityBitfieldValue();
+  base::string16 name_full_value = GetRawInfo(NAME_FULL);
+
+  *this = profile;
+
+  if (origin().empty())
+    set_origin(origin_value);
+  if (language_code().empty())
+    set_language_code(language_code_value);
+  if (GetValidityBitfieldValue() == 0)
+    SetValidityFromBitfieldValue(validity_bitfield_value);
+  if (!HasRawInfo(NAME_FULL))
+    SetRawInfo(NAME_FULL, name_full_value);
+}
+
 bool AutofillProfile::MergeDataFrom(const AutofillProfile& profile,
                                     const std::string& app_locale) {
   // Verified profiles should never be overwritten with unverified data.
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h
index 72288bd..0353a15 100644
--- a/components/autofill/core/browser/autofill_profile.h
+++ b/components/autofill/core/browser/autofill_profile.h
@@ -122,6 +122,10 @@
                              const std::string& app_locale,
                              const ServerFieldTypeSet& types) const;
 
+  // Overwrites the data of |this| profile with data from the given |profile|.
+  // Expects that the profiles have the same guid.
+  void OverwriteDataFrom(const AutofillProfile& profile);
+
   // Merges the data from |this| profile and the given |profile| into |this|
   // profile. Expects that |this| and |profile| have already been deemed
   // mergeable by an AutofillProfileComparator.
diff --git a/components/autofill/core/browser/autofill_profile_sync_util.cc b/components/autofill/core/browser/autofill_profile_sync_util.cc
index 3d85dd1..f81dc6f 100644
--- a/components/autofill/core/browser/autofill_profile_sync_util.cc
+++ b/components/autofill/core/browser/autofill_profile_sync_util.cc
@@ -29,13 +29,17 @@
   return trimmed_value;
 }
 
+bool IsAutofillProfileSpecificsValid(
+    const AutofillProfileSpecifics& specifics) {
+  return base::IsValidGUID(specifics.guid());
+}
+
 }  // namespace
 
 std::unique_ptr<EntityData> CreateEntityDataFromAutofillProfile(
     const AutofillProfile& entry) {
-  if (!base::IsValidGUID(entry.guid())) {
-    return nullptr;
-  }
+  // Validity of the guid is guaranteed by the database layer.
+  DCHECK(base::IsValidGUID(entry.guid()));
 
   auto entity_data = std::make_unique<EntityData>();
   entity_data->non_unique_name = entry.guid();
@@ -124,7 +128,7 @@
 
 std::unique_ptr<AutofillProfile> CreateAutofillProfileFromSpecifics(
     const AutofillProfileSpecifics& specifics) {
-  if (!base::IsValidGUID(specifics.guid())) {
+  if (!IsAutofillProfileSpecificsValid(specifics)) {
     return nullptr;
   }
   std::unique_ptr<AutofillProfile> profile =
@@ -215,15 +219,14 @@
 }
 
 std::string GetStorageKeyFromAutofillProfile(const AutofillProfile& entry) {
-  if (!base::IsValidGUID(entry.guid())) {
-    return std::string();
-  }
+  // Validity of the guid is guaranteed by the database layer.
+  DCHECK(base::IsValidGUID(entry.guid()));
   return entry.guid();
 }
 
 std::string GetStorageKeyFromAutofillProfileSpecifics(
     const AutofillProfileSpecifics& specifics) {
-  if (!base::IsValidGUID(specifics.guid())) {
+  if (!IsAutofillProfileSpecificsValid(specifics)) {
     return std::string();
   }
   return specifics.guid();
diff --git a/components/autofill/core/browser/autofill_profile_sync_util.h b/components/autofill/core/browser/autofill_profile_sync_util.h
index ef0d3d9d..a435952 100644
--- a/components/autofill/core/browser/autofill_profile_sync_util.h
+++ b/components/autofill/core/browser/autofill_profile_sync_util.h
@@ -21,13 +21,13 @@
 class AutofillProfile;
 
 // Converts the given |entry| into a syncer EntityData with equivalent
-// autofill profile specifics. Returns nullptr if |entry| has invalid guid.
+// autofill profile specifics. Returns nullptr if |entry| is invalid.
 // Shortens all string fields to AutofillTable::kMaxDataLength.
 std::unique_ptr<syncer::EntityData> CreateEntityDataFromAutofillProfile(
     const AutofillProfile& entry);
 
 // Converts the given autofill profile |specifics| into an equivalent
-// AutofillProfile. Returns nullptr if |specifics| has invalid guid.
+// AutofillProfile. Returns nullptr if |specifics| is invalid.
 std::unique_ptr<AutofillProfile> CreateAutofillProfileFromSpecifics(
     const sync_pb::AutofillProfileSpecifics& specifics);
 
diff --git a/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc b/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
index e0ebdfb..9204eca5 100644
--- a/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_sync_util_unittest.cc
@@ -142,14 +142,6 @@
   EXPECT_FALSE(entity_data->specifics.autofill_profile().has_company_name());
 }
 
-// Test that nullptr is produced if the input guid is invalid.
-TEST_F(AutofillProfileSyncUtilTest,
-       CreateEntityDataFromAutofillProfile_Invalid) {
-  AutofillProfile profile(kGuidInvalid, std::string());
-
-  EXPECT_EQ(nullptr, CreateEntityDataFromAutofillProfile(profile));
-}
-
 // Test that long fields get trimmed.
 TEST_F(AutofillProfileSyncUtilTest,
        CreateEntityDataFromAutofillProfile_Trimmed) {
@@ -275,13 +267,6 @@
   EXPECT_EQ(kGuid, GetStorageKeyFromAutofillProfile(profile));
 }
 
-// Tests that empty string is returned for entry with invalid guid.
-TEST_F(AutofillProfileSyncUtilTest, GetStorageKeyFromAutofillProfile_Invalid) {
-  AutofillProfile profile(kGuidInvalid, std::string());
-
-  EXPECT_EQ(std::string(), GetStorageKeyFromAutofillProfile(profile));
-}
-
 // Tests that guid is returned as storage key.
 TEST_F(AutofillProfileSyncUtilTest, GetStorageKeyFromAutofillProfileSpecifics) {
   AutofillProfileSpecifics specifics;
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
index d52c7773..3a125fc3 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.cc
@@ -17,6 +17,7 @@
 #include "components/autofill/core/browser/country_names.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/proto/autofill_sync.pb.h"
+#include "components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
@@ -105,8 +106,30 @@
     syncer::EntityChangeList entity_data) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  DCHECK(entity_data.empty());
-  // TODO(jkrcal): Implement non-empty initial merge.
+  AutofillProfileInitialSyncDifferenceTracker initial_sync_tracker(
+      GetAutofillTable());
+
+  for (const auto& change : entity_data) {
+    DCHECK(change.data().specifics.has_autofill_profile());
+    std::unique_ptr<AutofillProfile> remote =
+        CreateAutofillProfileFromSpecifics(
+            change.data().specifics.autofill_profile());
+    if (!remote) {
+      DVLOG(2) << "[AUTOFILL SYNC] Invalid remote specifics "
+               << change.data().specifics.autofill_profile().SerializeAsString()
+               << " received from the server in an initial sync.";
+      continue;
+    }
+    RETURN_IF_ERROR(
+        initial_sync_tracker.IncorporateRemoteProfile(std::move(remote)));
+  }
+
+  RETURN_IF_ERROR(
+      initial_sync_tracker.MergeSimilarEntriesForInitialSync(app_locale_));
+  RETURN_IF_ERROR(
+      FlushSyncTracker(std::move(metadata_change_list), &initial_sync_tracker));
+
+  web_data_backend_->NotifyThatSyncHasStarted(syncer::AUTOFILL_PROFILE);
   return base::nullopt;
 }
 
@@ -115,9 +138,27 @@
     syncer::EntityChangeList entity_changes) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  DCHECK(entity_changes.empty());
-  // TODO(jkrcal): Implement non-empty sync changes.
-  return base::nullopt;
+  AutofillProfileSyncDifferenceTracker tracker(GetAutofillTable());
+  for (const syncer::EntityChange& change : entity_changes) {
+    if (change.type() == syncer::EntityChange::ACTION_DELETE) {
+      RETURN_IF_ERROR(tracker.IncorporateRemoteDelete(change.storage_key()));
+    } else {
+      DCHECK(change.data().specifics.has_autofill_profile());
+      std::unique_ptr<AutofillProfile> remote =
+          CreateAutofillProfileFromSpecifics(
+              change.data().specifics.autofill_profile());
+      if (!remote) {
+        DVLOG(2)
+            << "[AUTOFILL SYNC] Invalid remote specifics "
+            << change.data().specifics.autofill_profile().SerializeAsString()
+            << " received from the server in an initial sync.";
+        continue;
+      }
+      RETURN_IF_ERROR(tracker.IncorporateRemoteProfile(std::move(remote)));
+    }
+  }
+
+  return FlushSyncTracker(std::move(metadata_change_list), &tracker);
 }
 
 void AutofillProfileSyncBridge::GetData(StorageKeyList storage_keys,
@@ -194,6 +235,29 @@
   }
 }
 
+base::Optional<syncer::ModelError> AutofillProfileSyncBridge::FlushSyncTracker(
+    std::unique_ptr<MetadataChangeList> metadata_change_list,
+    AutofillProfileSyncDifferenceTracker* tracker) {
+  DCHECK(tracker);
+
+  RETURN_IF_ERROR(tracker->FlushToLocal(
+      base::BindOnce(&AutofillWebDataBackend::NotifyOfMultipleAutofillChanges,
+                     base::Unretained(web_data_backend_))));
+
+  std::vector<std::unique_ptr<AutofillProfile>> profiles_to_upload_to_sync;
+  RETURN_IF_ERROR(tracker->FlushToSync(&profiles_to_upload_to_sync));
+  for (const std::unique_ptr<AutofillProfile>& entry :
+       profiles_to_upload_to_sync) {
+    change_processor()->Put(GetStorageKeyFromAutofillProfile(*entry),
+                            CreateEntityDataFromAutofillProfile(*entry),
+                            metadata_change_list.get());
+  }
+
+  return static_cast<syncer::SyncMetadataStoreChangeList*>(
+             metadata_change_list.get())
+      ->TakeError();
+}
+
 void AutofillProfileSyncBridge::LoadMetadata() {
   if (!web_data_backend_ || !web_data_backend_->GetDatabase() ||
       !GetAutofillTable()) {
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h
index d961d0b..547ba71 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h
@@ -26,6 +26,7 @@
 
 namespace autofill {
 
+class AutofillProfileSyncDifferenceTracker;
 class AutofillTable;
 class AutofillWebDataBackend;
 class AutofillWebDataService;
@@ -87,6 +88,11 @@
   // changes.
   void ActOnLocalChange(const AutofillProfileChange& change);
 
+  // Flushes changes accumulated within |tracker| both to local and to sync.
+  base::Optional<syncer::ModelError> FlushSyncTracker(
+      std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+      AutofillProfileSyncDifferenceTracker* tracker);
+
   // Synchronously load sync metadata from the autofill table and pass it to the
   // processor so that it can start tracking changes.
   void LoadMetadata();
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
index efc4439..f7c032c1 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_bridge_unittest.cc
@@ -19,6 +19,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_profile_sync_util.h"
 #include "components/autofill/core/browser/country_names.h"
@@ -62,12 +63,17 @@
 using testing::Eq;
 using testing::Property;
 using testing::Return;
+using testing::UnorderedElementsAre;
 
 namespace {
 
 // Some guids for testing.
 const char kGuidA[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44A";
 const char kGuidB[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
+const char kGuidC[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44C";
+const char kGuidD[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44D";
+const char kGuidInvalid[] = "EDC609ED-7EEE-4F27-B00C";
+const char kHttpOrigin[] = "http://www.example.com/";
 const char kHttpsOrigin[] = "https://www.example.com/";
 const int kValidityStateBitfield = 1984;
 const char kLocaleString[] = "en-US";
@@ -109,15 +115,35 @@
   return entity_data->specifics.autofill_profile();
 }
 
-MATCHER_P(HasSpecifics, expected, "") {
-  const AutofillProfileSpecifics& s1 = arg->specifics.autofill_profile();
-  const AutofillProfileSpecifics& s2 = expected;
+AutofillProfileSpecifics CreateAutofillProfileSpecifics(
+    const std::string& guid,
+    const std::string& origin) {
+  AutofillProfileSpecifics specifics;
+  specifics.set_guid(guid);
+  specifics.set_origin(origin);
+  // Make it consistent with the constructor of AutofillProfile constructor (the
+  // clock value is overrided by TestAutofillClock in the test fixture).
+  specifics.set_use_count(1);
+  specifics.set_use_date(kJune2017.ToTimeT());
+  return specifics;
+}
 
-  AutofillProfile p1 = CreateAutofillProfile(s1);
-  AutofillProfile p2 = CreateAutofillProfile(s2);
-  if (!p1.EqualsIncludingUsageStatsForTesting(p2)) {
-    *result_listener << "entry\n[" << p1 << "]\n"
-                     << "did not match expected\n[" << p2 << "]";
+MATCHER_P(HasSpecifics, expected, "") {
+  AutofillProfile arg_profile =
+      CreateAutofillProfile(arg->specifics.autofill_profile());
+  AutofillProfile expected_profile = CreateAutofillProfile(expected);
+  if (!arg_profile.EqualsIncludingUsageStatsForTesting(expected_profile)) {
+    *result_listener << "entry\n[" << arg_profile << "]\n"
+                     << "did not match expected\n[" << expected_profile << "]";
+    return false;
+  }
+  return true;
+}
+
+MATCHER_P(WithUsageStats, expected, "") {
+  if (!arg.EqualsIncludingUsageStatsForTesting(expected)) {
+    *result_listener << "entry\n[" << arg << "]\n"
+                     << "did not match expected\n[" << expected << "]";
     return false;
   }
   return true;
@@ -133,6 +159,79 @@
   }
 }
 
+// Returns a profile with all fields set.  Contains identical data to the data
+// returned from ConstructCompleteSpecifics().
+AutofillProfile ConstructCompleteProfile() {
+  AutofillProfile profile(kGuidA, kHttpsOrigin);
+
+  profile.set_use_count(7);
+  profile.set_use_date(base::Time::FromTimeT(1423182152));
+
+  profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("John K. Doe, Jr."));
+  profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  profile.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("K."));
+  profile.SetRawInfo(NAME_LAST, ASCIIToUTF16("Doe"));
+
+  profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("user@example.com"));
+  profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("1.800.555.1234"));
+
+  profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("123 Fake St.\n"
+                                                               "Apt. 42"));
+  EXPECT_EQ(ASCIIToUTF16("123 Fake St."),
+            profile.GetRawInfo(ADDRESS_HOME_LINE1));
+  EXPECT_EQ(ASCIIToUTF16("Apt. 42"), profile.GetRawInfo(ADDRESS_HOME_LINE2));
+
+  profile.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Google, Inc."));
+  profile.SetRawInfo(ADDRESS_HOME_CITY, ASCIIToUTF16("Mountain View"));
+  profile.SetRawInfo(ADDRESS_HOME_STATE, ASCIIToUTF16("California"));
+  profile.SetRawInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("94043"));
+  profile.SetRawInfo(ADDRESS_HOME_COUNTRY, ASCIIToUTF16("US"));
+  profile.SetRawInfo(ADDRESS_HOME_SORTING_CODE, ASCIIToUTF16("CEDEX"));
+  profile.SetRawInfo(ADDRESS_HOME_DEPENDENT_LOCALITY,
+                     ASCIIToUTF16("Santa Clara"));
+  profile.set_language_code("en");
+  profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
+  return profile;
+}
+
+// Returns AutofillProfileSpecifics with all Autofill profile fields set.
+// Contains identical data to the data returned from ConstructCompleteProfile().
+AutofillProfileSpecifics ConstructCompleteSpecifics() {
+  AutofillProfileSpecifics specifics;
+
+  specifics.set_guid(kGuidA);
+  specifics.set_origin(kHttpsOrigin);
+  specifics.set_use_count(7);
+  specifics.set_use_date(1423182152);
+
+  specifics.add_name_first("John");
+  specifics.add_name_middle("K.");
+  specifics.add_name_last("Doe");
+  specifics.add_name_full("John K. Doe, Jr.");
+
+  specifics.add_email_address("user@example.com");
+
+  specifics.add_phone_home_whole_number("1.800.555.1234");
+
+  specifics.set_address_home_line1("123 Fake St.");
+  specifics.set_address_home_line2("Apt. 42");
+  specifics.set_address_home_street_address(
+      "123 Fake St.\n"
+      "Apt. 42");
+
+  specifics.set_company_name("Google, Inc.");
+  specifics.set_address_home_city("Mountain View");
+  specifics.set_address_home_state("California");
+  specifics.set_address_home_zip("94043");
+  specifics.set_address_home_country("US");
+  specifics.set_address_home_sorting_code("CEDEX");
+  specifics.set_address_home_dependent_locality("Santa Clara");
+  specifics.set_address_home_language_code("en");
+  specifics.set_validity_state_bitfield(kValidityStateBitfield);
+
+  return specifics;
+}
+
 }  // namespace
 
 class AutofillProfileSyncBridgeTest : public testing::Test {
@@ -188,6 +287,12 @@
     real_processor_->OnUpdateReceived(state, initial_updates);
   }
 
+  void ApplySyncChanges(const EntityChangeList& changes) {
+    const base::Optional<syncer::ModelError> error = bridge()->ApplySyncChanges(
+        bridge()->CreateMetadataChangeList(), changes);
+    EXPECT_FALSE(error) << error->ToString();
+  }
+
   void AddAutofillProfilesToTable(
       const std::vector<AutofillProfile>& profile_list) {
     for (const auto& profile : profile_list) {
@@ -195,7 +300,7 @@
     }
   }
 
-  std::vector<AutofillProfile> GetAllData() {
+  std::vector<AutofillProfile> GetAllLocalData() {
     std::vector<AutofillProfile> data;
     // Perform an async call synchronously for testing.
     base::RunLoop loop;
@@ -308,6 +413,34 @@
   bridge()->AutofillProfileChanged(change);
 }
 
+// Usage stats should be updated by the client.
+TEST_F(AutofillProfileSyncBridgeTest,
+       AutofillProfileChanged_Updated_UsageStatsOverwrittenByClient) {
+  // Remote data has a profile with usage stats.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.set_address_home_language_code("en");
+  remote.set_use_count(9);
+  remote.set_use_date(25);
+
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(),
+              ElementsAre(WithUsageStats(CreateAutofillProfile(remote))));
+
+  // Update to the usage stats for that profile.
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.set_language_code("en");
+  local.set_use_count(10U);
+  local.set_use_date(base::Time::FromTimeT(30));
+  AutofillProfileChange change(AutofillProfileChange::UPDATE, kGuidA, &local);
+
+  EXPECT_CALL(
+      mock_processor(),
+      Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local)), _));
+
+  bridge()->AutofillProfileChanged(change);
+}
+
 // Server profile updates should be ignored.
 TEST_F(AutofillProfileSyncBridgeTest,
        AutofillProfileChanged_Updated_IgnoreServerProfiles) {
@@ -340,7 +473,7 @@
   local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
   AddAutofillProfilesToTable({local1, local2});
 
-  EXPECT_THAT(GetAllData(), ElementsAre(local1, local2));
+  EXPECT_THAT(GetAllLocalData(), UnorderedElementsAre(local1, local2));
 }
 
 TEST_F(AutofillProfileSyncBridgeTest, GetData) {
@@ -366,6 +499,333 @@
   EXPECT_THAT(data, ElementsAre(local1));
 }
 
+TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData) {
+  AutofillProfile local1 = AutofillProfile(kGuidA, kHttpOrigin);
+  local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  AutofillProfile local2 = AutofillProfile(kGuidB, std::string());
+  local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
+  local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
+  AddAutofillProfilesToTable({local1, local2});
+
+  AutofillProfileSpecifics remote1 =
+      CreateAutofillProfileSpecifics(kGuidC, kHttpsOrigin);
+  remote1.add_name_first("Jane");
+  AutofillProfileSpecifics remote2 =
+      CreateAutofillProfileSpecifics(kGuidD, kSettingsOrigin);
+  remote2.add_name_first("Harry");
+  // This one will have the name and origin updated.
+  AutofillProfileSpecifics remote3 =
+      CreateAutofillProfileSpecifics(kGuidB, kSettingsOrigin);
+  remote3.add_name_first("Tom Doe");
+
+  EXPECT_CALL(
+      mock_processor(),
+      Put(kGuidA, HasSpecifics(CreateAutofillProfileSpecifics(local1)), _));
+  EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0);
+
+  StartSyncing({remote1, remote2, remote3});
+
+  EXPECT_THAT(GetAllLocalData(),
+              UnorderedElementsAre(local1, CreateAutofillProfile(remote1),
+                                   CreateAutofillProfile(remote2),
+                                   CreateAutofillProfile(remote3)));
+}
+
+// Ensure that all profile fields are able to be synced up from the client to
+// the server.
+TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToServer) {
+  AutofillProfile local = ConstructCompleteProfile();
+  AddAutofillProfilesToTable({local});
+
+  // This complete profile is fully uploaded to sync.
+  EXPECT_CALL(mock_processor(),
+              Put(_, HasSpecifics(ConstructCompleteSpecifics()), _));
+  StartSyncing({});
+
+  // No changes locally.
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(WithUsageStats(local)));
+}
+
+// Ensure that all profile fields are able to be synced down from the server to
+// the client (and nothing gets uploaded back).
+TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SyncAllFieldsToClient) {
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({ConstructCompleteSpecifics()});
+
+  EXPECT_THAT(GetAllLocalData(),
+              ElementsAre(WithUsageStats(ConstructCompleteProfile())));
+}
+
+TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_IdenticalProfiles) {
+  AutofillProfile local1 = AutofillProfile(kGuidA, kHttpOrigin);
+  local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  AutofillProfile local2 = AutofillProfile(kGuidB, kSettingsOrigin);
+  local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
+  local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
+  AddAutofillProfilesToTable({local1, local2});
+
+  // The synced profiles are identical to the local ones, except that the guids
+  // are different.
+  AutofillProfileSpecifics remote1 =
+      CreateAutofillProfileSpecifics(kGuidC, kHttpsOrigin);
+  remote1.add_name_first("John");
+  remote1.set_address_home_street_address("1 1st st");
+  AutofillProfileSpecifics remote2 =
+      CreateAutofillProfileSpecifics(kGuidD, kHttpsOrigin);
+  remote2.add_name_first("Tom");
+  remote2.set_address_home_street_address("2 2nd st");
+
+  // Both remote profiles win, only the verified origin is taken over for the
+  // second profile.
+  AutofillProfileSpecifics merged2(remote2);
+  merged2.set_origin(kSettingsOrigin);
+  EXPECT_CALL(mock_processor(), Put(kGuidD, HasSpecifics(merged2), _));
+
+  StartSyncing({remote1, remote2});
+
+  EXPECT_THAT(GetAllLocalData(),
+              UnorderedElementsAre(CreateAutofillProfile(remote1),
+                                   CreateAutofillProfile(merged2)));
+}
+
+TEST_F(AutofillProfileSyncBridgeTest, MergeSyncData_SimilarProfiles) {
+  AutofillProfile local1 = AutofillProfile(kGuidA, kHttpOrigin);
+  local1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  local1.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  local1.set_use_count(27);
+  AutofillProfile local2 = AutofillProfile(kGuidB, kSettingsOrigin);
+  local2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
+  local2.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2nd st"));
+  AddAutofillProfilesToTable({local1, local2});
+
+  // The synced profiles are identical to the local ones, except that the guids
+  // and use_count values are different.
+  AutofillProfileSpecifics remote1 =
+      CreateAutofillProfileSpecifics(kGuidC, kHttpsOrigin);
+  remote1.add_name_first("John");
+  remote1.set_address_home_street_address("1 1st st");
+  remote1.set_company_name("Frobbers, Inc.");
+  remote1.set_use_count(13);
+  AutofillProfileSpecifics remote2 =
+      CreateAutofillProfileSpecifics(kGuidD, kHttpsOrigin);
+  remote2.add_name_first("Tom");
+  remote2.set_address_home_street_address("2 2nd st");
+  remote2.set_company_name("Fizzbang, LLC.");
+  remote2.set_use_count(4);
+
+  // The first profile should have its origin updated.
+  // The second profile should remain as-is, because an unverified profile
+  // should never overwrite a verified one.
+  AutofillProfileSpecifics merged1(remote1);
+  merged1.set_origin(kHttpOrigin);
+  // TODO(jkrcal): This is taken over from the previous test suite without any
+  // reasoning why this happens. This indeed happens, deep in
+  // AutofillProfileComparator when merging profiles both without NAME_FULL, we
+  // obtain a profile with NAME_FULL. Not sure if intended.
+  merged1.add_name_full("John");
+  // Merging two profile takes their max use count.
+  merged1.set_use_count(27);
+
+  // Expect updating the first (merged) profile and adding the second local one.
+  EXPECT_CALL(mock_processor(), Put(kGuidC, HasSpecifics(merged1), _));
+  EXPECT_CALL(
+      mock_processor(),
+      Put(kGuidB, HasSpecifics(CreateAutofillProfileSpecifics(local2)), _));
+  EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0);
+
+  StartSyncing({remote1, remote2});
+
+  EXPECT_THAT(GetAllLocalData(),
+              UnorderedElementsAre(
+                  WithUsageStats(CreateAutofillProfile(merged1)), local2,
+                  WithUsageStats(CreateAutofillProfile(remote2))));
+}
+
+// TODO(jkrcal): All the MergeSimilarProfiles_* tests need some diff in Info to
+// trigger the merge similar code path (we create the diff using phone number).
+// Otherwise, we trigger the merge same code path and none of the tests pass. Is
+// it desired?
+
+// Tests that MergeSimilarProfiles keeps the most recent use date of the two
+// profiles being merged.
+TEST_F(AutofillProfileSyncBridgeTest,
+       MergeSyncData_SimilarProfiles_OlderUseDate) {
+  // Different guids, same origin, difference in the phone number.
+  AutofillProfile local(kGuidA, kHttpOrigin);
+  local.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("650234567"));
+  local.set_use_date(base::Time::FromTimeT(30));
+  AddAutofillProfilesToTable({local});
+
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidB, kHttpOrigin);
+  // |local| has a more recent use date.
+  remote.set_use_date(25);
+
+  // The use date of |local| should replace the use date of |remote|.
+  AutofillProfileSpecifics merged(remote);
+  merged.set_use_date(30);
+  merged.add_phone_home_whole_number("650234567");
+  EXPECT_CALL(mock_processor(), Put(kGuidB, HasSpecifics(merged), _));
+
+  StartSyncing({remote});
+}
+
+// Tests that MergeSimilarProfiles keeps the most recent use date of the two
+// profiles being merged.
+TEST_F(AutofillProfileSyncBridgeTest,
+       MergeSyncData_SimilarProfiles_NewerUseDate) {
+  // Different guids, same origin, difference in the phone number.
+  AutofillProfile local(kGuidA, kHttpOrigin);
+  local.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("650234567"));
+  local.set_use_date(base::Time::FromTimeT(30));
+  AddAutofillProfilesToTable({local});
+
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidB, kHttpOrigin);
+  // |remote| has a more recent use date.
+  remote.set_use_date(35);
+
+  // The use date of |local| should _not_ replace the use date of |remote|.
+  AutofillProfileSpecifics merged(remote);
+  merged.add_phone_home_whole_number("650234567");
+  EXPECT_CALL(mock_processor(), Put(kGuidB, HasSpecifics(merged), _));
+
+  StartSyncing({remote});
+}
+
+// Tests that MergeSimilarProfiles saves the max of the use counts of the two
+// profiles in |remote|.
+TEST_F(AutofillProfileSyncBridgeTest,
+       MergeSyncData_SimilarProfiles_NonZeroUseCounts) {
+  // Different guids, same origin, difference in the phone number.
+  AutofillProfile local(kGuidA, kHttpOrigin);
+  local.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("650234567"));
+  local.set_use_count(12);
+  AddAutofillProfilesToTable({local});
+
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidB, kHttpOrigin);
+  remote.set_use_count(5);
+
+  // The use count of |local| should replace the use count of |remote|.
+  AutofillProfileSpecifics merged(remote);
+  merged.set_use_count(12);
+  merged.add_phone_home_whole_number("650234567");
+  EXPECT_CALL(mock_processor(), Put(kGuidB, HasSpecifics(merged), _));
+
+  StartSyncing({remote});
+}
+
+// Tests that when merging similar profiles for initial sync, we add the
+// additional information of |local| into |remote|.
+TEST_F(AutofillProfileSyncBridgeTest,
+       MergeSyncData_SimilarProfiles_LocalOriginPreserved) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16("650234567"));
+  AddAutofillProfilesToTable({local});
+
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidB, kHttpOrigin);
+  remote.set_address_home_language_code("en");
+
+  // Expect that the resulting merged profile is written back to sync and that
+  // it has the phone number and origin from |local|.
+  AutofillProfileSpecifics merged(remote);
+  merged.set_origin(kHttpsOrigin);
+  merged.add_phone_home_whole_number("650234567");
+  // TODO(jkrcal): Is this expected that language code gets deleted? Not
+  // explicitly covered by previous tests but happens.
+  merged.set_address_home_language_code("");
+  EXPECT_CALL(mock_processor(), Put(kGuidB, HasSpecifics(merged), _));
+
+  StartSyncing({remote});
+}
+
+// Sync data without origin should not overwrite existing origin in local
+// autofill profile.
+TEST_F(AutofillProfileSyncBridgeTest,
+       MergeSyncData_SimilarProfiles_LocalExistingOriginPreserved) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  AddAutofillProfilesToTable({local});
+
+  // Remote data does not have an origin value.
+  AutofillProfileSpecifics remote = CreateAutofillProfileSpecifics(kGuidA, "");
+  remote.clear_origin();
+  remote.add_name_first("John");
+  ASSERT_FALSE(remote.has_origin());
+
+  // Expect no sync events to add origin to the remote data.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+
+  // Expect the local autofill profile to still have an origin after sync.
+  AutofillProfile merged(local);
+  merged.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
+}
+
+// Ensure that no Sync events are generated to fill in missing origins from Sync
+// with explicitly present empty ones. This ensures that the migration to add
+// origins to profiles does not generate lots of needless Sync updates.
+TEST_F(AutofillProfileSyncBridgeTest,
+       MergeSyncData_SimilarProfiles_LocalMissingOriginPreserved) {
+  AutofillProfile local = AutofillProfile(kGuidA, std::string());
+  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  AddAutofillProfilesToTable({local});
+
+  // Create a Sync profile identical to |local|, except with no origin set.
+  AutofillProfileSpecifics remote = CreateAutofillProfileSpecifics(kGuidA, "");
+  remote.clear_origin();
+  remote.add_name_first("John");
+  ASSERT_FALSE(remote.has_origin());
+
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
+}
+
+TEST_F(AutofillProfileSyncBridgeTest, ApplySyncChanges) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpsOrigin);
+  AddAutofillProfilesToTable({local});
+
+  StartSyncing({});
+
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidB, kHttpOrigin);
+  remote.add_name_first("Jane");
+
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0);
+
+  ApplySyncChanges(
+      {EntityChange::CreateDelete(kGuidA),
+       EntityChange::CreateAdd(kGuidB, SpecificsToEntity(remote))});
+
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote)));
+}
+
+// Ensure that entries with invalid specifics are ignored.
+TEST_F(AutofillProfileSyncBridgeTest, ApplySyncChanges_OmitsInvalidSpecifics) {
+  StartSyncing({});
+
+  AutofillProfileSpecifics remote_valid =
+      CreateAutofillProfileSpecifics(kGuidA, std::string());
+  AutofillProfileSpecifics remote_invalid =
+      CreateAutofillProfileSpecifics(kGuidInvalid, std::string());
+
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  ApplySyncChanges(
+      {EntityChange::CreateAdd(kGuidA, SpecificsToEntity(remote_valid)),
+       EntityChange::CreateAdd(kGuidInvalid,
+                               SpecificsToEntity(remote_invalid))});
+
+  EXPECT_THAT(GetAllLocalData(),
+              ElementsAre(CreateAutofillProfile(remote_valid)));
+}
+
 // Verifies that setting the street address field also sets the (deprecated)
 // address line 1 and line 2 fields.
 TEST_F(AutofillProfileSyncBridgeTest, StreetAddress_SplitAutomatically) {
@@ -402,4 +862,363 @@
   EXPECT_FALSE(remote.has_address_home_street_address());
 }
 
+// Ensure that the street address field takes precedence over the (deprecated)
+// address line 1 and line 2 fields, even though these are expected to always be
+// in sync in practice.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_StreetAddress_TakesPrecedenceOverAddressLines) {
+  // Create remote entry with conflicting address data in the street address
+  // field vs. the address line 1 and address line 2 fields.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.set_address_home_line1("123 Example St.");
+  remote.set_address_home_line2("Apt. 42");
+  remote.set_address_home_street_address(
+      "456 El Camino Real\n"
+      "Suite #1337");
+
+  StartSyncing({remote});
+
+  // Verify that full street address takes precedence over address lines.
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
+                   ASCIIToUTF16("456 El Camino Real\n"
+                                "Suite #1337"));
+  local.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("456 El Camino Real"));
+  local.SetRawInfo(ADDRESS_HOME_LINE2, ASCIIToUTF16("Suite #1337"));
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
+}
+
+// Ensure that no Sync events are generated to fill in missing street address
+// fields from Sync with explicitly present ones identical to the data stored in
+// the line1 and line2 fields. This ensures that the migration to add the
+// street address field to profiles does not generate lots of needless Sync
+// updates.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_StreetAddress_NoUpdateToEmptyStreetAddressSyncedUp) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("123 Example St.\n"
+                                                             "Apt. 42"));
+  AddAutofillProfilesToTable({local});
+
+  // Create a Sync profile identical to |profile|, except without street address
+  // explicitly set.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.set_address_home_line1("123 Example St.");
+  remote.set_address_home_line2("Apt. 42");
+
+  // No update to sync, no change in local data.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
+}
+
+// Missing language code field should not generate sync events.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_LanguageCode_MissingCodesNoSync) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  ASSERT_TRUE(local.language_code().empty());
+  AddAutofillProfilesToTable({local});
+
+  // Remote data does not have a language code value.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  ASSERT_FALSE(remote.has_address_home_language_code());
+
+  // No update to sync, no change in local data.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
+}
+
+// Empty language code should be overwritten by sync.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_LanguageCode_ExistingRemoteWinsOverMissingLocal) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  ASSERT_TRUE(local.language_code().empty());
+  AddAutofillProfilesToTable({local});
+
+  // Remote data has "en" language code.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.set_address_home_language_code("en");
+
+  // No update to sync, remote language code overwrites the empty local one.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote)));
+}
+
+// Local language code should be overwritten by remote one.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_LanguageCode_ExistingRemoteWinsOverExistingLocal) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.set_language_code("de");
+  AddAutofillProfilesToTable({local});
+
+  // Remote data has "en" language code.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.set_address_home_language_code("en");
+
+  // No update to sync, remote language code overwrites the local one.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote)));
+}
+
+// Sync data without language code should not overwrite existing language code
+// in local autofill profile.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_LanguageCode_ExistingLocalWinsOverMissingRemote) {
+  // Local autofill profile has "en" language code.
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.set_language_code("en");
+  AddAutofillProfilesToTable({local});
+
+  // Remote data does not have a language code value.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.add_name_first("John");
+  ASSERT_FALSE(remote.has_address_home_language_code());
+
+  // Expect local autofill profile to still have "en" language code after
+  AutofillProfile merged(local);
+  merged.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+
+  // No update to sync, remote language code overwrites the local one.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
+}
+
+// Missing validity state bitifield should not generate sync events.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_ValidityState_DefaultValueNoSync) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  ASSERT_EQ(0, local.GetValidityBitfieldValue());
+  AddAutofillProfilesToTable({local});
+
+  // Remote data does not have a validity state bitfield value.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  ASSERT_FALSE(remote.has_validity_state_bitfield());
+
+  // No update to sync, no change in local data.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
+}
+
+// Default validity state bitfield should be overwritten by sync.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_ValidityState_ExistingRemoteWinsOverMissingLocal) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  ASSERT_EQ(0, local.GetValidityBitfieldValue());
+  AddAutofillProfilesToTable({local});
+
+  // Remote data has a non default validity state bitfield value.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.set_validity_state_bitfield(kValidityStateBitfield);
+  ASSERT_TRUE(remote.has_validity_state_bitfield());
+
+  // No update to sync, the validity bitfield should be stored to local.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote)));
+}
+
+// Local validity state bitfield should be overwritten by sync.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_ValidityState_ExistingRemoteWinsOverExistingLocal) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.SetValidityFromBitfieldValue(kValidityStateBitfield + 1);
+  AddAutofillProfilesToTable({local});
+
+  // Remote data has a non default validity state bitfield value.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.set_validity_state_bitfield(kValidityStateBitfield);
+  ASSERT_TRUE(remote.has_validity_state_bitfield());
+
+  // No update to sync, the remote validity bitfield should overwrite local.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(CreateAutofillProfile(remote)));
+}
+
+// Sync data without a default validity state bitfield should not overwrite
+// an existing validity state bitfield in local autofill profile.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_ValidityState_ExistingLocalWinsOverMissingRemote) {
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.SetValidityFromBitfieldValue(kValidityStateBitfield);
+  AddAutofillProfilesToTable({local});
+
+  // Remote data has a non default validity state bitfield value.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.add_name_first("John");
+  ASSERT_FALSE(remote.has_validity_state_bitfield());
+
+  // Expect local autofill profile to still have the validity state after.
+  AutofillProfile merged(local);
+  merged.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+
+  // No update to sync, the local validity bitfield should stay untouched.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
+}
+
+// Missing full name field should not generate sync events.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_FullName_MissingValueNoSync) {
+  // Local autofill profile has an empty full name.
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  AddAutofillProfilesToTable({local});
+
+  // Remote data does not have a full name value.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.add_name_first(std::string("John"));
+
+  // No update to sync, no change in local data.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
+}
+
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_FullName_ExistingLocalWinsOverMissingRemote) {
+  // Local autofill profile has a full name.
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.SetRawInfo(NAME_FULL, ASCIIToUTF16("John Jacob Smith, Jr"));
+  AddAutofillProfilesToTable({local});
+
+  // Remote data does not have a full name value.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.add_name_first(std::string("John"));
+  remote.add_name_middle(std::string("Jacob"));
+  remote.add_name_last(std::string("Smith"));
+
+  // Expect local autofill profile to still have the same full name after.
+  AutofillProfile merged(local);
+  merged.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  merged.SetRawInfo(NAME_MIDDLE, ASCIIToUTF16("Jacob"));
+  merged.SetRawInfo(NAME_LAST, ASCIIToUTF16("Smith"));
+
+  // No update to sync, no change in local data.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
+}
+
+// Missing use_count/use_date fields should not generate sync events.
+TEST_F(AutofillProfileSyncBridgeTest,
+       RemoteWithSameGuid_UsageStats_MissingValueNoSync) {
+  // Local autofill profile has 0 for use_count/use_date.
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.set_language_code("en");
+  local.set_use_count(0);
+  local.set_use_date(base::Time());
+  AddAutofillProfilesToTable({local});
+
+  // Remote data does not have use_count/use_date.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.clear_use_count();
+  remote.clear_use_date();
+  remote.set_address_home_language_code("en");
+
+  // No update to sync, no change in local data.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(WithUsageStats(local)));
+}
+
+struct UpdatesUsageStatsTestCase {
+  size_t local_use_count;
+  base::Time local_use_date;
+  size_t remote_use_count;
+  int remote_use_date;
+  size_t merged_use_count;
+  base::Time merged_use_date;
+};
+
+class AutofillProfileSyncBridgeUpdatesUsageStatsTest
+    : public AutofillProfileSyncBridgeTest,
+      public testing::WithParamInterface<UpdatesUsageStatsTestCase> {
+ public:
+  AutofillProfileSyncBridgeUpdatesUsageStatsTest() {}
+  ~AutofillProfileSyncBridgeUpdatesUsageStatsTest() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncBridgeUpdatesUsageStatsTest);
+};
+
+TEST_P(AutofillProfileSyncBridgeUpdatesUsageStatsTest, UpdatesUsageStats) {
+  auto test_case = GetParam();
+
+  // Local data has usage stats.
+  AutofillProfile local(kGuidA, kHttpsOrigin);
+  local.set_language_code("en");
+  local.set_use_count(test_case.local_use_count);
+  local.set_use_date(test_case.local_use_date);
+  ASSERT_EQ(test_case.local_use_count, local.use_count());
+  ASSERT_EQ(test_case.local_use_date, local.use_date());
+  AddAutofillProfilesToTable({local});
+
+  // Remote data has usage stats.
+  AutofillProfileSpecifics remote =
+      CreateAutofillProfileSpecifics(kGuidA, kHttpsOrigin);
+  remote.set_address_home_language_code("en");
+  remote.set_use_count(test_case.remote_use_count);
+  remote.set_use_date(test_case.remote_use_date);
+  ASSERT_TRUE(remote.has_use_count());
+  ASSERT_TRUE(remote.has_use_date());
+
+  // Expect the local autofill profile to have usage stats after sync.
+  AutofillProfile merged(local);
+  merged.set_use_count(test_case.merged_use_count);
+  merged.set_use_date(test_case.merged_use_date);
+
+  // Expect no changes to remote data.
+  EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+
+  StartSyncing({remote});
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(WithUsageStats(merged)));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    AutofillProfileSyncBridgeTest,
+    AutofillProfileSyncBridgeUpdatesUsageStatsTest,
+    testing::Values(
+        // Local profile with default stats.
+        UpdatesUsageStatsTestCase{
+            /*local_use_count=*/0U,
+            /*local_use_date=*/base::Time(),
+            /*remote_use_count=*/9U,
+            /*remote_use_date=*/4321,
+            /*merged_use_count=*/9U,
+            /*merged_use_date=*/base::Time::FromTimeT(4321)},
+        // Local profile has older stats than the server.
+        UpdatesUsageStatsTestCase{
+            /*local_use_count=*/3U,
+            /*local_use_date=*/base::Time::FromTimeT(1234),
+            /*remote_use_count=*/9U, /*remote_use_date=*/4321,
+            /*merged_use_count=*/9U,
+            /*merged_use_date=*/base::Time::FromTimeT(4321)},
+        // Local profile has newer stats than the server
+        UpdatesUsageStatsTestCase{
+            /*local_use_count=*/10U,
+            /*local_use_date=*/base::Time::FromTimeT(9999),
+            /*remote_use_count=*/9U, /*remote_use_date=*/4321,
+            /*merged_use_count=*/9U,
+            /*merged_use_date=*/base::Time::FromTimeT(4321)}));
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
new file mode 100644
index 0000000..c5d3a8ee
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.cc
@@ -0,0 +1,296 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_profile_comparator.h"
+#include "components/autofill/core/browser/autofill_profile_sync_util.h"
+#include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/sync/model/model_error.h"
+
+namespace autofill {
+
+using base::Optional;
+using syncer::ModelError;
+
+AutofillProfileSyncDifferenceTracker::AutofillProfileSyncDifferenceTracker(
+    AutofillTable* table)
+    : table_(table) {}
+
+AutofillProfileSyncDifferenceTracker::~AutofillProfileSyncDifferenceTracker() {}
+
+Optional<ModelError>
+AutofillProfileSyncDifferenceTracker::IncorporateRemoteProfile(
+    std::unique_ptr<AutofillProfile> remote) {
+  const std::string remote_storage_key =
+      GetStorageKeyFromAutofillProfile(*remote);
+
+  if (!GetLocalOnlyEntries()) {
+    return ModelError(FROM_HERE, "Failed reading from WebDatabase.");
+  }
+
+  Optional<AutofillProfile> local_with_same_storage_key =
+      ReadEntry(remote_storage_key);
+
+  if (local_with_same_storage_key) {
+    // The remote profile already exists locally with the same key. Update
+    // the local entry with remote data.
+    std::unique_ptr<AutofillProfile> updated =
+        std::make_unique<AutofillProfile>(local_with_same_storage_key.value());
+    // We ignore remote updates to a verified profile because we want to keep
+    // the exact version that the user edited by hand.
+    if (local_with_same_storage_key->IsVerified() && !remote->IsVerified()) {
+      return base::nullopt;
+    }
+    updated->OverwriteDataFrom(*remote);
+    // TODO(jkrcal): if |updated| deviates from |remote|, we should sync it back
+    // up. The only way |updated| can differ is having some extra fields
+    // compared to |remote|. Thus, this cannot lead to an infinite loop of
+    // commits from two clients as each commit decreases the set of empty
+    // fields. This invariant depends on the implementation of
+    // OverwriteDataFrom() and thus should be enforced by a DCHECK.
+
+    if (!updated->EqualsForSyncPurposes(*local_with_same_storage_key)) {
+      // We need to write back locally new changes in this entry.
+      update_to_local_.push_back(std::move(updated));
+    }
+    GetLocalOnlyEntries()->erase(remote_storage_key);
+    return base::nullopt;
+  }
+
+  // Check if profile appears under a different storage key to be de-duplicated.
+  for (const auto& pair : *GetLocalOnlyEntries()) {
+    const std::string& local_storage_key = pair.first;
+    const AutofillProfile& local = *pair.second;
+
+    // Look for exact duplicates, compare only profile contents (and
+    // ignore origin and language code in comparison).
+    if (local.Compare(*remote) == 0) {
+      // We found a duplicate, we keep the new (remote) one and delete the
+      // local one.
+      DVLOG(2)
+          << "[AUTOFILL SYNC] The profile "
+          << base::UTF16ToUTF8(local.GetRawInfo(NAME_FIRST))
+          << base::UTF16ToUTF8(local.GetRawInfo(NAME_LAST))
+          << " already exists with a different storage key; keep the remote key"
+          << remote_storage_key << " and delete the local key "
+          << local_storage_key;
+
+      // Ensure that a verified profile can never revert back to an unverified
+      // one. In such a case, take over the local origin for the new (remote)
+      // entry.
+      if (local.IsVerified() && !remote->IsVerified()) {
+        remote->set_origin(local.origin());
+        // Save a copy of the remote profile also to sync.
+        save_to_sync_.push_back(std::make_unique<AutofillProfile>(*remote));
+      }
+      // Delete the local profile that gets replaced by |remote|.
+      DeleteFromLocal(local_storage_key);
+      break;
+    }
+  }
+
+  add_to_local_.push_back(std::move(remote));
+  return base::nullopt;
+}
+
+Optional<ModelError>
+AutofillProfileSyncDifferenceTracker::IncorporateRemoteDelete(
+    const std::string& storage_key) {
+  DCHECK(!storage_key.empty());
+  DeleteFromLocal(storage_key);
+  return base::nullopt;
+}
+
+Optional<ModelError> AutofillProfileSyncDifferenceTracker::FlushToLocal(
+    base::OnceClosure autofill_changes_callback) {
+  for (const std::string& storage_key : delete_from_local_) {
+    if (!table_->RemoveAutofillProfile(storage_key)) {
+      return ModelError(FROM_HERE, "Failed deleting from WebDatabase");
+    }
+  }
+  for (const std::unique_ptr<AutofillProfile>& entry : add_to_local_) {
+    if (!table_->AddAutofillProfile(*entry)) {
+      return ModelError(FROM_HERE, "Failed updating WebDatabase");
+    }
+  }
+  for (const std::unique_ptr<AutofillProfile>& entry : update_to_local_) {
+    if (!table_->UpdateAutofillProfile(*entry)) {
+      return ModelError(FROM_HERE, "Failed updating WebDatabase");
+    }
+  }
+  if (!delete_from_local_.empty() || !add_to_local_.empty() ||
+      !update_to_local_.empty()) {
+    std::move(autofill_changes_callback).Run();
+  }
+  return base::nullopt;
+}
+
+Optional<ModelError> AutofillProfileSyncDifferenceTracker::FlushToSync(
+    std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync) {
+  for (std::unique_ptr<AutofillProfile>& entry : save_to_sync_) {
+    profiles_to_upload_to_sync->push_back(std::move(entry));
+  }
+  return base::nullopt;
+}
+
+Optional<AutofillProfile> AutofillProfileSyncDifferenceTracker::ReadEntry(
+    const std::string& storage_key) {
+  DCHECK(GetLocalOnlyEntries());
+  auto iter = GetLocalOnlyEntries()->find(storage_key);
+  if (iter != GetLocalOnlyEntries()->end()) {
+    return *iter->second;
+  }
+  return base::nullopt;
+}
+
+void AutofillProfileSyncDifferenceTracker::DeleteFromLocal(
+    const std::string& storage_key) {
+  DCHECK(GetLocalOnlyEntries());
+  delete_from_local_.insert(storage_key);
+  GetLocalOnlyEntries()->erase(storage_key);
+}
+
+std::map<std::string, std::unique_ptr<AutofillProfile>>*
+AutofillProfileSyncDifferenceTracker::GetLocalOnlyEntries() {
+  if (!InitializeLocalOnlyEntriesIfNeeded()) {
+    return nullptr;
+  }
+  return &local_only_entries_;
+}
+
+bool AutofillProfileSyncDifferenceTracker::
+    InitializeLocalOnlyEntriesIfNeeded() {
+  if (local_only_entries_initialized_) {
+    return true;
+  }
+
+  std::vector<std::unique_ptr<AutofillProfile>> entries;
+  if (!table_->GetAutofillProfiles(&entries)) {
+    return false;
+  }
+
+  for (std::unique_ptr<AutofillProfile>& entry : entries) {
+    std::string storage_key = GetStorageKeyFromAutofillProfile(*entry);
+    local_only_entries_[storage_key] = std::move(entry);
+  }
+
+  local_only_entries_initialized_ = true;
+  return true;
+}
+
+AutofillProfileInitialSyncDifferenceTracker::
+    AutofillProfileInitialSyncDifferenceTracker(AutofillTable* table)
+    : AutofillProfileSyncDifferenceTracker(table) {}
+
+AutofillProfileInitialSyncDifferenceTracker::
+    ~AutofillProfileInitialSyncDifferenceTracker() {}
+
+Optional<ModelError>
+AutofillProfileInitialSyncDifferenceTracker::IncorporateRemoteDelete(
+    const std::string& storage_key) {
+  // Remote delete is not allowed in initial sync.
+  NOTREACHED();
+  return base::nullopt;
+}
+
+Optional<ModelError> AutofillProfileInitialSyncDifferenceTracker::FlushToSync(
+    std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync) {
+  // First, flush standard updates to sync.
+  AutofillProfileSyncDifferenceTracker::FlushToSync(profiles_to_upload_to_sync);
+
+  // For initial sync, we additionally need to upload all local only entries.
+  if (!GetLocalOnlyEntries()) {
+    return ModelError(FROM_HERE, "Failed reading from WebDatabase.");
+  }
+  for (auto& pair : *GetLocalOnlyEntries()) {
+    std::string storage_key = pair.first;
+    // No deletions coming from remote are allowed for initial sync.
+    DCHECK(delete_from_local_.count(storage_key) == 0);
+    profiles_to_upload_to_sync->push_back(std::move(pair.second));
+  }
+  return base::nullopt;
+}
+
+Optional<ModelError>
+AutofillProfileInitialSyncDifferenceTracker::MergeSimilarEntriesForInitialSync(
+    const std::string& app_locale) {
+  if (!GetLocalOnlyEntries()) {
+    return ModelError(FROM_HERE, "Failed reading from WebDatabase.");
+  }
+
+  // This merge cannot happen on the fly during IncorporateRemoteSpecifics().
+  // Namely, we do not want to merge a local entry with a _similar_ remote
+  // entry if anoter perfectly fitting remote entry comes later during the
+  // initial sync (a remote entry fits perfectly to a given local entry if
+  // it has fully equal data or even the same storage key). After all the calls
+  // to IncorporateRemoteSpecifics() are over, GetLocalOnlyEntries() only
+  // contains unmatched entries that can be safely merged with similar remote
+  // entries.
+
+  AutofillProfileComparator comparator(app_locale);
+  // Loop over all new remote entries to find merge candidates. Using
+  // non-const reference because we want to update |remote| in place if
+  // needed.
+  for (std::unique_ptr<AutofillProfile>& remote : add_to_local_) {
+    Optional<AutofillProfile> local =
+        FindMergeableLocalEntry(*remote, comparator);
+    if (!local) {
+      continue;
+    }
+
+    DVLOG(2)
+        << "[AUTOFILL SYNC] A similar profile to "
+        << base::UTF16ToUTF8(remote->GetRawInfo(NAME_FIRST))
+        << base::UTF16ToUTF8(remote->GetRawInfo(NAME_LAST))
+        << " already exists with a different storage key; keep the remote key"
+        << GetStorageKeyFromAutofillProfile(*remote)
+        << ", merge local data into it and delete the local key"
+        << GetStorageKeyFromAutofillProfile(*local);
+
+    // For similar profile pairs, the local profile is always removed and its
+    // content merged (if applicable) in the profile that came from sync.
+    AutofillProfile remote_before_merge = *remote;
+    remote->MergeDataFrom(*local, app_locale);
+    if (!remote->EqualsForSyncPurposes(remote_before_merge)) {
+      // We need to sync new changes in the entry back to the server.
+      save_to_sync_.push_back(std::make_unique<AutofillProfile>(*remote));
+      // |remote| is updated in place within |add_to_local_| so the newest
+      // merged version is stored to local.
+    }
+
+    DeleteFromLocal(GetStorageKeyFromAutofillProfile(*local));
+  }
+
+  return base::nullopt;
+}
+
+Optional<AutofillProfile>
+AutofillProfileInitialSyncDifferenceTracker::FindMergeableLocalEntry(
+    const AutofillProfile& remote,
+    const AutofillProfileComparator& comparator) {
+  DCHECK(GetLocalOnlyEntries());
+
+  // Both the remote and the local entry need to be non-verified to be
+  // mergeable.
+  if (remote.IsVerified()) {
+    return base::nullopt;
+  }
+
+  // Check if there is a mergeable local profile.
+  for (const auto& pair : *GetLocalOnlyEntries()) {
+    const AutofillProfile& local_candidate = *pair.second;
+    if (!local_candidate.IsVerified() &&
+        comparator.AreMergeable(local_candidate, remote)) {
+      return local_candidate;
+    }
+  }
+  return base::nullopt;
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h
new file mode 100644
index 0000000..4c7fbf7a
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h
@@ -0,0 +1,139 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNC_DIFFERENCE_TRACKER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNC_DIFFERENCE_TRACKER_H_
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/optional.h"
+
+namespace syncer {
+class ModelError;
+}  // namespace syncer
+
+namespace autofill {
+
+class AutofillProfile;
+class AutofillProfileComparator;
+class AutofillTable;
+
+// This is used to respond to ApplySyncChanges() and MergeSyncData(). Attempts
+// to lazily load local data, and then react to sync data by maintaining
+// internal state until flush calls are made, at which point the applicable
+// modification should be sent towards local and sync directions.
+class AutofillProfileSyncDifferenceTracker {
+ public:
+  explicit AutofillProfileSyncDifferenceTracker(AutofillTable* table);
+  virtual ~AutofillProfileSyncDifferenceTracker();
+
+  // Adds a new |remote| entry to the diff tracker, originating from the sync
+  // server. The provided |remote| entry must be valid.
+  base::Optional<syncer::ModelError> IncorporateRemoteProfile(
+      std::unique_ptr<AutofillProfile> remote);
+
+  // Informs the diff tracker that the entry with |storage_key| has been deleted
+  // from the sync server. |storage_key| must be non-empty.
+  virtual base::Optional<syncer::ModelError> IncorporateRemoteDelete(
+      const std::string& storage_key);
+
+  // Writes all local changes to the provided autofill |table_|. After flushing,
+  // not further remote changes should get incorporated.
+  base::Optional<syncer::ModelError> FlushToLocal(
+      base::OnceClosure autofill_changes_callback);
+
+  // Writes into |profiles_to_upload_to_sync| all autofill profiles to be sent
+  // to the sync server. After flushing, not further remote changes should get
+  // incorporated.
+  virtual base::Optional<syncer::ModelError> FlushToSync(
+      std::vector<std::unique_ptr<AutofillProfile>>*
+          profiles_to_upload_to_sync);
+
+ protected:
+  // If the entry is found, |entry| will be return, otherwise base::nullopt is
+  // returned.
+  base::Optional<AutofillProfile> ReadEntry(const std::string& storage_key);
+
+  // Tries to find a local entry that is mergeable with |remote| (according to
+  // |comparator|). If such an entry is found, it is returned. Otherwise,
+  // base::nullopt is returned.
+  base::Optional<AutofillProfile> FindMergeableLocalEntry(
+      const AutofillProfile& remote,
+      const AutofillProfileComparator& comparator);
+
+  // Informs the tracker that a local entry with |storage_key| should get
+  // deleted.
+  void DeleteFromLocal(const std::string& storage_key);
+
+  // Accessor for data that is only stored local. Initializes the data if
+  // needed. Returns nullptr if initialization failed.
+  std::map<std::string, std::unique_ptr<AutofillProfile>>*
+  GetLocalOnlyEntries();
+
+  // Helper function called by GetLocalOnlyEntries().
+  bool InitializeLocalOnlyEntriesIfNeeded();
+
+  // The table for reading local data.
+  AutofillTable* const table_;
+
+  // This class loads local data from |table_| lazily. This field tracks if that
+  // has happened or not yet.
+  bool local_only_entries_initialized_ = false;
+
+  // We use unique_ptrs for storing AutofillProfile to avoid unnecessary copies.
+
+  // Local data, mapped by storage key. Use unique_to_local() to access it.
+  std::map<std::string, std::unique_ptr<AutofillProfile>> local_only_entries_;
+
+  // Contain changes (originating from sync) that need to be saved to the local
+  // store.
+  std::set<std::string> delete_from_local_;
+  std::vector<std::unique_ptr<AutofillProfile>> add_to_local_;
+  std::vector<std::unique_ptr<AutofillProfile>> update_to_local_;
+
+  // Contains merged data for entries that existed on both sync and local sides
+  // and need to be saved back to sync.
+  std::vector<std::unique_ptr<AutofillProfile>> save_to_sync_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncDifferenceTracker);
+};
+
+class AutofillProfileInitialSyncDifferenceTracker
+    : public AutofillProfileSyncDifferenceTracker {
+ public:
+  explicit AutofillProfileInitialSyncDifferenceTracker(AutofillTable* table);
+  ~AutofillProfileInitialSyncDifferenceTracker() override;
+
+  base::Optional<syncer::ModelError> IncorporateRemoteDelete(
+      const std::string& storage_key) override;
+
+  base::Optional<syncer::ModelError> FlushToSync(
+      std::vector<std::unique_ptr<AutofillProfile>>* profiles_to_upload_to_sync)
+      override;
+
+  // Performs an additional pass through remote entries incorporated from sync
+  // to find any similarities with local entries. Should be run after all
+  // entries get incorporated but before flushing results to local/sync.
+  base::Optional<syncer::ModelError> MergeSimilarEntriesForInitialSync(
+      const std::string& app_locale);
+
+ private:
+  // Returns a local entry that is mergeable with |remote| if it exists.
+  // Otherwise, returns base::nullopt.
+  base::Optional<AutofillProfile> FindMergeableLocalEntry(
+      const AutofillProfile& remote,
+      const AutofillProfileComparator& comparator);
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillProfileInitialSyncDifferenceTracker);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_PROFILE_SYNC_DIFFERENCE_TRACKER_H_
diff --git a/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
new file mode 100644
index 0000000..779ad92
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker_unittest.cc
@@ -0,0 +1,438 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/webdata/autofill_profile_sync_difference_tracker.h"
+
+#include "base/bind_helpers.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/autofill_profile_sync_util.h"
+#include "components/autofill/core/browser/country_names.h"
+#include "components/autofill/core/browser/test_autofill_clock.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/sync/model/model_error.h"
+#include "components/webdata/common/web_database.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+namespace {
+
+using base::ASCIIToUTF16;
+using base::MockCallback;
+using testing::ElementsAre;
+using testing::IsEmpty;
+
+// Some guids for testing.
+const char kGuidA[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44A";
+const char kGuidB[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
+const char kHttpOrigin[] = "http://www.example.com/";
+const char kHttpsOrigin[] = "https://www.example.com/";
+const char kLocaleString[] = "en-US";
+const base::Time kJune2017 = base::Time::FromDoubleT(1497552271);
+
+}  // namespace
+
+class AutofillProfileSyncDifferenceTrackerTestBase : public testing::Test {
+ public:
+  AutofillProfileSyncDifferenceTrackerTestBase() {}
+  ~AutofillProfileSyncDifferenceTrackerTestBase() override {}
+
+  void SetUp() override {
+    // Fix a time for implicitly constructed use_dates in AutofillProfile.
+    test_clock_.SetNow(kJune2017);
+
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    db_.AddTable(&table_);
+    db_.Init(temp_dir_.GetPath().AppendASCII("SyncTestWebDatabase"));
+  }
+
+  void AddAutofillProfilesToTable(
+      const std::vector<AutofillProfile>& profile_list) {
+    for (const auto& profile : profile_list) {
+      table_.AddAutofillProfile(profile);
+    }
+  }
+
+  void IncorporateRemoteProfile(const AutofillProfile& profile) {
+    EXPECT_EQ(base::nullopt, tracker()->IncorporateRemoteProfile(
+                                 std::make_unique<AutofillProfile>(profile)));
+  }
+
+  std::vector<AutofillProfile> FlushAndReturnProfilesToUploadToSync() {
+    EXPECT_EQ(base::nullopt,
+              tracker()->FlushToLocal(
+                  /*autofill_changes_callback=*/base::DoNothing()));
+
+    std::vector<std::unique_ptr<AutofillProfile>> vector_of_unique_ptrs;
+    EXPECT_EQ(base::nullopt,
+              tracker()->FlushToSync(
+                  /*profiles_to_upload_to_sync=*/&vector_of_unique_ptrs));
+
+    // Copy all the elements by value so that we have a vector that is easier to
+    // work with in the test.
+    std::vector<AutofillProfile> vector_of_values;
+    for (const std::unique_ptr<AutofillProfile>& entry :
+         vector_of_unique_ptrs) {
+      vector_of_values.push_back(*entry);
+    }
+    return vector_of_values;
+  }
+
+  std::vector<AutofillProfile> GetAllLocalData() {
+    std::vector<std::unique_ptr<AutofillProfile>> vector_of_unique_ptrs;
+    // Meant as an assertion but I cannot use ASSERT_TRUE in non-void function.
+    EXPECT_TRUE(table()->GetAutofillProfiles(&vector_of_unique_ptrs));
+
+    // Copy all the elements by value so that we have a vector that is easier to
+    // work with in the test.
+    std::vector<AutofillProfile> local_data;
+    for (const std::unique_ptr<AutofillProfile>& entry :
+         vector_of_unique_ptrs) {
+      local_data.push_back(*entry);
+    }
+    return local_data;
+  }
+
+  virtual AutofillProfileSyncDifferenceTracker* tracker() = 0;
+
+  AutofillTable* table() { return &table_; }
+
+ private:
+  autofill::TestAutofillClock test_clock_;
+  base::ScopedTempDir temp_dir_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  AutofillTable table_;
+  WebDatabase db_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncDifferenceTrackerTestBase);
+};
+
+class AutofillProfileSyncDifferenceTrackerTest
+    : public AutofillProfileSyncDifferenceTrackerTestBase {
+ public:
+  AutofillProfileSyncDifferenceTrackerTest() : tracker_(table()) {}
+  ~AutofillProfileSyncDifferenceTrackerTest() override {}
+
+  AutofillProfileSyncDifferenceTracker* tracker() override { return &tracker_; }
+
+ private:
+  AutofillProfileSyncDifferenceTracker tracker_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillProfileSyncDifferenceTrackerTest);
+};
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       IncorporateRemoteProfileShouldOverwriteProfileWithSameKey) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
+  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile is completely different but it has the same key.
+  AutofillProfile remote = AutofillProfile(kGuidA, kHttpsOrigin);
+  remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
+
+  IncorporateRemoteProfile(remote);
+
+  // Nothing gets uploaded to sync and the remote profile wins.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
+}
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       IncorporateRemoteProfileShouldOverwriteUnverifiedProfileByVerified) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpsOrigin);
+  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile has the same key but it is not verified.
+  AutofillProfile remote = AutofillProfile(kGuidA, kSettingsOrigin);
+  remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
+
+  IncorporateRemoteProfile(remote);
+
+  // Nothing gets uploaded to sync and the local profile wins.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
+}
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       IncorporateRemoteProfileShouldNotOverwriteVerifiedProfileByUnverified) {
+  AutofillProfile local = AutofillProfile(kGuidA, kSettingsOrigin);
+  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile has the same key but it is not verified.
+  AutofillProfile remote = AutofillProfile(kGuidA, kHttpsOrigin);
+  remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Tom"));
+
+  IncorporateRemoteProfile(remote);
+
+  // Nothing gets uploaded to sync and the local profile wins.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local));
+}
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       IncorporateRemoteProfileShouldNotOverwriteFullNameByEmptyString) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
+  local.SetRawInfo(NAME_FULL, ASCIIToUTF16("John"));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile has the same key.
+  AutofillProfile remote = AutofillProfile(kGuidA, kHttpsOrigin);
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2st st"));
+
+  AutofillProfile merged(remote);
+  merged.SetRawInfo(NAME_FULL, ASCIIToUTF16("John"));
+
+  IncorporateRemoteProfile(remote);
+
+  // Nothing gets uploaded to sync and the remote profile wins except for the
+  // full name.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
+}
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       IncorporateRemoteProfileShouldMergeIdenticalProfilesWithDifferentKeys) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
+  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile is identical to the local one, except that the guids and
+  // origins are different.
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpsOrigin);
+  remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+
+  IncorporateRemoteProfile(remote);
+
+  // Nothing gets uploaded to sync and the remote profile wins.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
+}
+
+TEST_F(
+    AutofillProfileSyncDifferenceTrackerTest,
+    IncorporateRemoteProfileShouldMergeIdenticalProfilesWithDifferentKeysButKeepVerifiedOrigin) {
+  AutofillProfile local = AutofillProfile(kGuidA, kSettingsOrigin);
+  local.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile has the same key.
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpsOrigin);
+  remote.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+
+  AutofillProfile merged(remote);
+  merged.set_origin(kSettingsOrigin);
+
+  IncorporateRemoteProfile(remote);
+
+  // Nothing gets uploaded to sync and the remote profile wins except for the
+  // full name.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(merged));
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
+}
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       FlushToLocalShouldNotCallbackWhenNotNeeded) {
+  MockCallback<base::OnceClosure> autofill_changes_callback;
+
+  EXPECT_CALL(autofill_changes_callback, Run()).Times(0);
+  EXPECT_EQ(base::nullopt,
+            tracker()->FlushToLocal(autofill_changes_callback.Get()));
+}
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       FlushToLocalShouldCallbackWhenProfileDeleted) {
+  AutofillProfile local = AutofillProfile(kGuidA, kSettingsOrigin);
+  AddAutofillProfilesToTable({local});
+
+  tracker()->IncorporateRemoteDelete(kGuidA);
+
+  MockCallback<base::OnceClosure> autofill_changes_callback;
+  EXPECT_CALL(autofill_changes_callback, Run()).Times(1);
+  EXPECT_EQ(base::nullopt,
+            tracker()->FlushToLocal(autofill_changes_callback.Get()));
+
+  // On top of that, the profile should also get deleted.
+  EXPECT_THAT(GetAllLocalData(), IsEmpty());
+}
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       FlushToLocalShouldCallbackWhenProfileAdded) {
+  AutofillProfile remote = AutofillProfile(kGuidA, kSettingsOrigin);
+  IncorporateRemoteProfile(remote);
+
+  MockCallback<base::OnceClosure> autofill_changes_callback;
+  EXPECT_CALL(autofill_changes_callback, Run()).Times(1);
+  EXPECT_EQ(base::nullopt,
+            tracker()->FlushToLocal(autofill_changes_callback.Get()));
+
+  // On top of that, the profile should also get added.
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
+}
+
+TEST_F(AutofillProfileSyncDifferenceTrackerTest,
+       FlushToLocalShouldCallbackWhenProfileUpdated) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpsOrigin);
+  AddAutofillProfilesToTable({local});
+
+  AutofillProfile remote = AutofillProfile(kGuidA, kHttpsOrigin);
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  IncorporateRemoteProfile(remote);
+
+  MockCallback<base::OnceClosure> autofill_changes_callback;
+  EXPECT_CALL(autofill_changes_callback, Run()).Times(1);
+  EXPECT_EQ(base::nullopt,
+            tracker()->FlushToLocal(autofill_changes_callback.Get()));
+
+  // On top of that, the profile with key kGuidA should also get updated.
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
+}
+
+class AutofillProfileInitialSyncDifferenceTrackerTest
+    : public AutofillProfileSyncDifferenceTrackerTestBase {
+ public:
+  AutofillProfileInitialSyncDifferenceTrackerTest()
+      : initial_tracker_(table()) {}
+  ~AutofillProfileInitialSyncDifferenceTrackerTest() override {}
+
+  void MergeSimilarEntriesForInitialSync() {
+    initial_tracker_.MergeSimilarEntriesForInitialSync(kLocaleString);
+  }
+
+  AutofillProfileSyncDifferenceTracker* tracker() override {
+    return &initial_tracker_;
+  }
+
+ private:
+  AutofillProfileInitialSyncDifferenceTracker initial_tracker_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillProfileInitialSyncDifferenceTrackerTest);
+};
+
+TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
+       MergeSimilarEntriesForInitialSyncShouldSyncUpChanges) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  local.set_use_count(27);
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile matches the local one (except for origin and use count).
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpsOrigin);
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
+  remote.set_use_count(13);
+
+  // The remote profile wins (as regards the storage key).
+  AutofillProfile merged(remote);
+  // The local origin wins when merging.
+  merged.set_origin(kHttpOrigin);
+  // Merging two profile takes their max use count.
+  merged.set_use_count(27);
+
+  IncorporateRemoteProfile(remote);
+  MergeSimilarEntriesForInitialSync();
+
+  // The merged profile needs to get uploaded back to sync and stored locally.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(merged));
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(merged));
+}
+
+TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
+       MergeSimilarEntriesForInitialSyncShouldNotSyncUpWhenNotNeeded) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  local.set_use_count(13);
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile matches the local one and has some additional data.
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpOrigin);
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
+  // Merging two profile takes their max use count, so use count of 27 is taken.
+  remote.set_use_count(27);
+
+  IncorporateRemoteProfile(remote);
+  MergeSimilarEntriesForInitialSync();
+
+  // Nothing gets uploaded to sync and the remote profile wins.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), IsEmpty());
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(remote));
+}
+
+TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
+       MergeSimilarEntriesForInitialSyncNotMatchNonsimilarEntries) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  local.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile has a different street address.
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpOrigin);
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("2 2st st"));
+  remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
+
+  IncorporateRemoteProfile(remote);
+  MergeSimilarEntriesForInitialSync();
+
+  // The local profile gets uploaded (due to initial sync) and the remote
+  // profile gets stored locally.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(local));
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local, remote));
+}
+
+TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
+       MergeSimilarEntriesForInitialSyncDoesNotMatchLocalVerifiedEntry) {
+  // The local entry is verified, should not get merged.
+  AutofillProfile local = AutofillProfile(kGuidA, kSettingsOrigin);
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile is similar to the local one.
+  AutofillProfile remote = AutofillProfile(kGuidB, kHttpOrigin);
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
+
+  IncorporateRemoteProfile(remote);
+  MergeSimilarEntriesForInitialSync();
+
+  // The local profile gets uploaded (due to initial sync) and the remote
+  // profile gets stored locally.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(local));
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local, remote));
+}
+
+TEST_F(AutofillProfileInitialSyncDifferenceTrackerTest,
+       MergeSimilarEntriesForInitialSyncDoesNotMatchRemoteVerifiedEntry) {
+  AutofillProfile local = AutofillProfile(kGuidA, kHttpOrigin);
+  local.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  AddAutofillProfilesToTable({local});
+
+  // The remote profile is similar to the local one but is verified and thus it
+  // should not get merged.
+  AutofillProfile remote = AutofillProfile(kGuidB, kSettingsOrigin);
+  remote.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, ASCIIToUTF16("1 1st st"));
+  remote.SetRawInfo(COMPANY_NAME, ASCIIToUTF16("Frobbers, Inc."));
+
+  IncorporateRemoteProfile(remote);
+  MergeSimilarEntriesForInitialSync();
+
+  // The local profile gets uploaded (due to initial sync) and the remote
+  // profile gets stored locally.
+  EXPECT_THAT(FlushAndReturnProfilesToUploadToSync(), ElementsAre(local));
+  EXPECT_THAT(GetAllLocalData(), ElementsAre(local, remote));
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc
index ed798d9..9fc16b1 100644
--- a/components/autofill/core/common/password_form.cc
+++ b/components/autofill/core/common/password_form.cc
@@ -76,6 +76,8 @@
   submission_event_string_stream << form.submission_event;
   target->SetString("submission_event", submission_event_string_stream.str());
   target->SetBoolean("only_for_fallback_saving", form.only_for_fallback_saving);
+  target->SetBoolean("is_gaia_with_skip_save_password_form",
+                     form.is_gaia_with_skip_save_password_form);
 }
 
 }  // namespace
@@ -98,7 +100,8 @@
       is_public_suffix_match(false),
       is_affiliation_based_match(false),
       submission_event(SubmissionIndicatorEvent::NONE),
-      only_for_fallback_saving(false) {}
+      only_for_fallback_saving(false),
+      is_gaia_with_skip_save_password_form(false) {}
 
 PasswordForm::PasswordForm(const PasswordForm& other) = default;
 
@@ -156,7 +159,9 @@
          app_display_name == form.app_display_name &&
          app_icon_url == form.app_icon_url &&
          submission_event == form.submission_event &&
-         only_for_fallback_saving == form.only_for_fallback_saving;
+         only_for_fallback_saving == form.only_for_fallback_saving &&
+         is_gaia_with_skip_save_password_form ==
+             form.is_gaia_with_skip_save_password_form;
 }
 
 bool PasswordForm::operator!=(const PasswordForm& form) const {
diff --git a/components/autofill/core/common/password_form.h b/components/autofill/core/common/password_form.h
index 6a3d00e..b3d9b14 100644
--- a/components/autofill/core/common/password_form.h
+++ b/components/autofill/core/common/password_form.h
@@ -342,6 +342,9 @@
   // fields were found). But this form can be saved only with the fallback.
   bool only_for_fallback_saving;
 
+  // True iff this is Gaia form which should be skipped on saving.
+  bool is_gaia_with_skip_save_password_form;
+
   // Return true if we consider this form to be a change password form.
   // We use only client heuristics, so it could include signup forms.
   bool IsPossibleChangePasswordForm() const;
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index 3a529438b..cea0375 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -153,10 +153,6 @@
     Scan new card
   </message>
 
-  <message name="IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE" desc="Text shown as the title of the suggestion drop down when a password field is clicked.">
-    Use password for:
-  </message>
-
   <if expr="not use_titlecase">
   <message name="IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK" desc="The text shown as an option in the suggestion drop down when a password field is clicked">
     Show all saved passwords
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
index 91c48456..f941c9a 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
@@ -32,8 +32,9 @@
     static final int BACKGROUND_TASK_WEBAPK_UPDATE = 12;
     static final int BACKGROUND_TASK_DOWNLOAD_RESUMPTION = 13;
     static final int BACKGROUND_TASK_FEED_REFRESH = 14;
+    static final int BACKGROUND_TASK_COMPONENT_UPDATE = 15;
     // Keep this one at the end and increment appropriately when adding new tasks.
-    static final int BACKGROUND_TASK_COUNT = 15;
+    static final int BACKGROUND_TASK_COUNT = 16;
 
     static final String KEY_CACHED_UMA = "bts_cached_uma";
 
@@ -250,6 +251,8 @@
                 return BACKGROUND_TASK_DOWNLOAD_RESUMPTION;
             case TaskIds.FEED_REFRESH_JOB_ID:
                 return BACKGROUND_TASK_FEED_REFRESH;
+            case TaskIds.COMPONENT_UPDATE_JOB_ID:
+                return BACKGROUND_TASK_COMPONENT_UPDATE;
             default:
                 assert false;
         }
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java
index 4210211..9257fba 100644
--- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java
+++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java
@@ -27,6 +27,7 @@
     public static final int WEBAPK_UPDATE_JOB_ID = 91;
     public static final int DOWNLOAD_RESUMPTION_JOB_ID = 55;
     public static final int FEED_REFRESH_JOB_ID = 22;
+    public static final int COMPONENT_UPDATE_JOB_ID = 2;
 
     private TaskIds() {}
 }
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
index caa0465c..2dab5b2 100644
--- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
+++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
@@ -84,7 +84,10 @@
                         TaskIds.DOWNLOAD_RESUMPTION_JOB_ID));
         assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_FEED_REFRESH,
                 BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId(TaskIds.FEED_REFRESH_JOB_ID));
-        assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COUNT, 15);
+        assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COMPONENT_UPDATE,
+                BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId(
+                        TaskIds.COMPONENT_UPDATE_JOB_ID));
+        assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COUNT, 16);
     }
 
     @Test
diff --git a/components/consent_auditor/consent_auditor.cc b/components/consent_auditor/consent_auditor.cc
index 3dbb22b..678f169 100644
--- a/components/consent_auditor/consent_auditor.cc
+++ b/components/consent_auditor/consent_auditor.cc
@@ -90,11 +90,12 @@
       user_event_service_(user_event_service),
       app_version_(app_version),
       app_locale_(app_locale) {
-  DCHECK(!IsSeparateConsentTypeEnabled() || consent_sync_bridge_);
+  if (IsSeparateConsentTypeEnabled()) {
+    DCHECK(consent_sync_bridge_);
+  } else {
+    DCHECK(user_event_service_);
+  }
   DCHECK(pref_service_);
-  // TODO(vitaliii): Don't require user_event_service when the separate datatype
-  // is enabled.
-  DCHECK(user_event_service_);
 }
 
 ConsentAuditor::~ConsentAuditor() {}
diff --git a/components/cryptauth/BUILD.gn b/components/cryptauth/BUILD.gn
index fd210f0..21b14b6e 100644
--- a/components/cryptauth/BUILD.gn
+++ b/components/cryptauth/BUILD.gn
@@ -16,9 +16,6 @@
     "background_eid_generator.h",
     "connection.cc",
     "connection.h",
-    "cryptauth_access_token_fetcher.h",
-    "cryptauth_access_token_fetcher_impl.cc",
-    "cryptauth_access_token_fetcher_impl.h",
     "cryptauth_api_call_flow.cc",
     "cryptauth_api_call_flow.h",
     "cryptauth_client.h",
@@ -112,6 +109,7 @@
     "//crypto",
     "//google_apis",
     "//net",
+    "//services/identity/public/cpp",
   ]
 
   public_deps = [
@@ -185,7 +183,6 @@
   sources = [
     "background_eid_generator_unittest.cc",
     "connection_unittest.cc",
-    "cryptauth_access_token_fetcher_impl_unittest.cc",
     "cryptauth_api_call_flow_unittest.cc",
     "cryptauth_client_impl_unittest.cc",
     "cryptauth_device_manager_impl_unittest.cc",
@@ -220,6 +217,7 @@
     "//components/prefs:test_support",
     "//google_apis:test_support",
     "//net:test_support",
+    "//services/identity/public/cpp:test_support",
     "//testing/gtest",
   ]
 }
diff --git a/components/cryptauth/DEPS b/components/cryptauth/DEPS
index 0779a592f..2193bca9 100644
--- a/components/cryptauth/DEPS
+++ b/components/cryptauth/DEPS
@@ -12,5 +12,6 @@
   "+device/bluetooth",
   "+google_apis",
   "+net",
+  "+services/identity/public/cpp",
   "+third_party/cros_system_api/dbus/service_constants.h",
 ]
diff --git a/components/cryptauth/cryptauth_access_token_fetcher.h b/components/cryptauth/cryptauth_access_token_fetcher.h
deleted file mode 100644
index d79e7bd..0000000
--- a/components/cryptauth/cryptauth_access_token_fetcher.h
+++ /dev/null
@@ -1,30 +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 COMPONENTS_CRYPTAUTH_CRYPTAUTH_ACCESS_TOKEN_FETCHER_H_
-#define COMPONENTS_CRYPTAUTH_CRYPTAUTH_ACCESS_TOKEN_FETCHER_H_
-
-#include <string>
-
-#include "base/callback_forward.h"
-
-namespace cryptauth {
-
-// Simple interface for fetching the OAuth2 access token that authorizes
-// CryptAuth API calls. Do not reuse this after calling FetchAccessToken();
-// instead, create a new instance.
-class CryptAuthAccessTokenFetcher {
- public:
-  virtual ~CryptAuthAccessTokenFetcher() {}
-
-  // Fetches the access token asynchronously, invoking the callback upon
-  // completion. If the fetch fails, the callback will be invoked with an empty
-  // string.
-  typedef base::Callback<void(const std::string&)> AccessTokenCallback;
-  virtual void FetchAccessToken(const AccessTokenCallback& callback) = 0;
-};
-
-}  // namespace cryptauth
-
-#endif  // COMPONENTS_CRYPTAUTH_CRYPTAUTH_ACCESS_TOKEN_FETCHER_H_
diff --git a/components/cryptauth/cryptauth_access_token_fetcher_impl.cc b/components/cryptauth/cryptauth_access_token_fetcher_impl.cc
deleted file mode 100644
index f9ba926..0000000
--- a/components/cryptauth/cryptauth_access_token_fetcher_impl.cc
+++ /dev/null
@@ -1,60 +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 "components/cryptauth/cryptauth_access_token_fetcher_impl.h"
-
-namespace cryptauth {
-
-namespace {
-
-// Returns the set of OAuth2 scopes that CryptAuth uses.
-OAuth2TokenService::ScopeSet GetScopes() {
-  OAuth2TokenService::ScopeSet scopes;
-  scopes.insert("https://www.googleapis.com/auth/cryptauth");
-  return scopes;
-}
-
-}  // namespace
-
-CryptAuthAccessTokenFetcherImpl::CryptAuthAccessTokenFetcherImpl(
-    OAuth2TokenService* token_service,
-    const std::string& account_id)
-    : OAuth2TokenService::Consumer("cryptauth_access_token_fetcher"),
-      token_service_(token_service),
-      account_id_(account_id),
-      fetch_started_(false) {
-}
-
-CryptAuthAccessTokenFetcherImpl::~CryptAuthAccessTokenFetcherImpl() {
-}
-
-void CryptAuthAccessTokenFetcherImpl::FetchAccessToken(
-    const AccessTokenCallback& callback) {
-  if (fetch_started_) {
-    LOG(WARNING) << "Create an instance for each token fetched. Do not reuse.";
-    callback.Run(std::string());
-    return;
-  }
-
-  fetch_started_ = true;
-  callback_ = callback;
-  // This request will return a cached result if it is available, saving a
-  // network round trip every time we fetch the access token.
-  token_request_ = token_service_->StartRequest(account_id_, GetScopes(), this);
-}
-
-void CryptAuthAccessTokenFetcherImpl::OnGetTokenSuccess(
-    const OAuth2TokenService::Request* request,
-    const std::string& access_token,
-    const base::Time& expiration_time) {
-  callback_.Run(access_token);
-}
-
-void CryptAuthAccessTokenFetcherImpl::OnGetTokenFailure(
-    const OAuth2TokenService::Request* request,
-    const GoogleServiceAuthError& error) {
-  callback_.Run(std::string());
-}
-
-}  // namespace cryptauth
diff --git a/components/cryptauth/cryptauth_access_token_fetcher_impl.h b/components/cryptauth/cryptauth_access_token_fetcher_impl.h
deleted file mode 100644
index f683b54..0000000
--- a/components/cryptauth/cryptauth_access_token_fetcher_impl.h
+++ /dev/null
@@ -1,59 +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 COMPONENTS_CRYPTAUTH_CRYPTAUTH_ACCESS_TOKEN_FETCHER_IMPL_H_
-#define COMPONENTS_CRYPTAUTH_CRYPTAUTH_ACCESS_TOKEN_FETCHER_IMPL_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "components/cryptauth/cryptauth_access_token_fetcher.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-
-namespace cryptauth {
-
-// Implementation of CryptAuthAccessTokenFetcher fetching an access token for a
-// given account using the provided OAuth2TokenService.
-class CryptAuthAccessTokenFetcherImpl : public CryptAuthAccessTokenFetcher,
-                                        public OAuth2TokenService::Consumer {
- public:
-  // |token_service| is not owned, and must outlive this object.
-  CryptAuthAccessTokenFetcherImpl(OAuth2TokenService* token_service,
-                                  const std::string& account_id);
-  ~CryptAuthAccessTokenFetcherImpl() override;
-
-  // CryptAuthAccessTokenFetcher:
-  void FetchAccessToken(const AccessTokenCallback& callback) override;
-
- private:
-  // OAuth2TokenService::Consumer:
-  void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
-                         const std::string& access_token,
-                         const base::Time& expiration_time) override;
-  void OnGetTokenFailure(const OAuth2TokenService::Request* request,
-                         const GoogleServiceAuthError& error) override;
-
-  // System service that caches and fetches tokens for a given account.
-  // Not owned.
-  OAuth2TokenService* token_service_;
-
-  // The account id for whom to mint the token.
-  std::string account_id_;
-
-  // True if FetchAccessToken() has been called.
-  bool fetch_started_;
-
-  // Stores the request from |token_service_| to mint the token.
-  std::unique_ptr<OAuth2TokenService::Request> token_request_;
-
-  // Callback to invoke when the token fetch succeeds or fails.
-  AccessTokenCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(CryptAuthAccessTokenFetcherImpl);
-};
-
-}  // namespace cryptauth
-
-#endif  // COMPONENTS_CRYPTAUTH_CRYPTAUTH_ACCESS_TOKEN_FETCHER_IMPL_H_
diff --git a/components/cryptauth/cryptauth_access_token_fetcher_impl_unittest.cc b/components/cryptauth/cryptauth_access_token_fetcher_impl_unittest.cc
deleted file mode 100644
index 3e72c23..0000000
--- a/components/cryptauth/cryptauth_access_token_fetcher_impl_unittest.cc
+++ /dev/null
@@ -1,76 +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 "components/cryptauth/cryptauth_access_token_fetcher_impl.h"
-
-#include <string>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "google_apis/gaia/fake_oauth2_token_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cryptauth {
-
-namespace {
-
-const char kAccountId[] = "account_id";
-const char kAccessToken[] = "access_token";
-const char kInvalidResult[] = "invalid_result";
-
-// Callback that saves the fetched access token to the first argument.
-void SaveAccessToken(std::string* out_token, const std::string& in_token) {
-  *out_token = in_token;
-}
-
-}  // namespace
-
-class CryptAuthAccessTokenFetcherTest : public testing::Test {
- protected:
-  CryptAuthAccessTokenFetcherTest()
-      : fetcher_(&token_service_, kAccountId) {
-    token_service_.AddAccount(kAccountId);
-  }
-
-  FakeOAuth2TokenService token_service_;
-  CryptAuthAccessTokenFetcherImpl fetcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(CryptAuthAccessTokenFetcherTest);
-};
-
-TEST_F(CryptAuthAccessTokenFetcherTest, FetchSuccess) {
-  std::string result;
-  fetcher_.FetchAccessToken(base::Bind(SaveAccessToken, &result));
-  token_service_.IssueAllTokensForAccount(kAccountId, kAccessToken,
-                                          base::Time::Max());
-
-  EXPECT_EQ(kAccessToken, result);
-}
-
-TEST_F(CryptAuthAccessTokenFetcherTest, FetchFailure) {
-  std::string result(kInvalidResult);
-  fetcher_.FetchAccessToken(base::Bind(SaveAccessToken, &result));
-  token_service_.IssueErrorForAllPendingRequestsForAccount(
-      kAccountId,
-      GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR));
-
-  EXPECT_EQ(std::string(), result);
-}
-
-TEST_F(CryptAuthAccessTokenFetcherTest, FetcherReuse) {
-  std::string result1;
-  fetcher_.FetchAccessToken(base::Bind(SaveAccessToken, &result1));
-
-  {
-    std::string result2(kInvalidResult);
-    fetcher_.FetchAccessToken(base::Bind(SaveAccessToken, &result2));
-    EXPECT_EQ(std::string(), result2);
-  }
-
-  token_service_.IssueAllTokensForAccount(kAccountId, kAccessToken,
-                                          base::Time::Max());
-  EXPECT_EQ(kAccessToken, result1);
-}
-
-}  // namespace cryptauth
diff --git a/components/cryptauth/cryptauth_client_impl.cc b/components/cryptauth/cryptauth_client_impl.cc
index f16b4a2..19f7e0e6 100644
--- a/components/cryptauth/cryptauth_client_impl.cc
+++ b/components/cryptauth/cryptauth_client_impl.cc
@@ -10,8 +10,9 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
-#include "components/cryptauth/cryptauth_access_token_fetcher_impl.h"
 #include "components/cryptauth/switches.h"
+#include "services/identity/public/cpp/identity_manager.h"
+#include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
 
 namespace cryptauth {
 
@@ -53,11 +54,11 @@
 
 CryptAuthClientImpl::CryptAuthClientImpl(
     std::unique_ptr<CryptAuthApiCallFlow> api_call_flow,
-    std::unique_ptr<CryptAuthAccessTokenFetcher> access_token_fetcher,
+    identity::IdentityManager* identity_manager,
     scoped_refptr<net::URLRequestContextGetter> url_request_context,
     const DeviceClassifier& device_classifier)
     : api_call_flow_(std::move(api_call_flow)),
-      access_token_fetcher_(std::move(access_token_fetcher)),
+      identity_manager_(identity_manager),
       url_request_context_(url_request_context),
       device_classifier_(device_classifier),
       has_call_started_(false),
@@ -277,17 +278,29 @@
 
   request_path_ = request_path;
   error_callback_ = error_callback;
-  access_token_fetcher_->FetchAccessToken(base::Bind(
-      &CryptAuthClientImpl::OnAccessTokenFetched<ResponseProto>,
-      weak_ptr_factory_.GetWeakPtr(), serialized_request, response_callback));
+
+  OAuth2TokenService::ScopeSet scopes;
+  scopes.insert("https://www.googleapis.com/auth/cryptauth");
+
+  access_token_fetcher_ =
+      identity_manager_->CreateAccessTokenFetcherForPrimaryAccount(
+          "cryptauth_client", scopes,
+          base::BindOnce(
+              &CryptAuthClientImpl::OnAccessTokenFetched<ResponseProto>,
+              weak_ptr_factory_.GetWeakPtr(), serialized_request,
+              response_callback),
+          identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
 }
 
 template <class ResponseProto>
 void CryptAuthClientImpl::OnAccessTokenFetched(
     const std::string& serialized_request,
     const base::Callback<void(const ResponseProto&)>& response_callback,
-    const std::string& access_token) {
-  if (access_token.empty()) {
+    GoogleServiceAuthError error,
+    std::string access_token) {
+  access_token_fetcher_.reset();
+
+  if (error.state() != GoogleServiceAuthError::NONE) {
     OnApiCallFailed("Failed to get a valid access token.");
     return;
   }
@@ -320,24 +333,19 @@
 
 // CryptAuthClientFactoryImpl
 CryptAuthClientFactoryImpl::CryptAuthClientFactoryImpl(
-    OAuth2TokenService* token_service,
-    const std::string& account_id,
+    identity::IdentityManager* identity_manager,
     scoped_refptr<net::URLRequestContextGetter> url_request_context,
     const DeviceClassifier& device_classifier)
-    : token_service_(token_service),
-      account_id_(account_id),
+    : identity_manager_(identity_manager),
       url_request_context_(url_request_context),
-      device_classifier_(device_classifier) {
-}
+      device_classifier_(device_classifier) {}
 
 CryptAuthClientFactoryImpl::~CryptAuthClientFactoryImpl() {
 }
 
 std::unique_ptr<CryptAuthClient> CryptAuthClientFactoryImpl::CreateInstance() {
   return std::make_unique<CryptAuthClientImpl>(
-      base::WrapUnique(new CryptAuthApiCallFlow()),
-      base::WrapUnique(
-          new CryptAuthAccessTokenFetcherImpl(token_service_, account_id_)),
+      base::WrapUnique(new CryptAuthApiCallFlow()), identity_manager_,
       url_request_context_, device_classifier_);
 }
 
diff --git a/components/cryptauth/cryptauth_client_impl.h b/components/cryptauth/cryptauth_client_impl.h
index 3ccea85..b054edc 100644
--- a/components/cryptauth/cryptauth_client_impl.h
+++ b/components/cryptauth/cryptauth_client_impl.h
@@ -7,14 +7,17 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "components/cryptauth/cryptauth_access_token_fetcher.h"
 #include "components/cryptauth/cryptauth_api_call_flow.h"
 #include "components/cryptauth/cryptauth_client.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context_getter.h"
 
-class OAuth2TokenService;
+namespace identity {
+class IdentityManager;
+class PrimaryAccountAccessTokenFetcher;
+}  // namespace identity
+class GoogleServiceAuthError;
 
 namespace cryptauth {
 
@@ -26,13 +29,11 @@
   typedef base::Callback<void(const std::string&)> ErrorCallback;
 
   // Creates the client using |url_request_context| to make the HTTP request
-  // through |api_call_flow|. CryptAuthClientImpl takes ownership of
-  // |access_token_fetcher|, which provides the access token authorizing
-  // CryptAuth requests. The |device_classifier| argument contains basic device
-  // information of the caller (e.g. version and device type).
+  // through |api_call_flow|. The |device_classifier| argument contains basic
+  // device information of the caller (e.g. version and device type).
   CryptAuthClientImpl(
       std::unique_ptr<CryptAuthApiCallFlow> api_call_flow,
-      std::unique_ptr<CryptAuthAccessTokenFetcher> access_token_fetcher,
+      identity::IdentityManager* identity_manager,
       scoped_refptr<net::URLRequestContextGetter> url_request_context,
       const DeviceClassifier& device_classifier);
   ~CryptAuthClientImpl() override;
@@ -85,7 +86,8 @@
   void OnAccessTokenFetched(
       const std::string& serialized_request,
       const base::Callback<void(const ResponseProto&)>& response_callback,
-      const std::string& access_token);
+      GoogleServiceAuthError error,
+      std::string access_token);
 
   // Called with CryptAuthApiCallFlow completes successfully to deserialize and
   // return the result.
@@ -100,8 +102,11 @@
   // Constructs and executes the actual HTTP request.
   std::unique_ptr<CryptAuthApiCallFlow> api_call_flow_;
 
+  identity::IdentityManager* identity_manager_;
+
   // Fetches the access token authorizing the API calls.
-  std::unique_ptr<CryptAuthAccessTokenFetcher> access_token_fetcher_;
+  std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
+      access_token_fetcher_;
 
   // The context for network requests.
   scoped_refptr<net::URLRequestContextGetter> url_request_context_;
@@ -131,14 +136,12 @@
 // Implementation of CryptAuthClientFactory.
 class CryptAuthClientFactoryImpl : public CryptAuthClientFactory {
  public:
-  // |token_service|: Gets the user's access token.
-  //     Not owned, so |token_service| needs to outlive this object.
-  // |account_id|: The account id of the user.
+  // |identity_manager|: Gets the user's access token.
+  //     Not owned, so |identity_manager| needs to outlive this object.
   // |url_request_context|: The request context to make the HTTP requests.
   // |device_classifier|: Contains basic device information of the client.
   CryptAuthClientFactoryImpl(
-      OAuth2TokenService* token_service,
-      const std::string& account_id,
+      identity::IdentityManager* identity_manager,
       scoped_refptr<net::URLRequestContextGetter> url_request_context,
       const DeviceClassifier& device_classifier);
   ~CryptAuthClientFactoryImpl() override;
@@ -147,8 +150,7 @@
   std::unique_ptr<CryptAuthClient> CreateInstance() override;
 
  private:
-  OAuth2TokenService* token_service_;
-  const std::string account_id_;
+  identity::IdentityManager* identity_manager_;
   const scoped_refptr<net::URLRequestContextGetter> url_request_context_;
   const DeviceClassifier device_classifier_;
 
diff --git a/components/cryptauth/cryptauth_client_impl_unittest.cc b/components/cryptauth/cryptauth_client_impl_unittest.cc
index 960278d..d30fe59b 100644
--- a/components/cryptauth/cryptauth_client_impl_unittest.cc
+++ b/components/cryptauth/cryptauth_client_impl_unittest.cc
@@ -8,14 +8,14 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/test/null_task_runner.h"
-#include "components/cryptauth/cryptauth_access_token_fetcher.h"
+#include "base/test/scoped_task_environment.h"
 #include "components/cryptauth/cryptauth_api_call_flow.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 #include "components/cryptauth/switches.h"
-#include "google_apis/gaia/fake_oauth2_token_service.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_request_test_util.h"
+#include "services/identity/public/cpp/identity_test_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -32,6 +32,7 @@
 
 const char kTestGoogleApisUrl[] = "https://www.testgoogleapis.com";
 const char kAccessToken[] = "access_token";
+const char kEmail[] = "test@gmail.com";
 const char kPublicKey1[] = "public_key1";
 const char kPublicKey2[] = "public_key2";
 const char kBluetoothAddress1[] = "AA:AA:AA:AA:AA:AA";
@@ -43,24 +44,6 @@
 const char kDeviceSoftwarePackage[] = "cryptauth_client_unittest";
 const DeviceType kDeviceType = CHROME;
 
-// CryptAuthAccessTokenFetcher implementation simply returning a predetermined
-// access token.
-class FakeCryptAuthAccessTokenFetcher : public CryptAuthAccessTokenFetcher {
- public:
-  FakeCryptAuthAccessTokenFetcher() : access_token_(kAccessToken) {}
-
-  void FetchAccessToken(const AccessTokenCallback& callback) override {
-    callback.Run(access_token_);
-  }
-
-  void set_access_token(const std::string& access_token) {
-    access_token_ = access_token;
-  };
-
- private:
-  std::string access_token_;
-};
-
 // Mock CryptAuthApiCallFlow, which handles the HTTP requests to CryptAuth.
 class MockCryptAuthApiCallFlow : public CryptAuthApiCallFlow {
  public:
@@ -98,8 +81,7 @@
 class CryptAuthClientTest : public testing::Test {
  protected:
   CryptAuthClientTest()
-      : access_token_fetcher_(new FakeCryptAuthAccessTokenFetcher()),
-        api_call_flow_(new StrictMock<MockCryptAuthApiCallFlow>()),
+      : api_call_flow_(new StrictMock<MockCryptAuthApiCallFlow>()),
         url_request_context_(
             new net::TestURLRequestContextGetter(new base::NullTaskRunner())),
         serialized_request_(std::string()) {}
@@ -115,9 +97,11 @@
     device_classifier.set_device_software_package(kDeviceSoftwarePackage);
     device_classifier.set_device_type(kDeviceType);
 
+    identity_test_environment_.MakePrimaryAccountAvailable(kEmail);
+
     client_.reset(
         new CryptAuthClientImpl(base::WrapUnique(api_call_flow_),
-                                base::WrapUnique(access_token_fetcher_),
+                                identity_test_environment_.identity_manager(),
                                 url_request_context_, device_classifier));
   }
 
@@ -145,8 +129,8 @@
   }
 
  protected:
-  // Owned by |client_|.
-  FakeCryptAuthAccessTokenFetcher* access_token_fetcher_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  identity::IdentityTestEnvironment identity_test_environment_;
   // Owned by |client_|.
   StrictMock<MockCryptAuthApiCallFlow>* api_call_flow_;
 
@@ -171,6 +155,9 @@
       base::Bind(&SaveResult<GetMyDevicesResponse>, &result_proto),
       base::Bind(&NotCalled<std::string>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   GetMyDevicesRequest expected_request;
   EXPECT_TRUE(expected_request.ParseFromString(serialized_request_));
@@ -209,6 +196,9 @@
                         base::Bind(&NotCalled<GetMyDevicesResponse>),
                         base::Bind(&SaveResult<std::string>, &error_message),
                         PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   std::string kStatus500Error("HTTP status: 500");
   FailApiCallFlow(kStatus500Error);
@@ -228,6 +218,9 @@
       base::Bind(&SaveResult<FindEligibleUnlockDevicesResponse>,
                  &result_proto),
       base::Bind(&NotCalled<std::string>));
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   FindEligibleUnlockDevicesRequest expected_request;
   EXPECT_TRUE(expected_request.ParseFromString(serialized_request_));
@@ -271,6 +264,9 @@
       request_proto,
       base::Bind(&NotCalled<FindEligibleUnlockDevicesResponse>),
       base::Bind(&SaveResult<std::string>, &error_message));
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   std::string kStatus403Error("HTTP status: 403");
   FailApiCallFlow(kStatus403Error);
@@ -287,6 +283,9 @@
       FindEligibleForPromotionRequest(),
       base::Bind(&SaveResult<FindEligibleForPromotionResponse>, &result_proto),
       base::Bind(&NotCalled<std::string>));
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   FindEligibleForPromotionRequest expected_request;
   EXPECT_TRUE(expected_request.ParseFromString(serialized_request_));
@@ -306,6 +305,9 @@
       base::Bind(&SaveResult<SendDeviceSyncTickleResponse>, &result_proto),
       base::Bind(&NotCalled<std::string>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   SendDeviceSyncTickleRequest expected_request;
   EXPECT_TRUE(expected_request.ParseFromString(serialized_request_));
@@ -329,6 +331,9 @@
       base::Bind(&SaveResult<ToggleEasyUnlockResponse>,
                  &result_proto),
       base::Bind(&NotCalled<std::string>));
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   ToggleEasyUnlockRequest expected_request;
   EXPECT_TRUE(expected_request.ParseFromString(serialized_request_));
@@ -359,6 +364,9 @@
       request_proto, base::Bind(&SaveResult<SetupEnrollmentResponse>,
                                 &result_proto),
       base::Bind(&NotCalled<std::string>));
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   SetupEnrollmentRequest expected_request;
   EXPECT_TRUE(expected_request.ParseFromString(serialized_request_));
@@ -404,6 +412,9 @@
       base::Bind(&SaveResult<FinishEnrollmentResponse>,
                  &result_proto),
       base::Bind(&NotCalled<const std::string&>));
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   FinishEnrollmentRequest expected_request;
   EXPECT_TRUE(expected_request.ParseFromString(serialized_request_));
@@ -420,13 +431,14 @@
 }
 
 TEST_F(CryptAuthClientTest, FetchAccessTokenFailure) {
-  access_token_fetcher_->set_access_token("");
-
   std::string error_message;
   client_->GetMyDevices(GetMyDevicesRequest(),
                         base::Bind(&NotCalled<GetMyDevicesResponse>),
                         base::Bind(&SaveResult<std::string>, &error_message),
                         PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
+          GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
 
   EXPECT_EQ("Failed to get a valid access token.", error_message);
 }
@@ -441,6 +453,9 @@
                         base::Bind(&NotCalled<GetMyDevicesResponse>),
                         base::Bind(&SaveResult<std::string>, &error_message),
                         PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   flow_result_callback_.Run("Not a valid serialized response message.");
   EXPECT_EQ("Failed to parse response proto.", error_message);
@@ -459,6 +474,9 @@
       base::Bind(&SaveResult<GetMyDevicesResponse>, &result_proto),
       base::Bind(&NotCalled<std::string>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   // With request pending, make second request.
   {
@@ -495,6 +513,9 @@
                         base::Bind(&NotCalled<GetMyDevicesResponse>),
                         base::Bind(&SaveResult<std::string>, &error_message),
                         PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
 
   // With request pending, make second request.
   {
@@ -526,6 +547,9 @@
         base::Bind(&SaveResult<GetMyDevicesResponse>, &result_proto),
         base::Bind(&NotCalled<std::string>),
         PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+    identity_test_environment_
+        .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+            kAccessToken, base::Time::Max());
 
     GetMyDevicesResponse response_proto;
     response_proto.add_devices();
@@ -560,6 +584,9 @@
       base::Bind(&SaveResult<GetMyDevicesResponse>, &result_proto),
       base::Bind(&NotCalled<std::string>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
   GetMyDevicesRequest expected_request;
   EXPECT_TRUE(expected_request.ParseFromString(serialized_request_));
 
@@ -575,6 +602,7 @@
 
 TEST_F(CryptAuthClientTest, GetAccessTokenUsed) {
   EXPECT_TRUE(client_->GetAccessTokenUsed().empty());
+
   ExpectRequest(
       "https://www.testgoogleapis.com/cryptauth/v1/deviceSync/"
       "getmydevices?alt=proto");
@@ -587,6 +615,10 @@
       base::Bind(&SaveResult<GetMyDevicesResponse>, &result_proto),
       base::Bind(&NotCalled<std::string>),
       PARTIAL_TRAFFIC_ANNOTATION_FOR_TESTS);
+  identity_test_environment_
+      .WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+          kAccessToken, base::Time::Max());
+
   EXPECT_EQ(kAccessToken, client_->GetAccessTokenUsed());
 }
 
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index e0ccfb9..27afc38 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -182,7 +182,13 @@
   EXPECT_TRUE(frame_time.is_null());
 }
 
-TEST_P(SurfaceTest, SetOpaqueRegion) {
+// Disabled due to flakiness: crbug.com/856145
+#if defined(LEAK_SANITIZER)
+#define MAYBE_SetOpaqueRegion DISABLED_SetOpaqueRegion
+#else
+#define MAYBE_SetOpaqueRegion SetOpaqueRegion
+#endif
+TEST_P(SurfaceTest, MAYBE_SetOpaqueRegion) {
   gfx::Size buffer_size(1, 1);
   auto buffer = std::make_unique<Buffer>(
       exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
@@ -369,7 +375,13 @@
             frame.render_pass_list.back()->damage_rect);
 }
 
-TEST_P(SurfaceTest, SetBufferTransform) {
+// Disabled due to flakiness: crbug.com/856145
+#if defined(LEAK_SANITIZER)
+#define MAYBE_SetBufferTransform DISABLED_SetBufferTransform
+#else
+#define MAYBE_SetBufferTransform SetBufferTransform
+#endif
+TEST_P(SurfaceTest, MAYBE_SetBufferTransform) {
   gfx::Size buffer_size(256, 512);
   auto buffer = std::make_unique<Buffer>(
       exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
@@ -522,7 +534,13 @@
             frame.render_pass_list.back()->damage_rect);
 }
 
-TEST_P(SurfaceTest, SetCropAndBufferTransform) {
+// Disabled due to flakiness: crbug.com/856145
+#if defined(LEAK_SANITIZER)
+#define MAYBE_SetCropAndBufferTransform DISABLED_SetCropAndBufferTransform
+#else
+#define MAYBE_SetCropAndBufferTransform SetCropAndBufferTransform
+#endif
+TEST_P(SurfaceTest, MAYBE_SetCropAndBufferTransform) {
   gfx::Size buffer_size(128, 64);
   auto buffer = std::make_unique<Buffer>(
       exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
diff --git a/components/password_manager/core/browser/password_autofill_manager.cc b/components/password_manager/core/browser/password_autofill_manager.cc
index 20755cb1..7fc6f4b 100644
--- a/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/components/password_manager/core/browser/password_autofill_manager.cc
@@ -141,20 +141,6 @@
 #endif
 }
 
-void AddSimpleSuggestionWithSeparatorOnTop(
-    int value,
-    int frontend_id,
-    std::vector<autofill::Suggestion>* suggestions) {
-#if !defined(OS_ANDROID)
-  suggestions->push_back(autofill::Suggestion());
-  suggestions->back().frontend_id = autofill::POPUP_ITEM_ID_SEPARATOR;
-#endif
-
-  autofill::Suggestion suggestion(l10n_util::GetStringUTF8(value),
-                                  std::string(), std::string(), frontend_id);
-  suggestions->push_back(suggestion);
-}
-
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -241,24 +227,17 @@
     return;
   }
 
-  if (options & autofill::IS_PASSWORD_FIELD) {
-    autofill::Suggestion password_field_suggestions(l10n_util::GetStringUTF16(
-        IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE));
-    password_field_suggestions.frontend_id = autofill::POPUP_ITEM_ID_TITLE;
-    suggestions.insert(suggestions.begin(), password_field_suggestions);
-  }
-
-  GURL origin = (fill_data_it->second).origin;
+  GURL origin = fill_data_it->second.origin;
 
   if (ShouldShowManualFallbackForPreLollipop(
           autofill_client_->GetSyncService())) {
-    if (base::FeatureList::IsEnabled(
-            password_manager::features::kManualFallbacksFilling) &&
-        (options & autofill::IS_PASSWORD_FIELD) && password_client_ &&
+    if (password_client_ &&
         password_client_->IsFillingFallbackEnabledForCurrentPage()) {
-      AddSimpleSuggestionWithSeparatorOnTop(
-          IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK,
-          autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY, &suggestions);
+      autofill::Suggestion suggestion(
+          l10n_util::GetStringUTF8(IDS_PASSWORD_MANAGER_MANAGE_PASSWORDS),
+          std::string(), std::string(),
+          autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY);
+      suggestions.push_back(suggestion);
 
       show_all_saved_passwords_shown_context_ =
           metrics_util::SHOW_ALL_SAVED_PASSWORDS_CONTEXT_PASSWORD;
diff --git a/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index 9c18dcd..006da433 100644
--- a/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -130,6 +130,15 @@
 #endif
 }
 
+std::vector<base::string16> GetSuggestionList(
+    std::vector<base::string16> credentials) {
+  if (!IsPreLollipopAndroid()) {
+    credentials.push_back(
+        l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_MANAGE_PASSWORDS));
+  }
+  return credentials;
+}
+
 }  // namespace
 
 class PasswordAutofillManagerTest : public testing::Test {
@@ -165,16 +174,6 @@
   int fill_data_id() { return fill_data_id_; }
   autofill::PasswordFormFillData& fill_data() { return fill_data_; }
 
-  void SetManualFallbacksForFilling(bool enabled) {
-    if (enabled) {
-      scoped_feature_list_.InitAndEnableFeature(
-          password_manager::features::kManualFallbacksFilling);
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          password_manager::features::kManualFallbacksFilling);
-    }
-  }
-
   void SetManualFallbacksForFillingStandalone(bool enabled) {
     if (enabled) {
       scoped_feature_list_.InitAndEnableFeature(
@@ -185,12 +184,6 @@
     }
   }
 
-  static bool IsManualFallbackForFillingEnabled() {
-    return base::FeatureList::IsEnabled(
-               password_manager::features::kManualFallbacksFilling) &&
-           !IsPreLollipopAndroid();
-  }
-
   std::unique_ptr<PasswordAutofillManager> password_autofill_manager_;
 
   base::string16 test_username_;
@@ -260,6 +253,8 @@
 // suggestions.
 TEST_F(PasswordAutofillManagerTest, ExternalDelegatePasswordSuggestions) {
   for (bool is_suggestion_on_password_field : {false, true}) {
+    SCOPED_TRACE(testing::Message() << "is_suggestion_on_password_field = "
+                                    << is_suggestion_on_password_field);
     std::unique_ptr<TestPasswordManagerClient> client(
         new TestPasswordManagerClient);
     std::unique_ptr<MockAutofillClient> autofill_client(new MockAutofillClient);
@@ -277,16 +272,11 @@
                 FillSuggestion(test_username_, test_password_));
 
     std::vector<autofill::PopupItemId> ids = {
-        autofill::POPUP_ITEM_ID_USERNAME_ENTRY};
-    if (is_suggestion_on_password_field) {
-      ids = {autofill::POPUP_ITEM_ID_TITLE,
-             autofill::POPUP_ITEM_ID_PASSWORD_ENTRY};
-      if (IsManualFallbackForFillingEnabled()) {
-#if !defined(OS_ANDROID)
-        ids.push_back(autofill::POPUP_ITEM_ID_SEPARATOR);
-#endif
-        ids.push_back(autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY);
-      }
+        is_suggestion_on_password_field
+            ? autofill::POPUP_ITEM_ID_PASSWORD_ENTRY
+            : autofill::POPUP_ITEM_ID_USERNAME_ENTRY};
+    if (!IsPreLollipopAndroid()) {
+      ids.push_back(autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY);
     }
     EXPECT_CALL(
         *autofill_client,
@@ -334,41 +324,43 @@
   // First, simulate displaying suggestions matching an empty prefix. Also
   // verify that both the values and labels are filled correctly. The 'value'
   // should be the user name; the 'label' should be the realm.
-  EXPECT_CALL(*autofill_client,
-              ShowAutofillPopup(
-                  element_bounds, _,
-                  testing::AllOf(
-                      SuggestionVectorValuesAre(testing::UnorderedElementsAre(
-                          test_username_, additional_username)),
-                      SuggestionVectorLabelsAre(testing::UnorderedElementsAre(
-                          base::UTF8ToUTF16(data.preferred_realm),
-                          base::UTF8ToUTF16(additional.realm)))),
-                  _));
+  EXPECT_CALL(
+      *autofill_client,
+      ShowAutofillPopup(
+          element_bounds, _,
+          testing::AllOf(
+              SuggestionVectorValuesAre(testing::UnorderedElementsAreArray(
+                  GetSuggestionList({test_username_, additional_username}))),
+              SuggestionVectorLabelsAre(testing::AllOf(
+                  testing::Contains(base::UTF8ToUTF16(data.preferred_realm)),
+                  testing::Contains(base::UTF8ToUTF16(additional.realm))))),
+          _));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      dummy_key, base::i18n::RIGHT_TO_LEFT, base::string16(), false,
+      dummy_key, base::i18n::RIGHT_TO_LEFT, base::string16(), 0,
       element_bounds);
 
   // Now simulate displaying suggestions matching "John".
   EXPECT_CALL(
       *autofill_client,
       ShowAutofillPopup(element_bounds, _,
-                        SuggestionVectorValuesAre(
-                            testing::UnorderedElementsAre(additional_username)),
+                        SuggestionVectorValuesAre(testing::ElementsAreArray(
+                            GetSuggestionList({additional_username}))),
                         _));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("John"), false,
+      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("John"), 0,
       element_bounds);
 
   // Finally, simulate displaying all suggestions, without any prefix matching.
   EXPECT_CALL(
       *autofill_client,
-      ShowAutofillPopup(element_bounds, _,
-                        SuggestionVectorValuesAre(testing::UnorderedElementsAre(
-                            test_username_, additional_username)),
-                        _));
+      ShowAutofillPopup(
+          element_bounds, _,
+          SuggestionVectorValuesAre(testing::ElementsAreArray(
+              GetSuggestionList({test_username_, additional_username}))),
+          _));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("xyz"), true,
-      element_bounds);
+      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("xyz"),
+      autofill::SHOW_ALL, element_bounds);
 }
 
 // Verify that, for Android application credentials, the prettified realms of
@@ -393,15 +385,15 @@
   password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
 
   EXPECT_CALL(*autofill_client,
-              ShowAutofillPopup(
-                  _, _,
-                  SuggestionVectorLabelsAre(testing::UnorderedElementsAre(
-                      base::ASCIIToUTF16("android://com.example1.android/"),
-                      base::ASCIIToUTF16("android://com.example2.android/"))),
-                  _));
+              ShowAutofillPopup(_, _,
+                                SuggestionVectorLabelsAre(testing::AllOf(
+                                    testing::Contains(base::ASCIIToUTF16(
+                                        "android://com.example1.android/")),
+                                    testing::Contains(base::ASCIIToUTF16(
+                                        "android://com.example2.android/")))),
+                                _));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      dummy_key, base::i18n::RIGHT_TO_LEFT, base::string16(), false,
-      gfx::RectF());
+      dummy_key, base::i18n::RIGHT_TO_LEFT, base::string16(), 0, gfx::RectF());
 }
 
 TEST_F(PasswordAutofillManagerTest, FillSuggestionPasswordField) {
@@ -427,27 +419,12 @@
   int dummy_key = 0;
   password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
 
-  // Simulate displaying suggestions matching a username and specifying that the
-  // field is a password field.
-  base::string16 title = l10n_util::GetStringUTF16(
-      IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
-  std::vector<base::string16> elements = {title, test_username_};
-  if (IsManualFallbackForFillingEnabled()) {
-    elements = {
-      title,
-      test_username_,
-#if !defined(OS_ANDROID)
-      base::string16(),
-#endif
-      l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK)
-    };
-  }
-
   EXPECT_CALL(
       *autofill_client,
-      ShowAutofillPopup(
-          element_bounds, _,
-          SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
+      ShowAutofillPopup(element_bounds, _,
+                        SuggestionVectorValuesAre(testing::ElementsAreArray(
+                            GetSuggestionList({test_username_}))),
+                        _));
   password_autofill_manager_->OnShowPasswordSuggestions(
       dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
       autofill::IS_PASSWORD_FIELD, element_bounds);
@@ -483,14 +460,14 @@
   int dummy_key = 0;
   password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
 
-  EXPECT_CALL(
-      *autofill_client,
-      ShowAutofillPopup(element_bounds, _,
-                        SuggestionVectorValuesAre(testing::UnorderedElementsAre(
-                            username, additional_username)),
-                        _));
+  EXPECT_CALL(*autofill_client,
+              ShowAutofillPopup(
+                  element_bounds, _,
+                  SuggestionVectorValuesAre(testing::UnorderedElementsAreArray(
+                      GetSuggestionList({username, additional_username}))),
+                  _));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), false,
+      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), 0,
       element_bounds);
 }
 
@@ -527,7 +504,7 @@
   EXPECT_CALL(*autofill_client, ShowAutofillPopup(_, _, _, _)).Times(0);
 
   password_autofill_manager_->OnShowPasswordSuggestions(
-      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("oo"), false,
+      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("oo"), 0,
       element_bounds);
 }
 
@@ -566,12 +543,12 @@
   EXPECT_CALL(
       *autofill_client,
       ShowAutofillPopup(element_bounds, _,
-                        SuggestionVectorValuesAre(
-                            testing::UnorderedElementsAre(additional_username)),
+                        SuggestionVectorValuesAre(testing::ElementsAreArray(
+                            GetSuggestionList({additional_username}))),
                         _));
   password_autofill_manager_->OnShowPasswordSuggestions(
-      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo@exam"),
-      false, element_bounds);
+      dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo@exam"), 0,
+      element_bounds);
 }
 
 // Verify that typing "example" into the username field will match and order
@@ -606,12 +583,12 @@
   int dummy_key = 0;
   password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
 
-  EXPECT_CALL(
-      *autofill_client,
-      ShowAutofillPopup(element_bounds, _,
-                        SuggestionVectorValuesAre(testing::UnorderedElementsAre(
-                            username, additional_username)),
-                        _));
+  EXPECT_CALL(*autofill_client,
+              ShowAutofillPopup(
+                  element_bounds, _,
+                  SuggestionVectorValuesAre(testing::ElementsAreArray(
+                      GetSuggestionList({username, additional_username}))),
+                  _));
   password_autofill_manager_->OnShowPasswordSuggestions(
       dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), false,
       element_bounds);
@@ -651,45 +628,8 @@
   testing::Mock::VerifyAndClearExpectations(client->mock_driver());
 }
 
-// Tests that the "Show all passwords" suggestion isn't shown along with
-// "Use password for" in the popup when the feature which controls its
-// appearance is disabled.
-TEST_F(PasswordAutofillManagerTest,
-       NotShowAllPasswordsOptionOnPasswordFieldWhenFeatureDisabled) {
-  auto client = std::make_unique<TestPasswordManagerClient>();
-  auto autofill_client = std::make_unique<MockAutofillClient>();
-  InitializePasswordAutofillManager(client.get(), autofill_client.get());
-
-  gfx::RectF element_bounds;
-  autofill::PasswordFormFillData data;
-  data.username_field.value = test_username_;
-  data.password_field.value = test_password_;
-  data.origin = GURL("https://foo.test");
-
-  int dummy_key = 0;
-  password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
-
-  // String "Use password for:" shown when displaying suggestions matching a
-  // username and specifying that the field is a password field.
-  base::string16 title =
-      l10n_util::GetStringUTF16(IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
-
-  SetManualFallbacksForFilling(false);
-
-  // No "Show all passwords row" when feature is disabled.
-  EXPECT_CALL(*autofill_client,
-              ShowAutofillPopup(element_bounds, _,
-                                SuggestionVectorValuesAre(testing::ElementsAre(
-                                    title, test_username_)),
-                                _));
-  password_autofill_manager_->OnShowPasswordSuggestions(
-      dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
-      autofill::IS_PASSWORD_FIELD, element_bounds);
-}
-
-// Tests that the "Show all passwords" suggestion is shown along with
-// "Use password for" in the popup when the feature which controls its
-// appearance is enabled.
+// Tests that the "Manage passwords" suggestion is shown along with the password
+// popup.
 TEST_F(PasswordAutofillManagerTest, ShowAllPasswordsOptionOnPasswordField) {
   const char kShownContextHistogram[] =
       "PasswordManager.ShowAllSavedPasswordsShownContext";
@@ -716,30 +656,12 @@
   int dummy_key = 0;
   password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
 
-  // String "Use password for:" shown when displaying suggestions matching a
-  // username and specifying that the field is a password field.
-  base::string16 title =
-      l10n_util::GetStringUTF16(IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
-
-  SetManualFallbacksForFilling(true);
-
-  std::vector<base::string16> elements = {title, test_username_};
-  if (!IsPreLollipopAndroid()) {
-    elements = {
-      title,
-      test_username_,
-#if !defined(OS_ANDROID)
-      base::string16(),
-#endif
-      l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK)
-    };
-  }
-
   EXPECT_CALL(
       *autofill_client,
-      ShowAutofillPopup(
-          element_bounds, _,
-          SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
+      ShowAutofillPopup(element_bounds, _,
+                        SuggestionVectorValuesAre(testing::ElementsAreArray(
+                            GetSuggestionList({test_username_}))),
+                        _));
 
   password_autofill_manager_->OnShowPasswordSuggestions(
       dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
@@ -880,10 +802,9 @@
   }
 }
 
-// Tests that the "Show all passwords" fallback doesn't shows up in non-password
+// Tests that the "Manage passwords" fallback shows up in non-password
 // fields of login forms.
-TEST_F(PasswordAutofillManagerTest,
-       NotShowAllPasswordsOptionOnNonPasswordField) {
+TEST_F(PasswordAutofillManagerTest, ShowAllPasswordsOptionOnNonPasswordField) {
   auto client = std::make_unique<TestPasswordManagerClient>();
   auto autofill_client = std::make_unique<MockAutofillClient>();
   InitializePasswordAutofillManager(client.get(), autofill_client.get());
@@ -897,13 +818,12 @@
   int dummy_key = 0;
   password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
 
-  SetManualFallbacksForFilling(true);
-
   EXPECT_CALL(
       *autofill_client,
-      ShowAutofillPopup(
-          element_bounds, _,
-          SuggestionVectorValuesAre(testing::ElementsAre(test_username_)), _));
+      ShowAutofillPopup(element_bounds, _,
+                        SuggestionVectorValuesAre(testing::ElementsAreArray(
+                            GetSuggestionList({test_username_}))),
+                        _));
   password_autofill_manager_->OnShowPasswordSuggestions(
       dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_, 0, element_bounds);
 }
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 259c2fed..429aeaf 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -510,7 +510,8 @@
     password_manager::PasswordManagerDriver* driver,
     const PasswordForm& password_form) {
   if (!client_->IsSavingAndFillingEnabledForCurrentPage() ||
-      ShouldBlockPasswordForSameOriginButDifferentScheme(password_form))
+      ShouldBlockPasswordForSameOriginButDifferentScheme(password_form) ||
+      !client_->GetStoreResultFilter()->ShouldSave(password_form))
     return;
 
   PasswordFormManager* matched_manager = FindMatchedManager(
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index 37bbc4f..39a593d 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -124,7 +124,7 @@
   // Handles a password form being submitted, assumes that submission is
   // successful and does not do any checks on success of submission.
   // For example, this is called if |password_form| was filled
-  // upon in-page navigation.This often means history.pushState being
+  // upon in-page navigation. This often means history.pushState being
   // called from JavaScript.
   void OnPasswordFormSubmittedNoChecks(
       password_manager::PasswordManagerDriver* driver,
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index d9808cd..587ed1a 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -565,6 +565,35 @@
             user_action_tester.GetActionCount("PasswordManager_LoginPassed"));
 }
 
+// Tests that on Chrome sign-in form credentials are not saved.
+TEST_F(PasswordManagerTest, DoNotSaveOnChromeSignInForm) {
+  EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+      .WillRepeatedly(Return(true));
+
+  PasswordForm form(MakeSimpleForm());
+  form.is_gaia_with_skip_save_password_form = true;
+  std::vector<PasswordForm> observed = {form};
+  EXPECT_CALL(*store_, GetLogins(_, _))
+      .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+  manager()->OnPasswordFormsParsed(&driver_, observed);
+  manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+  EXPECT_CALL(*client_.GetStoreResultFilter(), ShouldSave(_))
+      .WillRepeatedly(Return(false));
+  // The user is typing a credential. No fallback should be available.
+  PasswordForm typed_credentials(form);
+  typed_credentials.password_value = ASCIIToUTF16("pw");
+  EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, _, _)).Times(0);
+  manager()->ShowManualFallbackForSaving(&driver_, form);
+
+  // The user submits the form. No prompt should pop up.
+  OnPasswordFormSubmitted(form);
+  EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
+  observed.clear();
+  manager()->DidNavigateMainFrame();
+  manager()->OnPasswordFormsRendered(&driver_, observed, true);
+}
+
 // Tests that a UKM metric "Login Passed" is sent when the submitted credentials
 // are already in the store and OnPasswordFormsParsed is called multiple times.
 TEST_F(PasswordManagerTest,
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index 63b9410..d120597 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -23,11 +23,6 @@
 const base::Feature kHtmlBasedUsernameDetector = {
     "HtmlBaseUsernameDetector", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Enable additional elements in the form popup UI, which will allow the user to
-// view all saved passwords.
-const base::Feature kManualFallbacksFilling = {
-    "ManualFallbacksFilling", base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Enable a standalone popup UI, which will allow the user to view all saved
 // passwords.
 const base::Feature kManualFallbacksFillingStandalone = {
@@ -38,10 +33,6 @@
 const base::Feature kPasswordForceSaving = {
     "PasswordForceSaving", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Enable the user to trigger password generation manually.
-const base::Feature kManualPasswordGeneration = {
-    "manual-password-generation", base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Controls the ability to generate passwords that fit sites' requirements.
 const base::Feature kPasswordGenerationRequirements = {
     "PasswordGenerationRequirements", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index 64b5e653..a47982ae 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -20,9 +20,7 @@
 extern const base::Feature kAffiliationBasedMatching;
 extern const base::Feature kAutofillHome;
 extern const base::Feature kHtmlBasedUsernameDetector;
-extern const base::Feature kManualFallbacksFilling;
 extern const base::Feature kManualFallbacksFillingStandalone;
-extern const base::Feature kManualPasswordGeneration;
 extern const base::Feature kPasswordGenerationRequirements;
 extern const base::Feature kPasswordGenerationRequirementsDomainOverrides;
 extern const base::Feature kPasswordForceSaving;
diff --git a/components/password_manager/sync/browser/sync_credentials_filter.cc b/components/password_manager/sync/browser/sync_credentials_filter.cc
index 3ca8250..9238f54 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter.cc
+++ b/components/password_manager/sync/browser/sync_credentials_filter.cc
@@ -77,9 +77,10 @@
 
 bool SyncCredentialsFilter::ShouldSave(
     const autofill::PasswordForm& form) const {
-  return !sync_util::IsSyncAccountCredential(
-      form, sync_service_factory_function_.Run(),
-      signin_manager_factory_function_.Run());
+  return !form.is_gaia_with_skip_save_password_form &&
+         !sync_util::IsSyncAccountCredential(
+             form, sync_service_factory_function_.Run(),
+             signin_manager_factory_function_.Run());
 }
 
 bool SyncCredentialsFilter::ShouldSaveGaiaPasswordHash(
diff --git a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc b/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
index 1a32af59..b28a3fd68 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
+++ b/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
@@ -374,6 +374,14 @@
   EXPECT_FALSE(filter_.ShouldSave(form));
 }
 
+TEST_F(CredentialsFilterTest, ShouldSave_SignIn_Form) {
+  PasswordForm form = SimpleGaiaForm("user@example.org");
+  form.is_gaia_with_skip_save_password_form = true;
+
+  SetSyncingPasswords(false);
+  EXPECT_FALSE(filter_.ShouldSave(form));
+}
+
 TEST_F(CredentialsFilterTest, ShouldSave_SyncCredential_NotSyncingPasswords) {
   PasswordForm form = SimpleGaiaForm("user@example.org");
 
diff --git a/components/policy/core/common/policy_loader_win.cc b/components/policy/core/common/policy_loader_win.cc
index 1e3d2e2a..6cdd7af 100644
--- a/components/policy/core/common/policy_loader_win.cc
+++ b/components/policy/core/common/policy_loader_win.cc
@@ -100,7 +100,11 @@
 // Encapculates logic to determine if enterprise policies should be honored.
 // This is used in various places below.
 bool ShouldHonorPolicies() {
-  return base::win::IsEnterpriseManaged();
+  bool is_enterprise_version =
+      base::win::OSInfo::GetInstance()->version_type() != base::win::SUITE_HOME;
+  return base::win::IsEnrolledToDomain() ||
+         (base::win::IsDeviceRegisteredWithManagement() &&
+          is_enterprise_version);
 }
 
 // Verifies that untrusted policies contain only safe values. Modifies the
diff --git a/components/resources/autofill_scaled_resources.grdp b/components/resources/autofill_scaled_resources.grdp
index 97db333..ef11660 100644
--- a/components/resources/autofill_scaled_resources.grdp
+++ b/components/resources/autofill_scaled_resources.grdp
@@ -32,7 +32,5 @@
   </if>
   <if expr="is_ios">
     <structure type="chrome_scaled_image" name="IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER" file="autofill/infobar_autofill_googlepay_with_divider.png" />
-    <structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON" file="autofill/autofill_tooltip_icon.png" />
-    <structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON_H" file="autofill/autofill_tooltip_icon_hover.png" />
   </if>
 </grit-part>
diff --git a/components/resources/default_100_percent/autofill/autofill_tooltip_icon.png b/components/resources/default_100_percent/autofill/autofill_tooltip_icon.png
deleted file mode 100644
index 4434da71..0000000
--- a/components/resources/default_100_percent/autofill/autofill_tooltip_icon.png
+++ /dev/null
Binary files differ
diff --git a/components/resources/default_100_percent/autofill/autofill_tooltip_icon_hover.png b/components/resources/default_100_percent/autofill/autofill_tooltip_icon_hover.png
deleted file mode 100644
index 893b63d..0000000
--- a/components/resources/default_100_percent/autofill/autofill_tooltip_icon_hover.png
+++ /dev/null
Binary files differ
diff --git a/components/resources/default_200_percent/autofill/autofill_tooltip_icon.png b/components/resources/default_200_percent/autofill/autofill_tooltip_icon.png
deleted file mode 100644
index 47322b9..0000000
--- a/components/resources/default_200_percent/autofill/autofill_tooltip_icon.png
+++ /dev/null
Binary files differ
diff --git a/components/resources/default_200_percent/autofill/autofill_tooltip_icon_hover.png b/components/resources/default_200_percent/autofill/autofill_tooltip_icon_hover.png
deleted file mode 100644
index 5d11236..0000000
--- a/components/resources/default_200_percent/autofill/autofill_tooltip_icon_hover.png
+++ /dev/null
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/autofill_tooltip_icon.png b/components/resources/default_300_percent/autofill/autofill_tooltip_icon.png
deleted file mode 100644
index 0c7dd7e..0000000
--- a/components/resources/default_300_percent/autofill/autofill_tooltip_icon.png
+++ /dev/null
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/autofill_tooltip_icon_hover.png b/components/resources/default_300_percent/autofill/autofill_tooltip_icon_hover.png
deleted file mode 100644
index 33bd12f..0000000
--- a/components/resources/default_300_percent/autofill/autofill_tooltip_icon_hover.png
+++ /dev/null
Binary files differ
diff --git a/components/safe_browsing/browser/safe_browsing_network_context.cc b/components/safe_browsing/browser/safe_browsing_network_context.cc
index 799d6cc..1dcc1cd5ea 100644
--- a/components/safe_browsing/browser/safe_browsing_network_context.cc
+++ b/components/safe_browsing/browser/safe_browsing_network_context.cc
@@ -166,7 +166,6 @@
     base::FilePath cookie_path = user_data_dir_.Append(
         base::FilePath::StringType(kSafeBrowsingBaseFilename) + kCookiesFile);
     network_context_params->cookie_path = cookie_path;
-    network_context_params->enable_encrypted_cookies = false;
 
     base::FilePath channel_id_path = user_data_dir_.Append(
         base::FilePath::StringType(kSafeBrowsingBaseFilename) + kChannelIDFile);
diff --git a/components/safe_search_api/BUILD.gn b/components/safe_search_api/BUILD.gn
index 35e8b8e..086b2ea 100644
--- a/components/safe_search_api/BUILD.gn
+++ b/components/safe_search_api/BUILD.gn
@@ -26,6 +26,7 @@
   deps = [
     ":safe_search_api",
     "//base",
+    "//base/test:test_support",
     "//net",
     "//net/traffic_annotation:test_support",
     "//services/network:test_support",
diff --git a/components/safe_search_api/url_checker.cc b/components/safe_search_api/url_checker.cc
index b48dc5c..161222e 100644
--- a/components/safe_search_api/url_checker.cc
+++ b/components/safe_search_api/url_checker.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/callback.h"
+#include "base/feature_list.h"
 #include "base/json/json_reader.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
@@ -73,6 +74,10 @@
 
 }  // namespace
 
+// Consider all URLs within a google domain to be safe.
+const base::Feature kAllowAllGoogleUrls{"SafeSearchAllowAllGoogleURLs",
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
+
 struct URLChecker::Check {
   Check(const GURL& url,
         std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
@@ -127,19 +132,21 @@
 URLChecker::~URLChecker() = default;
 
 bool URLChecker::CheckURL(const GURL& url, CheckCallback callback) {
-  // TODO(treib): Hack: For now, allow all Google URLs to save QPS. If we ever
-  // remove this, we should find a way to allow at least the NTP.
-  if (google_util::IsGoogleDomainUrl(url, google_util::ALLOW_SUBDOMAIN,
-                                     google_util::ALLOW_NON_STANDARD_PORTS)) {
-    std::move(callback).Run(url, Classification::SAFE, false);
-    return true;
-  }
-  // TODO(treib): Hack: For now, allow all YouTube URLs since YouTube has its
-  // own Safety Mode anyway.
-  if (google_util::IsYoutubeDomainUrl(url, google_util::ALLOW_SUBDOMAIN,
-                                      google_util::ALLOW_NON_STANDARD_PORTS)) {
-    std::move(callback).Run(url, Classification::SAFE, false);
-    return true;
+  if (base::FeatureList::IsEnabled(kAllowAllGoogleUrls)) {
+    // TODO(treib): Hack: For now, allow all Google URLs to save QPS.
+    if (google_util::IsGoogleDomainUrl(url, google_util::ALLOW_SUBDOMAIN,
+                                       google_util::ALLOW_NON_STANDARD_PORTS)) {
+      std::move(callback).Run(url, Classification::SAFE, false);
+      return true;
+    }
+    // TODO(treib): Hack: For now, allow all YouTube URLs since YouTube has its
+    // own Safety Mode anyway.
+    if (google_util::IsYoutubeDomainUrl(
+            url, google_util::ALLOW_SUBDOMAIN,
+            google_util::ALLOW_NON_STANDARD_PORTS)) {
+      std::move(callback).Run(url, Classification::SAFE, false);
+      return true;
+    }
   }
 
   auto cache_it = cache_.Get(url);
diff --git a/components/safe_search_api/url_checker.h b/components/safe_search_api/url_checker.h
index db3ec366..6eca2f1 100644
--- a/components/safe_search_api/url_checker.h
+++ b/components/safe_search_api/url_checker.h
@@ -22,11 +22,18 @@
 class SharedURLLoaderFactory;
 }  // namespace network
 
+namespace base {
+struct Feature;
+}
+
 namespace safe_search_api {
 
 // The SafeSearch API classification of a URL.
 enum class Classification { SAFE, UNSAFE };
 
+// Visible for testing.
+extern const base::Feature kAllowAllGoogleUrls;
+
 // This class uses the SafeSearch API to check the SafeSearch classification
 // of the content on a given URL and returns the result asynchronously
 // via a callback.
diff --git a/components/safe_search_api/url_checker_unittest.cc b/components/safe_search_api/url_checker_unittest.cc
index 8b43b63c..ea4e16c 100644
--- a/components/safe_search_api/url_checker_unittest.cc
+++ b/components/safe_search_api/url_checker_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "net/base/net_errors.h"
@@ -59,6 +60,10 @@
   return result;
 }
 
+std::string BuildPornResponse() {
+  return BuildResponse(true);
+}
+
 }  // namespace
 
 class SafeSearchURLCheckerTest : public testing::Test {
@@ -195,4 +200,44 @@
   ASSERT_FALSE(SendValidResponse(url, true));
 }
 
+TEST_F(SafeSearchURLCheckerTest, AllowAllGoogleURLs) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(kAllowAllGoogleUrls);
+  {
+    GURL url("https://sites.google.com/porn");
+    EXPECT_CALL(*this, OnCheckDone(url, Classification::SAFE, _));
+    // No server interaction.
+    bool cache_hit = CheckURL(url);
+    ASSERT_TRUE(cache_hit);
+  }
+  {
+    GURL url("https://youtube.com/porn");
+    EXPECT_CALL(*this, OnCheckDone(url, Classification::SAFE, _));
+    // No server interaction
+    bool cache_hit = CheckURL(url);
+    ASSERT_TRUE(cache_hit);
+  }
+}
+
+TEST_F(SafeSearchURLCheckerTest, NoAllowAllGoogleURLs) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndDisableFeature(kAllowAllGoogleUrls);
+  {
+    GURL url("https://sites.google.com/porn");
+    EXPECT_CALL(*this, OnCheckDone(url, Classification::UNSAFE, _));
+    SetupResponse(url, net::OK, BuildPornResponse());
+    bool cache_hit = CheckURL(url);
+    ASSERT_FALSE(cache_hit);
+    WaitForResponse();
+  }
+  {
+    GURL url("https://youtube.com/porn");
+    EXPECT_CALL(*this, OnCheckDone(url, Classification::UNSAFE, _));
+    SetupResponse(url, net::OK, BuildPornResponse());
+    bool cache_hit = CheckURL(url);
+    ASSERT_FALSE(cache_hit);
+    WaitForResponse();
+  }
+}
+
 }  // namespace safe_search_api
diff --git a/components/services/font/public/cpp/font_service_thread.cc b/components/services/font/public/cpp/font_service_thread.cc
index 38e3640..b4f3aa4 100644
--- a/components/services/font/public/cpp/font_service_thread.cc
+++ b/components/services/font/public/cpp/font_service_thread.cc
@@ -22,6 +22,7 @@
     : base::Thread(kFontThreadName),
       font_service_info_(font_service.PassInterface()),
       weak_factory_(this) {
+  DETACH_FROM_THREAD(thread_checker_);
   Start();
 }
 
@@ -31,7 +32,7 @@
     SkFontConfigInterface::FontIdentity* out_font_identity,
     SkString* out_family_name,
     SkFontStyle* out_style) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId());
 
   bool out_valid = false;
   // This proxies to the other thread, which proxies to mojo. Only on the reply
@@ -54,6 +55,7 @@
     std::string* out_family_name,
     bool* out_is_bold,
     bool* out_is_italic) {
+  DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId());
   bool out_valid = false;
   base::WaitableEvent done_event;
   task_runner()->PostTask(
@@ -74,6 +76,7 @@
     bool is_bold,
     float device_scale_factor,
     font_service::mojom::FontRenderStylePtr* out_font_render_style) {
+  DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId());
   bool out_valid = false;
   base::WaitableEvent done_event;
   task_runner()->PostTask(
@@ -92,6 +95,7 @@
     uint32_t charset,
     uint32_t fallback_family_type,
     base::File* out_font_file_handle) {
+  DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId());
   base::WaitableEvent done_event;
   task_runner()->PostTask(
       FROM_HERE,
@@ -103,7 +107,7 @@
 
 scoped_refptr<MappedFontFile> FontServiceThread::OpenStream(
     const SkFontConfigInterface::FontIdentity& identity) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId());
 
   base::File stream_file;
   // This proxies to the other thread, which proxies to mojo. Only on the
@@ -210,6 +214,7 @@
 void FontServiceThread::OnOpenStreamComplete(base::WaitableEvent* done_event,
                                              base::File* output_file,
                                              base::File file) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   pending_waitable_events_.erase(done_event);
   *output_file = std::move(file);
   done_event->Signal();
diff --git a/components/sync/base/model_type.h b/components/sync/base/model_type.h
index 27f49e9..91077499 100644
--- a/components/sync/base/model_type.h
+++ b/components/sync/base/model_type.h
@@ -224,6 +224,11 @@
   return ModelTypeSet::FromRange(FIRST_USER_MODEL_TYPE, LAST_USER_MODEL_TYPE);
 }
 
+// User types, which are not user-controlled.
+constexpr ModelTypeSet AlwaysPreferredUserTypes() {
+  return ModelTypeSet(DEVICE_INFO, USER_CONSENTS);
+}
+
 // These are the user-selectable data types.
 constexpr ModelTypeSet UserSelectableTypes() {
   return ModelTypeSet(BOOKMARKS, PREFERENCES, PASSWORDS, AUTOFILL, THEMES,
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc
index 07d6faa7..d261d9b 100644
--- a/components/sync/base/sync_prefs.cc
+++ b/components/sync/base/sync_prefs.cc
@@ -64,16 +64,13 @@
   // although they don't have sync representations.
   user_types.PutAll(ProxyTypes());
 
-  // Treat device info specially.
-  RegisterDataTypePreferredPref(registry, DEVICE_INFO, true);
-  user_types.Remove(DEVICE_INFO);
-
-  // All types are set to off by default, which forces a configuration to
-  // explicitly enable them. GetPreferredTypes() will ensure that any new
-  // implicit types are enabled when their pref group is, or via
-  // KeepEverythingSynced.
+  // All types except the always-preferred ones are set to off by default, which
+  // forces a configuration to explicitly enable them. GetPreferredTypes() will
+  // ensure that any new implicit types are enabled when their pref group is, or
+  // via KeepEverythingSynced.
   for (ModelTypeSet::Iterator it = user_types.First(); it.Good(); it.Inc()) {
-    RegisterDataTypePreferredPref(registry, it.Get(), false);
+    RegisterDataTypePreferredPref(registry, it.Get(),
+                                  AlwaysPreferredUserTypes().Has(it.Get()));
   }
 
   registry->RegisterBooleanPref(prefs::kSyncManaged, false);
@@ -436,23 +433,16 @@
     ModelType type,
     bool is_preferred) {
   const char* pref_name = GetPrefNameForDataType(type);
-  if (!pref_name) {
-    NOTREACHED();
-    return;
-  }
+  DCHECK(pref_name);
   registry->RegisterBooleanPref(pref_name, is_preferred);
 }
 
 bool SyncPrefs::GetDataTypePreferred(ModelType type) const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const char* pref_name = GetPrefNameForDataType(type);
-  if (!pref_name) {
-    NOTREACHED();
-    return false;
-  }
+  DCHECK(pref_name);
 
-  // Device info is always enabled.
-  if (pref_name == prefs::kSyncDeviceInfo)
+  if (AlwaysPreferredUserTypes().Has(type))
     return true;
 
   if (type == PROXY_TABS &&
@@ -469,13 +459,9 @@
 void SyncPrefs::SetDataTypePreferred(ModelType type, bool is_preferred) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   const char* pref_name = GetPrefNameForDataType(type);
-  if (!pref_name) {
-    NOTREACHED();
-    return;
-  }
+  DCHECK(pref_name);
 
-  // Device info is always preferred.
-  if (type == DEVICE_INFO)
+  if (AlwaysPreferredUserTypes().Has(type))
     return;
 
   pref_service_->SetBoolean(pref_name, is_preferred);
diff --git a/components/sync/base/sync_prefs_unittest.cc b/components/sync/base/sync_prefs_unittest.cc
index 08bc2a2e..af32ae4 100644
--- a/components/sync/base/sync_prefs_unittest.cc
+++ b/components/sync/base/sync_prefs_unittest.cc
@@ -66,10 +66,8 @@
   SyncPrefs sync_prefs(&pref_service_);
   sync_prefs.SetKeepEverythingSynced(false);
 
-  // Only device info is enabled by default.
-  ModelTypeSet expected(DEVICE_INFO);
   ModelTypeSet preferred_types = sync_prefs.GetPreferredDataTypes(UserTypes());
-  EXPECT_EQ(expected, preferred_types);
+  EXPECT_EQ(AlwaysPreferredUserTypes(), preferred_types);
 
   // Simulate an upgrade to delete directives + proxy tabs support. None of the
   // new types or their pref group types should be registering, ensuring they
@@ -165,8 +163,7 @@
       expected_preferred_types.Put(FAVICON_TRACKING);
     }
 
-    // Device info is always preferred.
-    expected_preferred_types.Put(DEVICE_INFO);
+    expected_preferred_types.PutAll(AlwaysPreferredUserTypes());
 
     sync_prefs.SetPreferredDataTypes(user_types, preferred_types);
     EXPECT_EQ(expected_preferred_types,
@@ -229,6 +226,24 @@
   EXPECT_TRUE(sync_prefs.GetPreferredDataTypes(UserTypes()).Has(DEVICE_INFO));
   sync_prefs.SetKeepEverythingSynced(false);
   EXPECT_TRUE(sync_prefs.GetPreferredDataTypes(UserTypes()).Has(DEVICE_INFO));
+  sync_prefs.SetPreferredDataTypes(
+      /*registered_types=*/ModelTypeSet(DEVICE_INFO),
+      /*preferred_types=*/ModelTypeSet());
+  EXPECT_TRUE(sync_prefs.GetPreferredDataTypes(UserTypes()).Has(DEVICE_INFO));
+}
+
+// User Consents should always be enabled.
+TEST_F(SyncPrefsTest, UserConsents) {
+  SyncPrefs sync_prefs(&pref_service_);
+  EXPECT_TRUE(sync_prefs.GetPreferredDataTypes(UserTypes()).Has(USER_CONSENTS));
+  sync_prefs.SetKeepEverythingSynced(true);
+  EXPECT_TRUE(sync_prefs.GetPreferredDataTypes(UserTypes()).Has(USER_CONSENTS));
+  sync_prefs.SetKeepEverythingSynced(false);
+  EXPECT_TRUE(sync_prefs.GetPreferredDataTypes(UserTypes()).Has(USER_CONSENTS));
+  sync_prefs.SetPreferredDataTypes(
+      /*registered_types=*/ModelTypeSet(USER_CONSENTS),
+      /*preferred_types=*/ModelTypeSet());
+  EXPECT_TRUE(sync_prefs.GetPreferredDataTypes(UserTypes()).Has(USER_CONSENTS));
 }
 
 // Verify that invalidation versions are persisted and loaded correctly.
diff --git a/components/sync/driver/data_type_controller.h b/components/sync/driver/data_type_controller.h
index 7d127de..30121b6 100644
--- a/components/sync/driver/data_type_controller.h
+++ b/components/sync/driver/data_type_controller.h
@@ -67,6 +67,8 @@
 
   using ModelLoadCallback = base::Callback<void(ModelType, const SyncError&)>;
 
+  using StopCallback = base::OnceClosure;
+
   using AllNodesCallback =
       base::Callback<void(const ModelType, std::unique_ptr<base::ListValue>)>;
 
@@ -127,9 +129,12 @@
   // See comments for ModelAssociationManager::OnSingleDataTypeWillStop.
   virtual void DeactivateDataType(ModelTypeConfigurer* configurer) = 0;
 
-  // Synchronously stops the data type. If StartAssociating has already been
-  // called but is not done yet it will be aborted. Similarly if LoadModels
-  // has not completed it will also be aborted.
+  // Stops the data type. If StartAssociating has already been called but is not
+  // done yet it will be aborted. Similarly if LoadModels has not completed it
+  // will also be aborted. Implementations may enter STOPPING state
+  // transitionaly but should eventually become STOPPED. At this point,
+  // |callback| will be run. |callback| must not be null.
+  //
   // NOTE: Stop() should be called after sync backend machinery has stopped
   // routing changes to this data type. Stop() should ensure the data type
   // logic shuts down gracefully by flushing remaining changes and calling
@@ -137,7 +142,8 @@
   // propagate from sync again from point where Stop() is called.
   // KEEP_METADATA is used when the engine just stops sync, and CLEAR_METADATA
   // is used when the user disables sync for data type.
-  virtual void Stop(SyncStopMetadataFate metadata_fate) = 0;
+  virtual void Stop(SyncStopMetadataFate metadata_fate,
+                    StopCallback callback) = 0;
 
   // Name of this data type.  For logging purposes only.
   std::string name() const { return ModelTypeToString(type()); }
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc
index e36f7f3..180f77b 100644
--- a/components/sync/driver/data_type_manager_impl.cc
+++ b/components/sync/driver/data_type_manager_impl.cc
@@ -804,6 +804,11 @@
   // callback will do nothing because state is set to STOPPING above.
   model_association_manager_.Stop(metadata_fate);
 
+  // Individual data type controllers might still be STOPPING, but we don't
+  // reflect that in |state_| because, for all practical matters, the manager is
+  // in a ready state and reconfguration can be triggered.
+  // TODO(mastiz): Reconsider waiting in STOPPING state until all datatypes have
+  // stopped.
   state_ = STOPPED;
 }
 
diff --git a/components/sync/driver/directory_data_type_controller.cc b/components/sync/driver/directory_data_type_controller.cc
index feaadf2..03d0c7e 100644
--- a/components/sync/driver/directory_data_type_controller.cc
+++ b/components/sync/driver/directory_data_type_controller.cc
@@ -60,6 +60,13 @@
   configurer->UnregisterDirectoryDataType(type());
 }
 
+void DirectoryDataTypeController::Stop(SyncStopMetadataFate metadata_fate,
+                                       StopCallback callback) {
+  DCHECK(CalledOnValidThread());
+  Stop(metadata_fate);
+  std::move(callback).Run();
+}
+
 void DirectoryDataTypeController::GetAllNodes(
     const AllNodesCallback& callback) {
   std::unique_ptr<base::ListValue> node_list = GetAllNodesForTypeFromDirectory(
diff --git a/components/sync/driver/directory_data_type_controller.h b/components/sync/driver/directory_data_type_controller.h
index 7c3f523..a2873ea 100644
--- a/components/sync/driver/directory_data_type_controller.h
+++ b/components/sync/driver/directory_data_type_controller.h
@@ -46,11 +46,15 @@
   // the data type's ChangeProcessor registration with the backend).
   // See ModelTypeConfigurer::DeactivateDataType for more details.
   void DeactivateDataType(ModelTypeConfigurer* configurer) override;
-
+  void Stop(SyncStopMetadataFate metadata_fate, StopCallback callback) final;
   void GetAllNodes(const AllNodesCallback& callback) override;
   void GetStatusCounters(const StatusCountersCallback& callback) override;
   void RecordMemoryUsageHistogram() override;
 
+  // Convenience overload with synchronous API, since directory types are always
+  // capable of stopping immediately.
+  virtual void Stop(SyncStopMetadataFate metadata_fate) = 0;
+
   // Returns a ListValue representing all nodes for a specified type by querying
   // the directory.
   static std::unique_ptr<base::ListValue> GetAllNodesForTypeFromDirectory(
diff --git a/components/sync/driver/model_association_manager.cc b/components/sync/driver/model_association_manager.cc
index 94386c5d..35628bb 100644
--- a/components/sync/driver/model_association_manager.cc
+++ b/components/sync/driver/model_association_manager.cc
@@ -9,7 +9,9 @@
 
 #include <algorithm>
 #include <functional>
+#include <utility>
 
+#include "base/barrier_closure.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
@@ -126,38 +128,53 @@
   state_ = INITIALIZED;
   notified_about_ready_for_configure_ = false;
 
-  StopDisabledTypes(preferred_types);
-  LoadEnabledTypes();
+  DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
+  std::map<DataTypeController*, SyncStopMetadataFate> types_to_stop;
+  for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
+       it != controllers_->end(); ++it) {
+    DataTypeController* dtc = (*it).second.get();
+    // We stop a datatype if it's not desired. Independently of being desired,
+    // if the datatype is already STOPPING, we also wait for it to stop, to make
+    // sure it's ready to start again (if appropriate).
+    if ((dtc->state() != DataTypeController::NOT_RUNNING &&
+         !desired_types_.Has(dtc->type())) ||
+        dtc->state() == DataTypeController::STOPPING) {
+      const SyncStopMetadataFate metadata_fate =
+          preferred_types.Has(dtc->type()) ? KEEP_METADATA : CLEAR_METADATA;
+      types_to_stop[dtc] = metadata_fate;
+    }
+  }
+
+  // Run LoadEnabledTypes() only after all relevant types are stopped.
+  // TODO(mastiz): Add test coverage to this waiting logic, including the
+  // case where the datatype is STOPPING when this function is called.
+  base::RepeatingClosure barrier_closure = base::BarrierClosure(
+      types_to_stop.size(),
+      base::BindOnce(&ModelAssociationManager::LoadEnabledTypes,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  for (const auto& dtc_and_metadata_fate : types_to_stop) {
+    DataTypeController* dtc = dtc_and_metadata_fate.first;
+    const SyncStopMetadataFate metadata_fate = dtc_and_metadata_fate.second;
+    DVLOG(1) << "ModelAssociationManager: stop " << dtc->name() << " with "
+             << SyncStopMetadataFateToString(metadata_fate);
+    StopDatatype(SyncError(), metadata_fate, dtc, barrier_closure);
+  }
 }
 
-void ModelAssociationManager::StopDatatype(const SyncError& error,
-                                           SyncStopMetadataFate metadata_fate,
-                                           DataTypeController* dtc) {
+void ModelAssociationManager::StopDatatype(
+    const SyncError& error,
+    SyncStopMetadataFate metadata_fate,
+    DataTypeController* dtc,
+    DataTypeController::StopCallback callback) {
   loaded_types_.Remove(dtc->type());
   associated_types_.Remove(dtc->type());
   associating_types_.Remove(dtc->type());
 
-  if (error.IsSet() || dtc->state() != DataTypeController::NOT_RUNNING) {
-    // If an error was set, the delegate must be informed of the error.
-    delegate_->OnSingleDataTypeWillStop(dtc->type(), error);
-    dtc->Stop(metadata_fate);
-  }
-}
+  DCHECK(error.IsSet() || (dtc->state() != DataTypeController::NOT_RUNNING));
 
-void ModelAssociationManager::StopDisabledTypes(ModelTypeSet preferred_types) {
-  DVLOG(1) << "ModelAssociationManager: Stopping disabled types.";
-  for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
-       it != controllers_->end(); ++it) {
-    DataTypeController* dtc = (*it).second.get();
-    if (dtc->state() != DataTypeController::NOT_RUNNING &&
-        !desired_types_.Has(dtc->type())) {
-      const SyncStopMetadataFate metadata_fate =
-          preferred_types.Has(dtc->type()) ? KEEP_METADATA : CLEAR_METADATA;
-      DVLOG(1) << "ModelAssociationManager: stop " << dtc->name() << " with "
-               << SyncStopMetadataFateToString(metadata_fate);
-      StopDatatype(SyncError(), metadata_fate, dtc);
-    }
-  }
+  delegate_->OnSingleDataTypeWillStop(dtc->type(), error);
+  dtc->Stop(metadata_fate, std::move(callback));
 }
 
 void ModelAssociationManager::LoadEnabledTypes() {
@@ -248,8 +265,11 @@
   for (DataTypeController::TypeMap::const_iterator it = controllers_->begin();
        it != controllers_->end(); ++it) {
     DataTypeController* dtc = (*it).second.get();
-    if (dtc->state() != DataTypeController::NOT_RUNNING) {
-      StopDatatype(SyncError(), metadata_fate, dtc);
+    if (dtc->state() != DataTypeController::NOT_RUNNING &&
+        dtc->state() != DataTypeController::STOPPING) {
+      // We don't really wait until all datatypes have been fully stopped, which
+      // is only required (and in fact waited for) when Initialize() is called.
+      StopDatatype(SyncError(), metadata_fate, dtc, base::DoNothing());
       DVLOG(1) << "ModelAssociationManager: Stopped " << dtc->name();
     }
   }
@@ -319,7 +339,8 @@
     DVLOG(1) << "ModelAssociationManager: Type encountered an error.";
     desired_types_.Remove(type);
     DataTypeController* dtc = controllers_->find(type)->second.get();
-    StopDatatype(local_merge_result.error(), KEEP_METADATA, dtc);
+    StopDatatype(local_merge_result.error(), KEEP_METADATA, dtc,
+                 base::DoNothing());
     NotifyDelegateIfReadyForConfigure();
 
     // Update configuration result.
@@ -386,14 +407,15 @@
        it != controllers_->end(); ++it) {
     DataTypeController* dtc = (*it).second.get();
     if (associating_types_.Has(dtc->type()) &&
-        dtc->state() != DataTypeController::NOT_RUNNING) {
+        dtc->state() != DataTypeController::NOT_RUNNING &&
+        dtc->state() != DataTypeController::STOPPING) {
       // TODO(wychen): enum uma should be strongly typed. crbug.com/661401
       UMA_HISTOGRAM_ENUMERATION("Sync.ConfigureFailed",
                                 ModelTypeToHistogramInt(dtc->type()),
                                 static_cast<int>(MODEL_TYPE_COUNT));
       StopDatatype(SyncError(FROM_HERE, SyncError::DATATYPE_ERROR,
                              "Association timed out.", dtc->type()),
-                   KEEP_METADATA, dtc);
+                   KEEP_METADATA, dtc, base::DoNothing());
     }
   }
 
diff --git a/components/sync/driver/model_association_manager.h b/components/sync/driver/model_association_manager.h
index 34d04ca..96e43f1 100644
--- a/components/sync/driver/model_association_manager.h
+++ b/components/sync/driver/model_association_manager.h
@@ -111,10 +111,6 @@
   // round of association.
   void ResetForNextAssociation();
 
-  // Called by Initialize() to stop types that are not in |desired_types_|.
-  // For types that not in |preferred_types| also clears sync metadata.
-  void StopDisabledTypes(ModelTypeSet preferred_types);
-
   // Start loading non-running types that are in |desired_types_|.
   void LoadEnabledTypes();
 
@@ -138,7 +134,8 @@
   // A helper to stop an individual datatype.
   void StopDatatype(const SyncError& error,
                     SyncStopMetadataFate metadata_fate,
-                    DataTypeController* dtc);
+                    DataTypeController* dtc,
+                    DataTypeController::StopCallback callback);
 
   // Calls delegate's OnAllDataTypesReadyForConfigure when all datatypes from
   // desired_types_ are ready for configure. Ensures that for every call to
diff --git a/components/sync/driver/model_type_controller.cc b/components/sync/driver/model_type_controller.cc
index d618830..d47c32e 100644
--- a/components/sync/driver/model_type_controller.cc
+++ b/components/sync/driver/model_type_controller.cc
@@ -85,6 +85,19 @@
     std::move(task).Run(delegate);
 }
 
+// Takes the strictest policy for clearing sync metadata.
+SyncStopMetadataFate TakeStrictestMetadataFate(SyncStopMetadataFate fate1,
+                                               SyncStopMetadataFate fate2) {
+  switch (fate1) {
+    case CLEAR_METADATA:
+      return CLEAR_METADATA;
+    case KEEP_METADATA:
+      return fate2;
+  }
+  NOTREACHED();
+  return KEEP_METADATA;
+}
+
 }  // namespace
 
 ModelTypeController::ModelTypeController(
@@ -146,15 +159,27 @@
 void ModelTypeController::LoadModelsDone(ConfigureResult result,
                                          const SyncError& error) {
   DCHECK(CalledOnValidThread());
+  DCHECK_NE(NOT_RUNNING, state_);
 
-  if (state_ == NOT_RUNNING) {
-    // The callback arrived on the UI thread after the type has been already
-    // stopped.
+  if (state_ == STOPPING) {
+    DCHECK(!model_stop_callbacks_.empty());
+    // This reply to OnSyncStarting() has arrived after the type has been
+    // requested to stop.
     DVLOG(1) << "Sync start completion received late for "
              << ModelTypeToString(type()) << ", it has been stopped meanwhile";
-    // TODO(mastiz): Call to Stop() here, but think through if that's enough,
-    // because perhaps the datatype was reenabled.
     RecordStartFailure(ABORTED);
+    PostModelTask(FROM_HERE, base::BindOnce(&StopSyncHelperOnModelThread,
+                                            model_stop_metadata_fate_));
+    state_ = NOT_RUNNING;
+
+    // We make a copy in case running the callbacks has side effects and
+    // modifies the vector, although we don't expect that in practice.
+    std::vector<StopCallback> model_stop_callbacks =
+        std::move(model_stop_callbacks_);
+    DCHECK(model_stop_callbacks_.empty());
+    for (StopCallback& stop_callback : model_stop_callbacks) {
+      std::move(stop_callback).Run();
+    }
     return;
   }
 
@@ -234,13 +259,13 @@
   }
 }
 
-void ModelTypeController::Stop(SyncStopMetadataFate metadata_fate) {
+void ModelTypeController::Stop(SyncStopMetadataFate metadata_fate,
+                               StopCallback callback) {
   DCHECK(CalledOnValidThread());
 
   switch (state()) {
     case ASSOCIATING:
-    case STOPPING:
-      // We don't really use these states in this class.
+      // We don't really use this state in this class.
       NOTREACHED();
       break;
 
@@ -251,9 +276,23 @@
       // realistic scenario (disable sync during shutdown?).
       return;
 
+    case STOPPING:
+      DCHECK(!model_stop_callbacks_.empty());
+      model_stop_metadata_fate_ =
+          TakeStrictestMetadataFate(model_stop_metadata_fate_, metadata_fate);
+      model_stop_callbacks_.push_back(std::move(callback));
+      break;
+
     case MODEL_STARTING:
-      DLOG(WARNING) << "Shortcutting stop for " << ModelTypeToString(type())
+      DCHECK(!model_load_callback_.is_null());
+      DCHECK(model_stop_callbacks_.empty());
+      DLOG(WARNING) << "Deferring stop for " << ModelTypeToString(type())
                     << " because it's still starting";
+      model_stop_metadata_fate_ = metadata_fate;
+      model_stop_callbacks_.push_back(std::move(callback));
+      // The actual stop will be executed in LoadModelsDone(), when the starting
+      // process is finished.
+      state_ = STOPPING;
       break;
 
     case MODEL_LOADED:
@@ -261,10 +300,10 @@
       DVLOG(1) << "Stopping sync for " << ModelTypeToString(type());
       PostModelTask(FROM_HERE, base::BindOnce(&StopSyncHelperOnModelThread,
                                               metadata_fate));
+      state_ = NOT_RUNNING;
+      std::move(callback).Run();
       break;
   }
-
-  state_ = NOT_RUNNING;
 }
 
 DataTypeController::State ModelTypeController::state() const {
diff --git a/components/sync/driver/model_type_controller.h b/components/sync/driver/model_type_controller.h
index 6a67ed6..f96bf88 100644
--- a/components/sync/driver/model_type_controller.h
+++ b/components/sync/driver/model_type_controller.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -46,7 +47,7 @@
   void StartAssociating(const StartCallback& start_callback) override;
   void ActivateDataType(ModelTypeConfigurer* configurer) override;
   void DeactivateDataType(ModelTypeConfigurer* configurer) override;
-  void Stop(SyncStopMetadataFate metadata_fate) override;
+  void Stop(SyncStopMetadataFate metadata_fate, StopCallback callback) override;
   State state() const override;
   void GetAllNodes(const AllNodesCallback& callback) override;
   void GetStatusCounters(const StatusCountersCallback& callback) override;
@@ -89,9 +90,19 @@
   // State of this datatype controller.
   State state_;
 
-  // Callbacks for use when starting the datatype.
+  // Callback for use when starting the datatype (usually MODEL_STARTING, but
+  // STOPPING if abort requested while starting).
   ModelLoadCallback model_load_callback_;
 
+  // Callbacks for use when stopping the datatype (STOPPING), which also
+  // includes aborting a start. This is important because STOPPING is a state
+  // used to make sure we don't request two starts in parallel to the delegate,
+  // which is hard to support (most notably in ClientTagBasedProcessor). We
+  // use a vector because it's allowed to call Stop() multiple times (i.e. while
+  // STOPPING).
+  std::vector<StopCallback> model_stop_callbacks_;
+  SyncStopMetadataFate model_stop_metadata_fate_;
+
   // Controller receives |activation_response_| from
   // ClientTagBasedModelTypeProcessor callback and must temporarily own it until
   // ActivateDataType is called.
diff --git a/components/sync/driver/model_type_controller_unittest.cc b/components/sync/driver/model_type_controller_unittest.cc
index 28a944c..61f5be92 100644
--- a/components/sync/driver/model_type_controller_unittest.cc
+++ b/components/sync/driver/model_type_controller_unittest.cc
@@ -228,7 +228,7 @@
 
   void DeactivateDataTypeAndStop(SyncStopMetadataFate metadata_fate) {
     controller_->DeactivateDataType(&configurer_);
-    controller_->Stop(metadata_fate);
+    controller_->Stop(metadata_fate, base::DoNothing());
   }
 
   // These threads can ping-pong for a bit so we run the model thread twice.
@@ -378,7 +378,7 @@
 TEST_F(ModelTypeControllerTest, StopBeforeLoadModels) {
   EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
 
-  controller()->Stop(CLEAR_METADATA);
+  controller()->Stop(CLEAR_METADATA, base::DoNothing());
 
   EXPECT_EQ(DataTypeController::NOT_RUNNING, controller()->state());
   // Ensure that DisableSync is not called.
diff --git a/components/sync/driver/proxy_data_type_controller.cc b/components/sync/driver/proxy_data_type_controller.cc
index 98d1dc9d..138e603a 100644
--- a/components/sync/driver/proxy_data_type_controller.cc
+++ b/components/sync/driver/proxy_data_type_controller.cc
@@ -4,6 +4,8 @@
 
 #include "components/sync/driver/proxy_data_type_controller.h"
 
+#include <utility>
+
 #include "base/values.h"
 #include "components/sync/engine/model_safe_worker.h"
 #include "components/sync/engine/model_type_configurer.h"
@@ -53,8 +55,10 @@
                      syncer_merge_result);
 }
 
-void ProxyDataTypeController::Stop(SyncStopMetadataFate metadata_fate) {
+void ProxyDataTypeController::Stop(SyncStopMetadataFate metadata_fate,
+                                   StopCallback callback) {
   state_ = NOT_RUNNING;
+  std::move(callback).Run();
 }
 
 DataTypeController::State ProxyDataTypeController::state() const {
diff --git a/components/sync/driver/proxy_data_type_controller.h b/components/sync/driver/proxy_data_type_controller.h
index e7add5eb..3f70df6 100644
--- a/components/sync/driver/proxy_data_type_controller.h
+++ b/components/sync/driver/proxy_data_type_controller.h
@@ -28,7 +28,7 @@
   void RegisterWithBackend(base::Callback<void(bool)> set_downloaded,
                            ModelTypeConfigurer* configurer) override;
   void StartAssociating(const StartCallback& start_callback) override;
-  void Stop(SyncStopMetadataFate metadata_fate) override;
+  void Stop(SyncStopMetadataFate metadata_fate, StopCallback callback) override;
   State state() const override;
   void ActivateDataType(ModelTypeConfigurer* configurer) override;
   void DeactivateDataType(ModelTypeConfigurer* configurer) override;
diff --git a/components/sync_bookmarks/BUILD.gn b/components/sync_bookmarks/BUILD.gn
index 22b3775..8e3935dc 100644
--- a/components/sync_bookmarks/BUILD.gn
+++ b/components/sync_bookmarks/BUILD.gn
@@ -10,12 +10,16 @@
     "bookmark_change_processor.h",
     "bookmark_data_type_controller.cc",
     "bookmark_data_type_controller.h",
+    "bookmark_local_changes_builder.cc",
+    "bookmark_local_changes_builder.h",
     "bookmark_model_associator.cc",
     "bookmark_model_associator.h",
     "bookmark_model_observer_impl.cc",
     "bookmark_model_observer_impl.h",
     "bookmark_model_type_processor.cc",
     "bookmark_model_type_processor.h",
+    "bookmark_remote_updates_handler.cc",
+    "bookmark_remote_updates_handler.h",
     "bookmark_sync_service.cc",
     "bookmark_sync_service.h",
     "synced_bookmark_tracker.cc",
@@ -41,6 +45,7 @@
     "bookmark_data_type_controller_unittest.cc",
     "bookmark_model_observer_impl_unittest.cc",
     "bookmark_model_type_processor_unittest.cc",
+    "bookmark_remote_updates_handler_unittest.cc",
     "synced_bookmark_tracker_unittest.cc",
   ]
 
diff --git a/components/sync_bookmarks/bookmark_local_changes_builder.cc b/components/sync_bookmarks/bookmark_local_changes_builder.cc
new file mode 100644
index 0000000..5800eb4
--- /dev/null
+++ b/components/sync_bookmarks/bookmark_local_changes_builder.cc
@@ -0,0 +1,106 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync_bookmarks/bookmark_local_changes_builder.h"
+
+#include <string>
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+#include "components/sync/base/time.h"
+#include "components/sync/protocol/bookmark_model_metadata.pb.h"
+#include "components/sync_bookmarks/synced_bookmark_tracker.h"
+
+namespace sync_bookmarks {
+
+namespace {
+
+sync_pb::EntitySpecifics SpecificsFromBookmarkNode(
+    const bookmarks::BookmarkNode* node) {
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::BookmarkSpecifics* bm_specifics = specifics.mutable_bookmark();
+  bm_specifics->set_url(node->url().spec());
+  // TODO(crbug.com/516866): Set the favicon.
+  bm_specifics->set_title(base::UTF16ToUTF8(node->GetTitle()));
+  bm_specifics->set_creation_time_us(
+      node->date_added().ToDeltaSinceWindowsEpoch().InMicroseconds());
+
+  bm_specifics->set_icon_url(node->icon_url() ? node->icon_url()->spec()
+                                              : std::string());
+
+  for (const std::pair<std::string, std::string>& pair :
+       *node->GetMetaInfoMap()) {
+    sync_pb::MetaInfo* meta_info = bm_specifics->add_meta_info();
+    meta_info->set_key(pair.first);
+    meta_info->set_value(pair.second);
+  }
+  return specifics;
+}
+
+}  // namespace
+
+BookmarkLocalChangesBuilder::BookmarkLocalChangesBuilder(
+    const SyncedBookmarkTracker* const bookmark_tracker)
+    : bookmark_tracker_(bookmark_tracker) {
+  DCHECK(bookmark_tracker);
+}
+
+std::vector<syncer::CommitRequestData>
+BookmarkLocalChangesBuilder::BuildCommitRequests(size_t max_entries) const {
+  DCHECK(bookmark_tracker_);
+  const std::vector<const SyncedBookmarkTracker::Entity*>
+      entities_with_local_changes =
+          bookmark_tracker_->GetEntitiesWithLocalChanges(max_entries);
+  DCHECK_LE(entities_with_local_changes.size(), max_entries);
+
+  std::vector<syncer::CommitRequestData> commit_requests;
+  for (const SyncedBookmarkTracker::Entity* entity :
+       entities_with_local_changes) {
+    DCHECK(entity->IsUnsynced());
+    const sync_pb::EntityMetadata* metadata = entity->metadata();
+
+    syncer::CommitRequestData request;
+    syncer::EntityData data;
+    data.id = metadata->server_id();
+    data.creation_time = syncer::ProtoTimeToTime(metadata->creation_time());
+    data.modification_time =
+        syncer::ProtoTimeToTime(metadata->modification_time());
+    if (!metadata->is_deleted()) {
+      const bookmarks::BookmarkNode* node = entity->bookmark_node();
+      DCHECK(node);
+      const bookmarks::BookmarkNode* parent = node->parent();
+      const SyncedBookmarkTracker::Entity* parent_entity =
+          bookmark_tracker_->GetEntityForBookmarkNode(parent);
+      DCHECK(parent_entity);
+      data.parent_id = parent_entity->metadata()->server_id();
+      // TODO(crbug.com/516866): Double check that custom passphrase works well
+      // with this implementation, because:
+      // 1. NonBlockingTypeCommitContribution::AdjustCommitProto() clears the
+      //    title out.
+      // 2. Bookmarks (maybe ancient legacy bookmarks only?) use/used |name| to
+      //    encode the title.
+      data.is_folder = node->is_folder();
+      // TODO(crbug.com/516866): Set the non_unique_name similar to directory
+      // implementation.
+      // https://cs.chromium.org/chromium/src/components/sync/syncable/write_node.cc?l=41&rcl=1675007db1e0eb03417e81442688bb11cd181f58
+      data.non_unique_name = base::UTF16ToUTF8(node->GetTitle());
+      data.unique_position = parent_entity->metadata()->unique_position();
+      // In case of deletion, make an EntityData with empty specifics to
+      // indicate deletion.
+      data.specifics = SpecificsFromBookmarkNode(node);
+    }
+    request.entity = data.PassToPtr();
+    request.sequence_number = metadata->sequence_number();
+    request.base_version = metadata->server_version();
+    // Specifics hash has been computed in the tracker when this entity has been
+    // added/updated.
+    request.specifics_hash = metadata->specifics_hash();
+
+    commit_requests.push_back(std::move(request));
+  }
+  return commit_requests;
+}
+
+}  // namespace sync_bookmarks
diff --git a/components/sync_bookmarks/bookmark_local_changes_builder.h b/components/sync_bookmarks/bookmark_local_changes_builder.h
new file mode 100644
index 0000000..0a5fd06
--- /dev/null
+++ b/components/sync_bookmarks/bookmark_local_changes_builder.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_LOCAL_CHANGES_BUILDER_H_
+#define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_LOCAL_CHANGES_BUILDER_H_
+
+#include <vector>
+
+#include "components/sync/engine/non_blocking_sync_common.h"
+
+namespace sync_bookmarks {
+
+class SyncedBookmarkTracker;
+
+class BookmarkLocalChangesBuilder {
+ public:
+  // |bookmark_tracker| must not be null and must outlive this object.
+  explicit BookmarkLocalChangesBuilder(
+      const SyncedBookmarkTracker* bookmark_tracker);
+  // Builds the commit requests list.
+  std::vector<syncer::CommitRequestData> BuildCommitRequests(
+      size_t max_entries) const;
+
+ private:
+  const SyncedBookmarkTracker* const bookmark_tracker_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkLocalChangesBuilder);
+};
+
+}  // namespace sync_bookmarks
+
+#endif  // COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_LOCAL_CHANGES_BUILDER_H_
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.cc b/components/sync_bookmarks/bookmark_model_type_processor.cc
index a3e4578..c685b55 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -7,138 +7,24 @@
 #include <utility>
 
 #include "base/callback.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/sync/base/model_type.h"
-#include "components/sync/base/time.h"
 #include "components/sync/engine/commit_queue.h"
 #include "components/sync/engine/model_type_processor_proxy.h"
 #include "components/sync/model/data_type_activation_request.h"
 #include "components/sync/protocol/bookmark_model_metadata.pb.h"
+#include "components/sync_bookmarks/bookmark_local_changes_builder.h"
 #include "components/sync_bookmarks/bookmark_model_observer_impl.h"
+#include "components/sync_bookmarks/bookmark_remote_updates_handler.h"
 #include "components/undo/bookmark_undo_utils.h"
 
 namespace sync_bookmarks {
 
 namespace {
 
-// The sync protocol identifies top-level entities by means of well-known tags,
-// (aka server defined tags) which should not be confused with titles or client
-// tags that aren't supported by bookmarks (at the time of writing). Each tag
-// corresponds to a singleton instance of a particular top-level node in a
-// user's share; the tags are consistent across users. The tags allow us to
-// locate the specific folders whose contents we care about synchronizing,
-// without having to do a lookup by name or path.  The tags should not be made
-// user-visible. For example, the tag "bookmark_bar" represents the permanent
-// node for bookmarks bar in Chrome. The tag "other_bookmarks" represents the
-// permanent folder Other Bookmarks in Chrome.
-//
-// It is the responsibility of something upstream (at time of writing, the sync
-// server) to create these tagged nodes when initializing sync for the first
-// time for a user.  Thus, once the backend finishes initializing, the
-// ProfileSyncService can rely on the presence of tagged nodes.
-const char kBookmarkBarTag[] = "bookmark_bar";
-const char kMobileBookmarksTag[] = "synced_bookmarks";
-const char kOtherBookmarksTag[] = "other_bookmarks";
-
-// Id is created by concatenating the specifics field number and the server tag
-// similar to LookbackServerEntity::CreateId() that uses
-// GetSpecificsFieldNumberFromModelType() to compute the field number.
-static const char kBookmarksRootId[] = "32904_google_chrome_bookmarks";
-
-// |sync_entity| must contain a bookmark specifics.
-// Metainfo entries must have unique keys.
-bookmarks::BookmarkNode::MetaInfoMap GetBookmarkMetaInfo(
-    const syncer::EntityData& sync_entity) {
-  const sync_pb::BookmarkSpecifics& specifics =
-      sync_entity.specifics.bookmark();
-  bookmarks::BookmarkNode::MetaInfoMap meta_info_map;
-  for (const sync_pb::MetaInfo& meta_info : specifics.meta_info()) {
-    meta_info_map[meta_info.key()] = meta_info.value();
-  }
-  DCHECK_EQ(static_cast<size_t>(specifics.meta_info_size()),
-            meta_info_map.size());
-  return meta_info_map;
-}
-
-// Creates a bookmark node under the given parent node from the given sync node.
-// Returns the newly created node. |sync_entity| must contain a bookmark
-// specifics with Metainfo entries having unique keys.
-const bookmarks::BookmarkNode* CreateBookmarkNode(
-    const syncer::EntityData& sync_entity,
-    const bookmarks::BookmarkNode* parent,
-    bookmarks::BookmarkModel* model,
-    int index) {
-  DCHECK(parent);
-  DCHECK(model);
-
-  const sync_pb::BookmarkSpecifics& specifics =
-      sync_entity.specifics.bookmark();
-  bookmarks::BookmarkNode::MetaInfoMap metainfo =
-      GetBookmarkMetaInfo(sync_entity);
-  if (sync_entity.is_folder) {
-    return model->AddFolderWithMetaInfo(
-        parent, index, base::UTF8ToUTF16(specifics.title()), &metainfo);
-  }
-  // 'creation_time_us' was added in M24. Assume a time of 0 means now.
-  const int64_t create_time_us = specifics.creation_time_us();
-  base::Time create_time =
-      (create_time_us == 0)
-          ? base::Time::Now()
-          : base::Time::FromDeltaSinceWindowsEpoch(
-                // Use FromDeltaSinceWindowsEpoch because create_time_us has
-                // always used the Windows epoch.
-                base::TimeDelta::FromMicroseconds(create_time_us));
-  return model->AddURLWithCreationTimeAndMetaInfo(
-      parent, index, base::UTF8ToUTF16(specifics.title()),
-      GURL(specifics.url()), create_time, &metainfo);
-  // TODO(crbug.com/516866): Add the favicon related code.
-}
-
-// Check whether an incoming specifics represent a valid bookmark or not.
-// |is_folder| is whether this specifics is for a folder or not.
-// Folders and tomstones entail different validation conditions.
-bool IsValidBookmark(const sync_pb::BookmarkSpecifics& specifics,
-                     bool is_folder) {
-  if (specifics.ByteSize() == 0) {
-    DLOG(ERROR) << "Invalid bookmark: empty specifics.";
-    return false;
-  }
-  if (is_folder) {
-    return true;
-  }
-  if (!GURL(specifics.url()).is_valid()) {
-    DLOG(ERROR) << "Invalid bookmark: invalid url in the specifics.";
-    return false;
-  }
-  return true;
-}
-
-sync_pb::EntitySpecifics SpecificsFromBookmarkNode(
-    const bookmarks::BookmarkNode* node) {
-  sync_pb::EntitySpecifics specifics;
-  sync_pb::BookmarkSpecifics* bm_specifics = specifics.mutable_bookmark();
-  bm_specifics->set_url(node->url().spec());
-  // TODO(crbug.com/516866): Set the favicon.
-  bm_specifics->set_title(base::UTF16ToUTF8(node->GetTitle()));
-  bm_specifics->set_creation_time_us(
-      node->date_added().ToDeltaSinceWindowsEpoch().InMicroseconds());
-
-  bm_specifics->set_icon_url(node->icon_url() ? node->icon_url()->spec()
-                                              : std::string());
-
-  for (const std::pair<std::string, std::string>& pair :
-       *node->GetMetaInfoMap()) {
-    sync_pb::MetaInfo* meta_info = bm_specifics->add_meta_info();
-    meta_info->set_key(pair.first);
-    meta_info->set_value(pair.second);
-  }
-  return specifics;
-}
-
 class ScopedRemoteUpdateBookmarks {
  public:
   // |bookmark_model|, |bookmark_undo_service| and |observer| must not be null
@@ -178,6 +64,7 @@
 
   DISALLOW_COPY_AND_ASSIGN(ScopedRemoteUpdateBookmarks);
 };
+
 }  // namespace
 
 BookmarkModelTypeProcessor::BookmarkModelTypeProcessor(
@@ -213,8 +100,9 @@
     size_t max_entries,
     const GetLocalChangesCallback& callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  BookmarkLocalChangesBuilder builder(bookmark_tracker_.get());
   std::vector<syncer::CommitRequestData> local_changes =
-      BuildCommitRequestsForLocalChanges(max_entries);
+      builder.BuildCommitRequests(max_entries);
   callback.Run(std::move(local_changes));
 }
 
@@ -256,36 +144,11 @@
 
   ScopedRemoteUpdateBookmarks update_bookmarks(
       bookmark_model_, bookmark_undo_service_, bookmark_model_observer_.get());
-
-  for (const syncer::UpdateResponseData* update : ReorderUpdates(updates)) {
-    const syncer::EntityData& update_entity = update->entity.value();
-    // TODO(crbug.com/516866): Check |update_entity| for sanity.
-    // 1. Has bookmark specifics or no specifics in case of delete.
-    // 2. All meta info entries in the specifics have unique keys.
-    const SyncedBookmarkTracker::Entity* tracked_entity =
-        bookmark_tracker_->GetEntityForSyncId(update_entity.id);
-    if (update_entity.is_deleted()) {
-      ProcessRemoteDelete(update_entity, tracked_entity);
-      continue;
-    }
-    if (!tracked_entity) {
-      ProcessRemoteCreate(*update);
-      continue;
-    }
-    // Ignore changes to the permanent nodes (e.g. bookmarks bar). We only care
-    // about their children.
-    if (bookmark_model_->is_permanent_node(tracked_entity->bookmark_node())) {
-      continue;
-    }
-    ProcessRemoteUpdate(*update, tracked_entity);
-  }
-}
-
-// static
-std::vector<const syncer::UpdateResponseData*>
-BookmarkModelTypeProcessor::ReorderUpdatesForTest(
-    const syncer::UpdateResponseDataList& updates) {
-  return ReorderUpdates(updates);
+  BookmarkRemoteUpdatesHandler updates_handler(bookmark_model_,
+                                               bookmark_tracker_.get());
+  updates_handler.Process(updates);
+  // Schedule save just in case one is needed.
+  schedule_save_closure_.Run();
 }
 
 const SyncedBookmarkTracker* BookmarkModelTypeProcessor::GetTrackerForTest()
@@ -293,216 +156,6 @@
   return bookmark_tracker_.get();
 }
 
-// static
-std::vector<const syncer::UpdateResponseData*>
-BookmarkModelTypeProcessor::ReorderUpdates(
-    const syncer::UpdateResponseDataList& updates) {
-  // TODO(crbug.com/516866): This is a very simple (hacky) reordering algorithm
-  // that assumes no folders exist except the top level permanent ones. This
-  // should be fixed before enabling USS for bookmarks.
-  std::vector<const syncer::UpdateResponseData*> ordered_updates;
-  for (const syncer::UpdateResponseData& update : updates) {
-    const syncer::EntityData& update_entity = update.entity.value();
-    if (update_entity.parent_id == "0") {
-      continue;
-    }
-    if (update_entity.parent_id == kBookmarksRootId) {
-      ordered_updates.push_back(&update);
-    }
-  }
-  for (const syncer::UpdateResponseData& update : updates) {
-    const syncer::EntityData& update_entity = update.entity.value();
-    // Deletions should come last.
-    if (update_entity.is_deleted()) {
-      continue;
-    }
-    if (update_entity.parent_id != "0" &&
-        update_entity.parent_id != kBookmarksRootId) {
-      ordered_updates.push_back(&update);
-    }
-  }
-  // Now add deletions.
-  for (const syncer::UpdateResponseData& update : updates) {
-    const syncer::EntityData& update_entity = update.entity.value();
-    if (!update_entity.is_deleted()) {
-      continue;
-    }
-    if (update_entity.parent_id != "0" &&
-        update_entity.parent_id != kBookmarksRootId) {
-      ordered_updates.push_back(&update);
-    }
-  }
-  return ordered_updates;
-}
-
-void BookmarkModelTypeProcessor::ProcessRemoteCreate(
-    const syncer::UpdateResponseData& update) {
-  // Because the Synced Bookmarks node can be created server side, it's possible
-  // it'll arrive at the client as an update. In that case it won't have been
-  // associated at startup, the GetChromeNodeFromSyncId call above will return
-  // null, and we won't detect it as a permanent node, resulting in us trying to
-  // create it here (which will fail). Therefore, we add special logic here just
-  // to detect the Synced Bookmarks folder.
-  const syncer::EntityData& update_entity = update.entity.value();
-  DCHECK(!update_entity.is_deleted());
-  if (update_entity.parent_id == kBookmarksRootId) {
-    // Associate permanent folders.
-    // TODO(crbug.com/516866): Method documentation says this method should be
-    // used in initial sync only. Make sure this is the case.
-    AssociatePermanentFolder(update);
-    return;
-  }
-  if (!IsValidBookmark(update_entity.specifics.bookmark(),
-                       update_entity.is_folder)) {
-    // Ignore creations with invalid specifics.
-    DLOG(ERROR) << "Couldn't add bookmark with an invalid specifics.";
-    return;
-  }
-  const bookmarks::BookmarkNode* parent_node = GetParentNode(update_entity);
-  if (!parent_node) {
-    // If we cannot find the parent, we can do nothing.
-    DLOG(ERROR) << "Could not find parent of node being added."
-                << " Node title: " << update_entity.specifics.bookmark().title()
-                << ", parent id = " << update_entity.parent_id;
-    return;
-  }
-  // TODO(crbug.com/516866): This code appends the code to the very end of the
-  // list of the children by assigning the index to the
-  // parent_node->child_count(). It should instead compute the exact using the
-  // unique position information of the new node as well as the siblings.
-  const bookmarks::BookmarkNode* bookmark_node = CreateBookmarkNode(
-      update_entity, parent_node, bookmark_model_, parent_node->child_count());
-  if (!bookmark_node) {
-    // We ignore bookmarks we can't add.
-    DLOG(ERROR) << "Failed to create bookmark node with title "
-                << update_entity.specifics.bookmark().title() << " and url "
-                << update_entity.specifics.bookmark().url();
-    return;
-  }
-  bookmark_tracker_->Add(update_entity.id, bookmark_node,
-                         update.response_version, update_entity.creation_time,
-                         update_entity.unique_position,
-                         update_entity.specifics);
-}
-
-void BookmarkModelTypeProcessor::ProcessRemoteUpdate(
-    const syncer::UpdateResponseData& update,
-    const SyncedBookmarkTracker::Entity* tracked_entity) {
-  const syncer::EntityData& update_entity = update.entity.value();
-  // Can only update existing nodes.
-  DCHECK(tracked_entity);
-  DCHECK_EQ(tracked_entity,
-            bookmark_tracker_->GetEntityForSyncId(update_entity.id));
-  // Must not be a deletion.
-  DCHECK(!update_entity.is_deleted());
-  if (!IsValidBookmark(update_entity.specifics.bookmark(),
-                       update_entity.is_folder)) {
-    // Ignore updates with invalid specifics.
-    DLOG(ERROR) << "Couldn't update bookmark with an invalid specifics.";
-    return;
-  }
-  if (tracked_entity->IsUnsynced()) {
-    // TODO(crbug.com/516866): Handle conflict resolution.
-    return;
-  }
-  if (tracked_entity->MatchesData(update_entity)) {
-    bookmark_tracker_->Update(update_entity.id, update.response_version,
-                              update_entity.modification_time,
-                              update_entity.specifics);
-    // Since there is no change in the model data, we should trigger data
-    // persistence here to save latest metadata.
-    schedule_save_closure_.Run();
-    return;
-  }
-  const bookmarks::BookmarkNode* node = tracked_entity->bookmark_node();
-  if (update_entity.is_folder != node->is_folder()) {
-    DLOG(ERROR) << "Could not update node. Remote node is a "
-                << (update_entity.is_folder ? "folder" : "bookmark")
-                << " while local node is a "
-                << (node->is_folder() ? "folder" : "bookmark");
-    return;
-  }
-  const sync_pb::BookmarkSpecifics& specifics =
-      update_entity.specifics.bookmark();
-  if (!update_entity.is_folder) {
-    bookmark_model_->SetURL(node, GURL(specifics.url()));
-  }
-
-  bookmark_model_->SetTitle(node, base::UTF8ToUTF16(specifics.title()));
-  // TODO(crbug.com/516866): Add the favicon related code.
-  bookmark_model_->SetNodeMetaInfoMap(node, GetBookmarkMetaInfo(update_entity));
-  bookmark_tracker_->Update(update_entity.id, update.response_version,
-                            update_entity.modification_time,
-                            update_entity.specifics);
-  // TODO(crbug.com/516866): Handle reparenting.
-  // TODO(crbug.com/516866): Handle the case of moving the bookmark to a new
-  // position under the same parent (i.e. change in the unique position)
-}
-
-void BookmarkModelTypeProcessor::ProcessRemoteDelete(
-    const syncer::EntityData& update_entity,
-    const SyncedBookmarkTracker::Entity* tracked_entity) {
-  DCHECK(update_entity.is_deleted());
-
-  DCHECK_EQ(tracked_entity,
-            bookmark_tracker_->GetEntityForSyncId(update_entity.id));
-
-  // Handle corner cases first.
-  if (tracked_entity == nullptr) {
-    // Local entity doesn't exist and update is tombstone.
-    DLOG(WARNING) << "Received remote delete for a non-existing item.";
-    return;
-  }
-
-  const bookmarks::BookmarkNode* node = tracked_entity->bookmark_node();
-  // Ignore changes to the permanent top-level nodes.  We only care about
-  // their children.
-  if (bookmark_model_->is_permanent_node(node)) {
-    return;
-  }
-  // TODO(crbug.com/516866): Allow deletions of non-empty direcoties if makes
-  // sense, and recursively delete children.
-  if (node->child_count() > 0) {
-    DLOG(WARNING) << "Trying to delete a non-empty folder.";
-    return;
-  }
-
-  bookmark_model_->Remove(node);
-  bookmark_tracker_->Remove(update_entity.id);
-}
-
-const bookmarks::BookmarkNode* BookmarkModelTypeProcessor::GetParentNode(
-    const syncer::EntityData& update_entity) const {
-  const SyncedBookmarkTracker::Entity* parent_entity =
-      bookmark_tracker_->GetEntityForSyncId(update_entity.parent_id);
-  if (!parent_entity) {
-    return nullptr;
-  }
-  return parent_entity->bookmark_node();
-}
-
-void BookmarkModelTypeProcessor::AssociatePermanentFolder(
-    const syncer::UpdateResponseData& update) {
-  const syncer::EntityData& update_entity = update.entity.value();
-  DCHECK_EQ(update_entity.parent_id, kBookmarksRootId);
-
-  const bookmarks::BookmarkNode* permanent_node = nullptr;
-  if (update_entity.server_defined_unique_tag == kBookmarkBarTag) {
-    permanent_node = bookmark_model_->bookmark_bar_node();
-  } else if (update_entity.server_defined_unique_tag == kOtherBookmarksTag) {
-    permanent_node = bookmark_model_->other_node();
-  } else if (update_entity.server_defined_unique_tag == kMobileBookmarksTag) {
-    permanent_node = bookmark_model_->mobile_node();
-  }
-
-  if (permanent_node != nullptr) {
-    bookmark_tracker_->Add(update_entity.id, permanent_node,
-                           update.response_version, update_entity.creation_time,
-                           update_entity.unique_position,
-                           update_entity.specifics);
-  }
-}
-
 std::string BookmarkModelTypeProcessor::EncodeSyncMetadata() const {
   std::string metadata_str;
   if (bookmark_tracker_) {
@@ -513,7 +166,7 @@
   return metadata_str;
 }
 
-void BookmarkModelTypeProcessor::DecodeSyncMetadata(
+void BookmarkModelTypeProcessor::ModelReadyToSync(
     const std::string& metadata_str,
     const base::RepeatingClosure& schedule_save_closure,
     bookmarks::BookmarkModel* model) {
@@ -652,63 +305,6 @@
   }
 }
 
-std::vector<syncer::CommitRequestData>
-BookmarkModelTypeProcessor::BuildCommitRequestsForLocalChanges(
-    size_t max_entries) {
-  DCHECK(bookmark_tracker_);
-  const std::vector<const SyncedBookmarkTracker::Entity*>
-      entities_with_local_changes =
-          bookmark_tracker_->GetEntitiesWithLocalChanges(max_entries);
-  DCHECK_LE(entities_with_local_changes.size(), max_entries);
-
-  std::vector<syncer::CommitRequestData> commit_requests;
-  for (const SyncedBookmarkTracker::Entity* entity :
-       entities_with_local_changes) {
-    DCHECK(entity->IsUnsynced());
-    const sync_pb::EntityMetadata* metadata = entity->metadata();
-
-    syncer::CommitRequestData request;
-    syncer::EntityData data;
-    data.id = metadata->server_id();
-    data.creation_time = syncer::ProtoTimeToTime(metadata->creation_time());
-    data.modification_time =
-        syncer::ProtoTimeToTime(metadata->modification_time());
-    if (!metadata->is_deleted()) {
-      const bookmarks::BookmarkNode* node = entity->bookmark_node();
-      DCHECK(node);
-      const bookmarks::BookmarkNode* parent = node->parent();
-      const SyncedBookmarkTracker::Entity* parent_entity =
-          bookmark_tracker_->GetEntityForBookmarkNode(parent);
-      DCHECK(parent_entity);
-      data.parent_id = parent_entity->metadata()->server_id();
-      // TODO(crbug.com/516866): Double check that custom passphrase works well
-      // with this implementation, because:
-      // 1. NonBlockingTypeCommitContribution::AdjustCommitProto() clears the
-      //    title out.
-      // 2. Bookmarks (maybe ancient legacy bookmarks only?) use/used |name| to
-      //    encode the title.
-      data.is_folder = node->is_folder();
-      // TODO(crbug.com/516866): Set the non_unique_name similar to directory
-      // implementation.
-      // https://cs.chromium.org/chromium/src/components/sync/syncable/write_node.cc?l=41&rcl=1675007db1e0eb03417e81442688bb11cd181f58
-      data.non_unique_name = base::UTF16ToUTF8(node->GetTitle());
-      data.unique_position = parent_entity->metadata()->unique_position();
-      // In case of deletion, make an EntityData with empty specifics to
-      // indicate deletion.
-      data.specifics = SpecificsFromBookmarkNode(node);
-    }
-    request.entity = data.PassToPtr();
-    request.sequence_number = metadata->sequence_number();
-    request.base_version = metadata->server_version();
-    // Specifics hash has been computed in the tracker when this entity has been
-    // added/updated.
-    request.specifics_hash = metadata->specifics_hash();
-
-    commit_requests.push_back(std::move(request));
-  }
-  return commit_requests;
-}
-
 void BookmarkModelTypeProcessor::StartTrackingMetadata(
     std::vector<NodeMetadataPair> nodes_metadata,
     std::unique_ptr<sync_pb::ModelTypeState> model_type_state) {
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.h b/components/sync_bookmarks/bookmark_model_type_processor.h
index 420f6531..5dc106eb 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.h
+++ b/components/sync_bookmarks/bookmark_model_type_processor.h
@@ -22,7 +22,6 @@
 
 namespace bookmarks {
 class BookmarkModel;
-class BookmarkNode;
 }
 
 namespace sync_bookmarks {
@@ -57,7 +56,7 @@
   void RecordMemoryUsageHistogram() override;
 
   // Encodes all sync metadata into a string, representing a state that can be
-  // restored via DecodeSyncMetadata() below.
+  // restored via ModelReadyToSync() below.
   std::string EncodeSyncMetadata() const;
 
   // It mainly decodes a BookmarkModelMetadata proto seralized in
@@ -67,13 +66,9 @@
   // used for further model operations. |schedule_save_closure| is a repeating
   // closure used to schedule a save of the bookmark model together with the
   // metadata.
-  void DecodeSyncMetadata(const std::string& metadata_str,
-                          const base::RepeatingClosure& schedule_save_closure,
-                          bookmarks::BookmarkModel* model);
-
-  // Public for testing.
-  static std::vector<const syncer::UpdateResponseData*> ReorderUpdatesForTest(
-      const syncer::UpdateResponseDataList& updates);
+  void ModelReadyToSync(const std::string& metadata_str,
+                        const base::RepeatingClosure& schedule_save_closure,
+                        bookmarks::BookmarkModel* model);
 
   const SyncedBookmarkTracker* GetTrackerForTest() const;
 
@@ -82,51 +77,6 @@
  private:
   SEQUENCE_CHECKER(sequence_checker_);
 
-  // Reorders incoming updates such that parent creation is before child
-  // creation and child deletion is before parent deletion, and deletions should
-  // come last. The returned pointers point to the elements in the original
-  // |updates|.
-  static std::vector<const syncer::UpdateResponseData*> ReorderUpdates(
-      const syncer::UpdateResponseDataList& updates);
-
-  // Given a remote update entity, it returns the parent bookmark node of the
-  // corresponding node. It returns null if the parent node cannot be found.
-  const bookmarks::BookmarkNode* GetParentNode(
-      const syncer::EntityData& update_entity) const;
-
-  // Processes a remote creation of a bookmark node.
-  // 1. For permanent folders, they are only registered in |bookmark_tracker_|.
-  // 2. If the nodes parent cannot be found, the remote creation update is
-  //    ignored.
-  // 3. Otherwise, a new node is created in the local bookmark model and
-  //    registered in |bookmark_tracker_|.
-  void ProcessRemoteCreate(const syncer::UpdateResponseData& update);
-
-  // Processes a remote update of a bookmark node. |update| must not be a
-  // deletion, and the server_id must be already tracked, otherwise, it is a
-  // creation that gets handeled in ProcessRemoteCreate(). |tracked_entity| is
-  // the tracked entity for that server_id. It is passed as a dependency instead
-  // of performing a lookup inside ProcessRemoteUpdate() to avoid wasting CPU
-  // cycles for doing another lookup (this code runs on the UI thread).
-  void ProcessRemoteUpdate(const syncer::UpdateResponseData& update,
-                           const SyncedBookmarkTracker::Entity* tracked_entity);
-
-  // Process a remote delete of a bookmark node. |update_entity| must not be a
-  // deletion. |tracked_entity| is the tracked entity for that server_id. It is
-  // passed as a dependency instead of performing a lookup inside
-  // ProcessRemoteDelete() to avoid wasting CPU cycles for doing another lookup
-  // (this code runs on the UI thread).
-  void ProcessRemoteDelete(const syncer::EntityData& update_entity,
-                           const SyncedBookmarkTracker::Entity* tracked_entity);
-
-  // Associates the permanent bookmark folders with the corresponding server
-  // side ids and registers the association in |bookmark_tracker_|.
-  // |update_entity| must contain server_defined_unique_tag that is used to
-  // determine the corresponding permanent node. All permanent nodes are assumed
-  // to be directly children nodes of |kBookmarksRootId|. This method is used in
-  // the initial sync cycle only.
-  void AssociatePermanentFolder(const syncer::UpdateResponseData& update);
-
   // If preconditions are met, inform sync that we are ready to connect.
   void ConnectIfReady();
 
@@ -135,10 +85,6 @@
   // entities.
   void NudgeForCommitIfNeeded();
 
-  // Builds the commit requests list.
-  std::vector<syncer::CommitRequestData> BuildCommitRequestsForLocalChanges(
-      size_t max_entries);
-
   // Instantiates the required objects to track metadata and starts observing
   // changes from the bookmark model.
   void StartTrackingMetadata(
@@ -146,11 +92,11 @@
       std::unique_ptr<sync_pb::ModelTypeState> model_type_state);
 
   // Stores the start callback in between OnSyncStarting() and
-  // DecodeSyncMetadata().
+  // ModelReadyToSync().
   StartCallback start_callback_;
 
   // The bookmark model we are processing local changes from and forwarding
-  // remote changes to. It is set during DecodeSyncMetadata(), which is called
+  // remote changes to. It is set during ModelReadyToSync(), which is called
   // during startup, as part of the bookmark-loading process.
   bookmarks::BookmarkModel* bookmark_model_ = nullptr;
 
@@ -172,8 +118,10 @@
   std::unique_ptr<syncer::CommitQueue> worker_;
 
   // Keeps the mapping between server ids and bookmarks nodes together with sync
-  // metadata. It is constructed and set during DecodeSyncMetadata(), which is
-  // called during startup, as part of the bookmark-loading process.
+  // metadata. It is constructed and set during ModelReadyToSync(), if the
+  // loaded bookmarks JSON contained previous sync metadata, or upon completion
+  // of initial sync, which is called during startup, as part of the
+  // bookmark-loading process.
   std::unique_ptr<SyncedBookmarkTracker> bookmark_tracker_;
 
   // GUID string that identifies the sync client and is received from the sync
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index 1b52f13..63af6deb 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -25,9 +25,6 @@
 
 namespace {
 
-// The parent tag for children of the root entity. Entities with this parent are
-// referred to as top level enities.
-const char kRootParentTag[] = "0";
 const char kBookmarkBarTag[] = "bookmark_bar";
 const char kBookmarkBarId[] = "bookmark_bar_id";
 const char kBookmarksRootId[] = "32904_google_chrome_bookmarks";
@@ -119,12 +116,6 @@
   return response_data;
 }
 
-syncer::UpdateResponseData CreateBookmarkRootUpdateData() {
-  return CreateUpdateData({syncer::ModelTypeToRootTag(syncer::BOOKMARKS),
-                           std::string(), std::string(), kRootParentTag,
-                           syncer::ModelTypeToRootTag(syncer::BOOKMARKS)});
-}
-
 class TestSyncClient : public syncer::FakeSyncClient {
  public:
   explicit TestSyncClient(bookmarks::BookmarkModel* bookmark_model)
@@ -147,8 +138,9 @@
     // TODO(crbug.com/516866): This class assumes model is loaded and sync has
     // started before running tests. We should test other variations (i.e. model
     // isn't loaded yet and/or sync didn't start yet).
-    processor_.DecodeSyncMetadata(std::string(), schedule_save_closure_.Get(),
-                                  bookmark_model_.get());
+    processor_.ModelReadyToSync(/*metadata_str=*/std::string(),
+                                schedule_save_closure_.Get(),
+                                bookmark_model_.get());
     syncer::DataTypeActivationRequest request;
     request.cache_guid = kCacheGuid;
     processor_.OnSyncStarting(request, base::DoNothing());
@@ -169,38 +161,6 @@
   BookmarkModelTypeProcessor processor_;
 };
 
-TEST(BookmarkModelTypeProcessorReorderUpdatesTest, ShouldIgnoreRootNodes) {
-  syncer::UpdateResponseDataList updates;
-  updates.push_back(CreateBookmarkRootUpdateData());
-  std::vector<const syncer::UpdateResponseData*> ordered_updates =
-      BookmarkModelTypeProcessor::ReorderUpdatesForTest(updates);
-  // Root node update should be filtered out.
-  EXPECT_THAT(ordered_updates.size(), Eq(0U));
-}
-
-// TODO(crbug.com/516866): This should change to cover the general case of
-// parents before children for non-deletions, and another test should be added
-// for children before parents for deletions.
-TEST(BookmarkModelTypeProcessorReorderUpdatesTest,
-     ShouldPlacePermanentNodesFirstForNonDeletions) {
-  const std::string kNode1Id = "node1";
-  const std::string kNode2Id = "node2";
-  syncer::UpdateResponseDataList updates;
-  updates.push_back(CreateUpdateData(
-      {kNode1Id, std::string(), std::string(), kNode2Id, std::string()}));
-  updates.push_back(CreateUpdateData({kNode2Id, std::string(), std::string(),
-                                      kBookmarksRootId, kBookmarkBarTag}));
-  std::vector<const syncer::UpdateResponseData*> ordered_updates =
-      BookmarkModelTypeProcessor::ReorderUpdatesForTest(updates);
-
-  // No update should be dropped.
-  ASSERT_THAT(ordered_updates.size(), Eq(2U));
-
-  // Updates should be ordered such that parent node update comes first.
-  EXPECT_THAT(ordered_updates[0]->entity.value().id, Eq(kNode2Id));
-  EXPECT_THAT(ordered_updates[1]->entity.value().id, Eq(kNode1Id));
-}
-
 TEST_F(BookmarkModelTypeProcessorTest, ShouldUpdateModelAfterRemoteCreation) {
   syncer::UpdateResponseDataList updates;
   // Add update for the permanent folder "Bookmarks bar".
@@ -219,9 +179,6 @@
       bookmark_model()->bookmark_bar_node();
   EXPECT_TRUE(bookmarkbar->empty());
 
-  // Save will be scheduled in the model upon model change. No save should be
-  // scheduled from the processor.
-  EXPECT_CALL(*schedule_save_closure(), Run()).Times(0);
   processor()->OnUpdateReceived(CreateDummyModelTypeState(), updates);
 
   ASSERT_THAT(bookmarkbar->GetChild(0), NotNull());
@@ -255,9 +212,6 @@
       CreateUpdateData({kNodeId, kNewTitle, kNewUrl, kBookmarkBarId,
                         /*server_tag=*/std::string()}));
 
-  // Save will be scheduled in the model upon model change. No save should be
-  // scheduled from the processor.
-  EXPECT_CALL(*schedule_save_closure(), Run()).Times(0);
   processor()->OnUpdateReceived(CreateDummyModelTypeState(), updates);
 
   // Check if the bookmark has been updated properly.
@@ -347,9 +301,6 @@
   updates.push_back(CreateTombstone(kTitle1Id));
   updates.push_back(CreateTombstone(kFolder1Id));
 
-  // Save will be scheduled in the model upon model change. No save should be
-  // scheduled from the processor.
-  EXPECT_CALL(*schedule_save_closure(), Run()).Times(0);
   processor()->OnUpdateReceived(CreateDummyModelTypeState(), updates);
 
   // The structure should be
@@ -472,8 +423,8 @@
       sync_client()->GetBookmarkUndoServiceIfExists());
   std::string metadata_str;
   model_metadata.SerializeToString(&metadata_str);
-  new_processor.DecodeSyncMetadata(metadata_str, base::DoNothing(),
-                                   bookmark_model());
+  new_processor.ModelReadyToSync(metadata_str, base::DoNothing(),
+                                 bookmark_model());
 
   AssertState(&new_processor, bookmarks);
 }
@@ -505,8 +456,8 @@
   BookmarkModelTypeProcessor new_processor(
       sync_client()->GetBookmarkUndoServiceIfExists());
   model_metadata.SerializeToString(&metadata_str);
-  new_processor.DecodeSyncMetadata(metadata_str, base::DoNothing(),
-                                   bookmark_model());
+  new_processor.ModelReadyToSync(metadata_str, base::DoNothing(),
+                                 bookmark_model());
 
   AssertState(&new_processor, bookmarks);
 }
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
new file mode 100644
index 0000000..cbd9674
--- /dev/null
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -0,0 +1,357 @@
+// 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_bookmarks/bookmark_remote_updates_handler.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+
+namespace sync_bookmarks {
+
+namespace {
+
+// The sync protocol identifies top-level entities by means of well-known tags,
+// (aka server defined tags) which should not be confused with titles or client
+// tags that aren't supported by bookmarks (at the time of writing). Each tag
+// corresponds to a singleton instance of a particular top-level node in a
+// user's share; the tags are consistent across users. The tags allow us to
+// locate the specific folders whose contents we care about synchronizing,
+// without having to do a lookup by name or path.  The tags should not be made
+// user-visible. For example, the tag "bookmark_bar" represents the permanent
+// node for bookmarks bar in Chrome. The tag "other_bookmarks" represents the
+// permanent folder Other Bookmarks in Chrome.
+//
+// It is the responsibility of something upstream (at time of writing, the sync
+// server) to create these tagged nodes when initializing sync for the first
+// time for a user.  Thus, once the backend finishes initializing, the
+// ProfileSyncService can rely on the presence of tagged nodes.
+const char kBookmarkBarTag[] = "bookmark_bar";
+const char kMobileBookmarksTag[] = "synced_bookmarks";
+const char kOtherBookmarksTag[] = "other_bookmarks";
+
+// Id is created by concatenating the specifics field number and the server tag
+// similar to LookbackServerEntity::CreateId() that uses
+// GetSpecificsFieldNumberFromModelType() to compute the field number.
+const char kBookmarksRootId[] = "32904_google_chrome_bookmarks";
+
+// |sync_entity| must contain a bookmark specifics.
+// Metainfo entries must have unique keys.
+bookmarks::BookmarkNode::MetaInfoMap GetBookmarkMetaInfo(
+    const syncer::EntityData& sync_entity) {
+  const sync_pb::BookmarkSpecifics& specifics =
+      sync_entity.specifics.bookmark();
+  bookmarks::BookmarkNode::MetaInfoMap meta_info_map;
+  for (const sync_pb::MetaInfo& meta_info : specifics.meta_info()) {
+    meta_info_map[meta_info.key()] = meta_info.value();
+  }
+  DCHECK_EQ(static_cast<size_t>(specifics.meta_info_size()),
+            meta_info_map.size());
+  return meta_info_map;
+}
+
+// Creates a bookmark node under the given parent node from the given sync node.
+// Returns the newly created node. |sync_entity| must contain a bookmark
+// specifics with Metainfo entries having unique keys.
+const bookmarks::BookmarkNode* CreateBookmarkNode(
+    const syncer::EntityData& sync_entity,
+    const bookmarks::BookmarkNode* parent,
+    bookmarks::BookmarkModel* model,
+    int index) {
+  DCHECK(parent);
+  DCHECK(model);
+
+  const sync_pb::BookmarkSpecifics& specifics =
+      sync_entity.specifics.bookmark();
+  bookmarks::BookmarkNode::MetaInfoMap metainfo =
+      GetBookmarkMetaInfo(sync_entity);
+  if (sync_entity.is_folder) {
+    return model->AddFolderWithMetaInfo(
+        parent, index, base::UTF8ToUTF16(specifics.title()), &metainfo);
+  }
+  // 'creation_time_us' was added in M24. Assume a time of 0 means now.
+  const int64_t create_time_us = specifics.creation_time_us();
+  base::Time create_time =
+      (create_time_us == 0)
+          ? base::Time::Now()
+          : base::Time::FromDeltaSinceWindowsEpoch(
+                // Use FromDeltaSinceWindowsEpoch because create_time_us has
+                // always used the Windows epoch.
+                base::TimeDelta::FromMicroseconds(create_time_us));
+  return model->AddURLWithCreationTimeAndMetaInfo(
+      parent, index, base::UTF8ToUTF16(specifics.title()),
+      GURL(specifics.url()), create_time, &metainfo);
+  // TODO(crbug.com/516866): Add the favicon related code.
+}
+
+// Check whether an incoming specifics represent a valid bookmark or not.
+// |is_folder| is whether this specifics is for a folder or not.
+// Folders and tomstones entail different validation conditions.
+bool IsValidBookmark(const sync_pb::BookmarkSpecifics& specifics,
+                     bool is_folder) {
+  if (specifics.ByteSize() == 0) {
+    DLOG(ERROR) << "Invalid bookmark: empty specifics.";
+    return false;
+  }
+  if (is_folder) {
+    return true;
+  }
+  if (!GURL(specifics.url()).is_valid()) {
+    DLOG(ERROR) << "Invalid bookmark: invalid url in the specifics.";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+BookmarkRemoteUpdatesHandler::BookmarkRemoteUpdatesHandler(
+    bookmarks::BookmarkModel* bookmark_model,
+    SyncedBookmarkTracker* bookmark_tracker)
+    : bookmark_model_(bookmark_model), bookmark_tracker_(bookmark_tracker) {
+  DCHECK(bookmark_model);
+  DCHECK(bookmark_tracker);
+}
+
+void BookmarkRemoteUpdatesHandler::Process(
+    const syncer::UpdateResponseDataList& updates) {
+  for (const syncer::UpdateResponseData* update : ReorderUpdates(updates)) {
+    const syncer::EntityData& update_entity = update->entity.value();
+    // TODO(crbug.com/516866): Check |update_entity| for sanity.
+    // 1. Has bookmark specifics or no specifics in case of delete.
+    // 2. All meta info entries in the specifics have unique keys.
+    const SyncedBookmarkTracker::Entity* tracked_entity =
+        bookmark_tracker_->GetEntityForSyncId(update_entity.id);
+    if (update_entity.is_deleted()) {
+      ProcessRemoteDelete(update_entity, tracked_entity);
+      continue;
+    }
+    if (!tracked_entity) {
+      ProcessRemoteCreate(*update);
+      continue;
+    }
+    // Ignore changes to the permanent nodes (e.g. bookmarks bar). We only care
+    // about their children.
+    if (bookmark_model_->is_permanent_node(tracked_entity->bookmark_node())) {
+      continue;
+    }
+    ProcessRemoteUpdate(*update, tracked_entity);
+  }
+}
+
+// static
+std::vector<const syncer::UpdateResponseData*>
+BookmarkRemoteUpdatesHandler::ReorderUpdatesForTest(
+    const syncer::UpdateResponseDataList& updates) {
+  return ReorderUpdates(updates);
+}
+
+// static
+std::vector<const syncer::UpdateResponseData*>
+BookmarkRemoteUpdatesHandler::ReorderUpdates(
+    const syncer::UpdateResponseDataList& updates) {
+  // TODO(crbug.com/516866): This is a very simple (hacky) reordering algorithm
+  // that assumes no folders exist except the top level permanent ones. This
+  // should be fixed before enabling USS for bookmarks.
+  std::vector<const syncer::UpdateResponseData*> ordered_updates;
+  for (const syncer::UpdateResponseData& update : updates) {
+    const syncer::EntityData& update_entity = update.entity.value();
+    if (update_entity.parent_id == "0") {
+      continue;
+    }
+    if (update_entity.parent_id == kBookmarksRootId) {
+      ordered_updates.push_back(&update);
+    }
+  }
+  for (const syncer::UpdateResponseData& update : updates) {
+    const syncer::EntityData& update_entity = update.entity.value();
+    // Deletions should come last.
+    if (update_entity.is_deleted()) {
+      continue;
+    }
+    if (update_entity.parent_id != "0" &&
+        update_entity.parent_id != kBookmarksRootId) {
+      ordered_updates.push_back(&update);
+    }
+  }
+  // Now add deletions.
+  for (const syncer::UpdateResponseData& update : updates) {
+    const syncer::EntityData& update_entity = update.entity.value();
+    if (!update_entity.is_deleted()) {
+      continue;
+    }
+    if (update_entity.parent_id != "0" &&
+        update_entity.parent_id != kBookmarksRootId) {
+      ordered_updates.push_back(&update);
+    }
+  }
+  return ordered_updates;
+}
+
+void BookmarkRemoteUpdatesHandler::ProcessRemoteCreate(
+    const syncer::UpdateResponseData& update) {
+  // Because the Synced Bookmarks node can be created server side, it's possible
+  // it'll arrive at the client as an update. In that case it won't have been
+  // associated at startup, the GetChromeNodeFromSyncId call above will return
+  // null, and we won't detect it as a permanent node, resulting in us trying to
+  // create it here (which will fail). Therefore, we add special logic here just
+  // to detect the Synced Bookmarks folder.
+  const syncer::EntityData& update_entity = update.entity.value();
+  DCHECK(!update_entity.is_deleted());
+  if (update_entity.parent_id == kBookmarksRootId) {
+    // Associate permanent folders.
+    // TODO(crbug.com/516866): Method documentation says this method should be
+    // used in initial sync only. Make sure this is the case.
+    AssociatePermanentFolder(update);
+    return;
+  }
+  if (!IsValidBookmark(update_entity.specifics.bookmark(),
+                       update_entity.is_folder)) {
+    // Ignore creations with invalid specifics.
+    DLOG(ERROR) << "Couldn't add bookmark with an invalid specifics.";
+    return;
+  }
+  const bookmarks::BookmarkNode* parent_node = GetParentNode(update_entity);
+  if (!parent_node) {
+    // If we cannot find the parent, we can do nothing.
+    DLOG(ERROR) << "Could not find parent of node being added."
+                << " Node title: " << update_entity.specifics.bookmark().title()
+                << ", parent id = " << update_entity.parent_id;
+    return;
+  }
+  // TODO(crbug.com/516866): This code appends the code to the very end of the
+  // list of the children by assigning the index to the
+  // parent_node->child_count(). It should instead compute the exact using the
+  // unique position information of the new node as well as the siblings.
+  const bookmarks::BookmarkNode* bookmark_node = CreateBookmarkNode(
+      update_entity, parent_node, bookmark_model_, parent_node->child_count());
+  if (!bookmark_node) {
+    // We ignore bookmarks we can't add.
+    DLOG(ERROR) << "Failed to create bookmark node with title "
+                << update_entity.specifics.bookmark().title() << " and url "
+                << update_entity.specifics.bookmark().url();
+    return;
+  }
+  bookmark_tracker_->Add(update_entity.id, bookmark_node,
+                         update.response_version, update_entity.creation_time,
+                         update_entity.unique_position,
+                         update_entity.specifics);
+}
+
+void BookmarkRemoteUpdatesHandler::ProcessRemoteUpdate(
+    const syncer::UpdateResponseData& update,
+    const SyncedBookmarkTracker::Entity* tracked_entity) {
+  const syncer::EntityData& update_entity = update.entity.value();
+  // Can only update existing nodes.
+  DCHECK(tracked_entity);
+  DCHECK_EQ(tracked_entity,
+            bookmark_tracker_->GetEntityForSyncId(update_entity.id));
+  // Must not be a deletion.
+  DCHECK(!update_entity.is_deleted());
+  if (!IsValidBookmark(update_entity.specifics.bookmark(),
+                       update_entity.is_folder)) {
+    // Ignore updates with invalid specifics.
+    DLOG(ERROR) << "Couldn't update bookmark with an invalid specifics.";
+    return;
+  }
+  if (tracked_entity->IsUnsynced()) {
+    // TODO(crbug.com/516866): Handle conflict resolution.
+    return;
+  }
+  if (tracked_entity->MatchesData(update_entity)) {
+    bookmark_tracker_->Update(update_entity.id, update.response_version,
+                              update_entity.modification_time,
+                              update_entity.specifics);
+    return;
+  }
+  const bookmarks::BookmarkNode* node = tracked_entity->bookmark_node();
+  if (update_entity.is_folder != node->is_folder()) {
+    DLOG(ERROR) << "Could not update node. Remote node is a "
+                << (update_entity.is_folder ? "folder" : "bookmark")
+                << " while local node is a "
+                << (node->is_folder() ? "folder" : "bookmark");
+    return;
+  }
+  const sync_pb::BookmarkSpecifics& specifics =
+      update_entity.specifics.bookmark();
+  if (!update_entity.is_folder) {
+    bookmark_model_->SetURL(node, GURL(specifics.url()));
+  }
+
+  bookmark_model_->SetTitle(node, base::UTF8ToUTF16(specifics.title()));
+  // TODO(crbug.com/516866): Add the favicon related code.
+  bookmark_model_->SetNodeMetaInfoMap(node, GetBookmarkMetaInfo(update_entity));
+  bookmark_tracker_->Update(update_entity.id, update.response_version,
+                            update_entity.modification_time,
+                            update_entity.specifics);
+  // TODO(crbug.com/516866): Handle reparenting.
+  // TODO(crbug.com/516866): Handle the case of moving the bookmark to a new
+  // position under the same parent (i.e. change in the unique position)
+}
+
+void BookmarkRemoteUpdatesHandler::ProcessRemoteDelete(
+    const syncer::EntityData& update_entity,
+    const SyncedBookmarkTracker::Entity* tracked_entity) {
+  DCHECK(update_entity.is_deleted());
+
+  DCHECK_EQ(tracked_entity,
+            bookmark_tracker_->GetEntityForSyncId(update_entity.id));
+
+  // Handle corner cases first.
+  if (tracked_entity == nullptr) {
+    // Local entity doesn't exist and update is tombstone.
+    DLOG(WARNING) << "Received remote delete for a non-existing item.";
+    return;
+  }
+
+  const bookmarks::BookmarkNode* node = tracked_entity->bookmark_node();
+  // Ignore changes to the permanent top-level nodes.  We only care about
+  // their children.
+  if (bookmark_model_->is_permanent_node(node)) {
+    return;
+  }
+  // TODO(crbug.com/516866): Allow deletions of non-empty direcoties if makes
+  // sense, and recursively delete children.
+  if (node->child_count() > 0) {
+    DLOG(WARNING) << "Trying to delete a non-empty folder.";
+    return;
+  }
+
+  bookmark_model_->Remove(node);
+  bookmark_tracker_->Remove(update_entity.id);
+}
+
+const bookmarks::BookmarkNode* BookmarkRemoteUpdatesHandler::GetParentNode(
+    const syncer::EntityData& update_entity) const {
+  const SyncedBookmarkTracker::Entity* parent_entity =
+      bookmark_tracker_->GetEntityForSyncId(update_entity.parent_id);
+  if (!parent_entity) {
+    return nullptr;
+  }
+  return parent_entity->bookmark_node();
+}
+
+void BookmarkRemoteUpdatesHandler::AssociatePermanentFolder(
+    const syncer::UpdateResponseData& update) {
+  const syncer::EntityData& update_entity = update.entity.value();
+  DCHECK_EQ(update_entity.parent_id, kBookmarksRootId);
+
+  const bookmarks::BookmarkNode* permanent_node = nullptr;
+  if (update_entity.server_defined_unique_tag == kBookmarkBarTag) {
+    permanent_node = bookmark_model_->bookmark_bar_node();
+  } else if (update_entity.server_defined_unique_tag == kOtherBookmarksTag) {
+    permanent_node = bookmark_model_->other_node();
+  } else if (update_entity.server_defined_unique_tag == kMobileBookmarksTag) {
+    permanent_node = bookmark_model_->mobile_node();
+  }
+
+  if (permanent_node != nullptr) {
+    bookmark_tracker_->Add(update_entity.id, permanent_node,
+                           update.response_version, update_entity.creation_time,
+                           update_entity.unique_position,
+                           update_entity.specifics);
+  }
+}
+
+}  // namespace sync_bookmarks
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.h b/components/sync_bookmarks/bookmark_remote_updates_handler.h
new file mode 100644
index 0000000..ed6ad22
--- /dev/null
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.h
@@ -0,0 +1,89 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_REMOTE_UPDATES_HANDLER_H_
+#define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_REMOTE_UPDATES_HANDLER_H_
+
+#include <vector>
+
+#include "components/sync/engine/non_blocking_sync_common.h"
+#include "components/sync_bookmarks/synced_bookmark_tracker.h"
+
+namespace bookmarks {
+class BookmarkModel;
+class BookmarkNode;
+}  // namespace bookmarks
+
+namespace sync_bookmarks {
+
+// Responsible for processing remote updates received from the sync server.
+class BookmarkRemoteUpdatesHandler {
+ public:
+  // |bookmark_model| and |bookmark_tracker| must not be null and most outlive
+  // this object.
+  BookmarkRemoteUpdatesHandler(bookmarks::BookmarkModel* bookmark_model,
+                               SyncedBookmarkTracker* bookmark_tracker);
+  // Processes the updates received from the sync server in |updates| and
+  // updates the |bookmark_model_| and |bookmark_tracker_| accordingly.
+  void Process(const syncer::UpdateResponseDataList& updates);
+
+  // Public for testing.
+  static std::vector<const syncer::UpdateResponseData*> ReorderUpdatesForTest(
+      const syncer::UpdateResponseDataList& updates);
+
+ private:
+  // Reorders incoming updates such that parent creation is before child
+  // creation and child deletion is before parent deletion, and deletions should
+  // come last. The returned pointers point to the elements in the original
+  // |updates|.
+  static std::vector<const syncer::UpdateResponseData*> ReorderUpdates(
+      const syncer::UpdateResponseDataList& updates);
+
+  // Given a remote update entity, it returns the parent bookmark node of the
+  // corresponding node. It returns null if the parent node cannot be found.
+  const bookmarks::BookmarkNode* GetParentNode(
+      const syncer::EntityData& update_entity) const;
+
+  // Processes a remote creation of a bookmark node.
+  // 1. For permanent folders, they are only registered in |bookmark_tracker_|.
+  // 2. If the nodes parent cannot be found, the remote creation update is
+  //    ignored.
+  // 3. Otherwise, a new node is created in the local bookmark model and
+  //    registered in |bookmark_tracker_|.
+  void ProcessRemoteCreate(const syncer::UpdateResponseData& update);
+
+  // Processes a remote update of a bookmark node. |update| must not be a
+  // deletion, and the server_id must be already tracked, otherwise, it is a
+  // creation that gets handeled in ProcessRemoteCreate(). |tracked_entity| is
+  // the tracked entity for that server_id. It is passed as a dependency instead
+  // of performing a lookup inside ProcessRemoteUpdate() to avoid wasting CPU
+  // cycles for doing another lookup (this code runs on the UI thread).
+  void ProcessRemoteUpdate(const syncer::UpdateResponseData& update,
+                           const SyncedBookmarkTracker::Entity* tracked_entity);
+
+  // Process a remote delete of a bookmark node. |update_entity| must not be a
+  // deletion. |tracked_entity| is the tracked entity for that server_id. It is
+  // passed as a dependency instead of performing a lookup inside
+  // ProcessRemoteDelete() to avoid wasting CPU cycles for doing another lookup
+  // (this code runs on the UI thread).
+  void ProcessRemoteDelete(const syncer::EntityData& update_entity,
+                           const SyncedBookmarkTracker::Entity* tracked_entity);
+
+  // Associates the permanent bookmark folders with the corresponding server
+  // side ids and registers the association in |bookmark_tracker_|.
+  // |update_entity| must contain server_defined_unique_tag that is used to
+  // determine the corresponding permanent node. All permanent nodes are assumed
+  // to be directly children nodes of |kBookmarksRootId|. This method is used in
+  // the initial sync cycle only.
+  void AssociatePermanentFolder(const syncer::UpdateResponseData& update);
+
+  bookmarks::BookmarkModel* const bookmark_model_;
+  SyncedBookmarkTracker* const bookmark_tracker_;
+
+  DISALLOW_COPY_AND_ASSIGN(BookmarkRemoteUpdatesHandler);
+};
+
+}  // namespace sync_bookmarks
+
+#endif  // COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_REMOTE_UPDATES_HANDLER_H_
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
new file mode 100644
index 0000000..b641fa1
--- /dev/null
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -0,0 +1,95 @@
+// 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_bookmarks/bookmark_remote_updates_handler.h"
+
+#include <string>
+
+#include "components/sync/base/model_type.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Eq;
+
+namespace sync_bookmarks {
+
+namespace {
+
+// The parent tag for children of the root entity. Entities with this parent are
+// referred to as top level enities.
+const char kRootParentTag[] = "0";
+const char kBookmarkBarTag[] = "bookmark_bar";
+const char kBookmarksRootId[] = "32904_google_chrome_bookmarks";
+
+struct BookmarkInfo {
+  std::string server_id;
+  std::string title;
+  std::string url;  // empty for folders.
+  std::string parent_id;
+  std::string server_tag;
+};
+
+syncer::UpdateResponseData CreateUpdateData(const BookmarkInfo& bookmark_info) {
+  syncer::EntityData data;
+  data.id = bookmark_info.server_id;
+  data.parent_id = bookmark_info.parent_id;
+  data.server_defined_unique_tag = bookmark_info.server_tag;
+
+  sync_pb::BookmarkSpecifics* bookmark_specifics =
+      data.specifics.mutable_bookmark();
+  bookmark_specifics->set_title(bookmark_info.title);
+  if (bookmark_info.url.empty()) {
+    data.is_folder = true;
+  } else {
+    bookmark_specifics->set_url(bookmark_info.url);
+  }
+
+  syncer::UpdateResponseData response_data;
+  response_data.entity = data.PassToPtr();
+  // Similar to what's done in the loopback_server.
+  response_data.response_version = 0;
+  return response_data;
+}
+
+syncer::UpdateResponseData CreateBookmarkRootUpdateData() {
+  return CreateUpdateData({syncer::ModelTypeToRootTag(syncer::BOOKMARKS),
+                           std::string(), std::string(), kRootParentTag,
+                           syncer::ModelTypeToRootTag(syncer::BOOKMARKS)});
+}
+
+TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest, ShouldIgnoreRootNodes) {
+  syncer::UpdateResponseDataList updates;
+  updates.push_back(CreateBookmarkRootUpdateData());
+  std::vector<const syncer::UpdateResponseData*> ordered_updates =
+      BookmarkRemoteUpdatesHandler::ReorderUpdatesForTest(updates);
+  // Root node update should be filtered out.
+  EXPECT_THAT(ordered_updates.size(), Eq(0U));
+}
+
+// TODO(crbug.com/516866): This should change to cover the general case of
+// parents before children for non-deletions, and another test should be added
+// for children before parents for deletions.
+TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest,
+     ShouldPlacePermanentNodesFirstForNonDeletions) {
+  const std::string kNode1Id = "node1";
+  const std::string kNode2Id = "node2";
+  syncer::UpdateResponseDataList updates;
+  updates.push_back(CreateUpdateData(
+      {kNode1Id, std::string(), std::string(), kNode2Id, std::string()}));
+  updates.push_back(CreateUpdateData({kNode2Id, std::string(), std::string(),
+                                      kBookmarksRootId, kBookmarkBarTag}));
+  std::vector<const syncer::UpdateResponseData*> ordered_updates =
+      BookmarkRemoteUpdatesHandler::ReorderUpdatesForTest(updates);
+
+  // No update should be dropped.
+  ASSERT_THAT(ordered_updates.size(), Eq(2U));
+
+  // Updates should be ordered such that parent node update comes first.
+  EXPECT_THAT(ordered_updates[0]->entity.value().id, Eq(kNode2Id));
+  EXPECT_THAT(ordered_updates[1]->entity.value().id, Eq(kNode1Id));
+}
+
+}  // namespace
+
+}  // namespace sync_bookmarks
diff --git a/components/sync_bookmarks/bookmark_sync_service.cc b/components/sync_bookmarks/bookmark_sync_service.cc
index 3ef8eac..8a3d8e50 100644
--- a/components/sync_bookmarks/bookmark_sync_service.cc
+++ b/components/sync_bookmarks/bookmark_sync_service.cc
@@ -38,7 +38,7 @@
     const base::RepeatingClosure& schedule_save_closure,
     bookmarks::BookmarkModel* model) {
   if (bookmark_model_type_processor_) {
-    bookmark_model_type_processor_->DecodeSyncMetadata(
+    bookmark_model_type_processor_->ModelReadyToSync(
         metadata_str, schedule_save_closure, model);
   }
 }
diff --git a/components/unified_consent/BUILD.gn b/components/unified_consent/BUILD.gn
index 5cc7533..0f1f33dd 100644
--- a/components/unified_consent/BUILD.gn
+++ b/components/unified_consent/BUILD.gn
@@ -9,8 +9,8 @@
     "unified_consent_service.cc",
     "unified_consent_service.h",
     "unified_consent_service_client.h",
-    "url_keyed_anonymized_data_collection_consent_helper.cc",
-    "url_keyed_anonymized_data_collection_consent_helper.h",
+    "url_keyed_data_collection_consent_helper.cc",
+    "url_keyed_data_collection_consent_helper.h",
   ]
   deps = [
     "//base",
@@ -27,7 +27,7 @@
   testonly = true
   sources = [
     "unified_consent_service_unittest.cc",
-    "url_keyed_anonymized_data_collection_consent_helper_unittest.cc",
+    "url_keyed_data_collection_consent_helper_unittest.cc",
   ]
   deps = [
     ":unified_consent",
diff --git a/components/unified_consent/pref_names.cc b/components/unified_consent/pref_names.cc
index 7d4a2c9..8aa2fcd 100644
--- a/components/unified_consent/pref_names.cc
+++ b/components/unified_consent/pref_names.cc
@@ -4,6 +4,7 @@
 
 #include "components/unified_consent/pref_names.h"
 
+namespace unified_consent {
 namespace prefs {
 
 const char kUnifiedConsentGiven[] = "unified_consent_given";
@@ -12,3 +13,4 @@
     "url_keyed_anonymized_data_collection.enabled";
 
 }  // namespace prefs
+}  // namespace unified_consent
diff --git a/components/unified_consent/pref_names.h b/components/unified_consent/pref_names.h
index ac20a73..a5a3ecd5 100644
--- a/components/unified_consent/pref_names.h
+++ b/components/unified_consent/pref_names.h
@@ -5,11 +5,13 @@
 #ifndef COMPONENTS_UNIFIED_CONSENT_PREF_NAMES_H_
 #define COMPONENTS_UNIFIED_CONSENT_PREF_NAMES_H_
 
+namespace unified_consent {
 namespace prefs {
 
 extern const char kUnifiedConsentGiven[];
 extern const char kUrlKeyedAnonymizedDataCollectionEnabled[];
 
 }  // namespace prefs
+}  // namespace unified_consent
 
 #endif  // COMPONENTS_UNIFIED_CONSENT_PREF_NAMES_H_
diff --git a/components/unified_consent/unified_consent_service.cc b/components/unified_consent/unified_consent_service.cc
index 6ba5d58..dc8fe992 100644
--- a/components/unified_consent/unified_consent_service.cc
+++ b/components/unified_consent/unified_consent_service.cc
@@ -13,6 +13,8 @@
 #include "components/unified_consent/pref_names.h"
 #include "components/unified_consent/unified_consent_service_client.h"
 
+namespace unified_consent {
+
 UnifiedConsentService::UnifiedConsentService(
     UnifiedConsentServiceClient* service_client,
     PrefService* pref_service,
@@ -92,3 +94,5 @@
   service_client_->SetSafeBrowsingExtendedReportingEnabled(true);
   service_client_->SetNetworkPredictionEnabled(true);
 }
+
+}  //  namespace unified_consent
diff --git a/components/unified_consent/unified_consent_service.h b/components/unified_consent/unified_consent_service.h
index 162d2c9..a8098f1 100644
--- a/components/unified_consent/unified_consent_service.h
+++ b/components/unified_consent/unified_consent_service.h
@@ -24,6 +24,8 @@
 class SyncService;
 }
 
+namespace unified_consent {
+
 class UnifiedConsentServiceClient;
 
 // A browser-context keyed service that is used to manage the user consent
@@ -64,4 +66,6 @@
   DISALLOW_COPY_AND_ASSIGN(UnifiedConsentService);
 };
 
+}  // namespace unified_consent
+
 #endif  // COMPONENTS_UNIFIED_CONSENT_UNIFIED_CONSENT_SERVICE_H_
diff --git a/components/unified_consent/unified_consent_service_client.h b/components/unified_consent/unified_consent_service_client.h
index 583c1f8..6eaf95a 100644
--- a/components/unified_consent/unified_consent_service_client.h
+++ b/components/unified_consent/unified_consent_service_client.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_UNIFIED_CONSENT_UNIFIED_CONSENT_SERVICE_CLIENT_H_
 #define COMPONENTS_UNIFIED_CONSENT_UNIFIED_CONSENT_SERVICE_CLIENT_H_
 
+namespace unified_consent {
+
 class UnifiedConsentServiceClient {
  public:
   virtual ~UnifiedConsentServiceClient() {}
@@ -23,4 +25,6 @@
   virtual void SetNetworkPredictionEnabled(bool enabled) = 0;
 };
 
+}  // namespace unified_consent
+
 #endif  // COMPONENTS_UNIFIED_CONSENT_UNIFIED_CONSENT_SERVICE_CLIENT_H_
diff --git a/components/unified_consent/unified_consent_service_unittest.cc b/components/unified_consent/unified_consent_service_unittest.cc
index b30d4cb1..b81a988 100644
--- a/components/unified_consent/unified_consent_service_unittest.cc
+++ b/components/unified_consent/unified_consent_service_unittest.cc
@@ -15,6 +15,7 @@
 #include "services/identity/public/cpp/identity_test_environment.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace unified_consent {
 namespace {
 
 class TestSyncService : public syncer::FakeSyncService {
@@ -142,3 +143,4 @@
 #endif  // !defined(OS_CHROMEOS)
 
 }  // namespace
+}  // namespace unified_consent
diff --git a/components/unified_consent/url_keyed_anonymized_data_collection_consent_helper.h b/components/unified_consent/url_keyed_anonymized_data_collection_consent_helper.h
deleted file mode 100644
index 9c92098..0000000
--- a/components/unified_consent/url_keyed_anonymized_data_collection_consent_helper.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_UNIFIED_CONSENT_URL_KEYED_ANONYMIZED_DATA_COLLECTION_CONSENT_HELPER_H_
-#define COMPONENTS_UNIFIED_CONSENT_URL_KEYED_ANONYMIZED_DATA_COLLECTION_CONSENT_HELPER_H_
-
-#include <memory>
-
-#include "base/observer_list.h"
-
-class PrefService;
-namespace syncer {
-class SyncService;
-}
-
-namespace unified_consent {
-
-// Helper class that allows clients to check whether the user has consented
-// for URL-keyed anonymized data collection.
-class UrlKeyedAnonymizedDataCollectionConsentHelper {
- public:
-  class Observer {
-   public:
-    // Called when the state of the URL-keyed anonymized data collection
-    // changes.
-    virtual void OnUrlKeyedDataCollectionConsentStateChanged(bool enabled) = 0;
-  };
-
-  // Creates a new |UrlKeyedAnonymizedDataCollectionConsentHelper| instance. We
-  // distinguish the following cases:
-  // 1. If |is_unified_consent_enabled| true, then the instance is backed by
-  //    |pref_service|. Url-keyed data collection is enabled if the preference
-  //    |prefs::kUrlKeyedAnonymizedDataCollectionEnabled| is set to true.
-  //
-  // 2. If |is_unified_consent_enabled| is false, then the instance is backed by
-  //    the sync service. Url-keyed data collection is enabled if sync is active
-  //    and if sync history is enabled.
-  //
-  // Note: |pref_service| must outlive the retuned instance.
-  static std::unique_ptr<UrlKeyedAnonymizedDataCollectionConsentHelper>
-  NewInstance(bool is_unified_consent_enabled,
-              PrefService* pref_service,
-              syncer::SyncService* sync_service);
-
-  virtual ~UrlKeyedAnonymizedDataCollectionConsentHelper();
-
-  // Returns true if the user has consented for URL keyed anonymized data
-  // collection.
-  virtual bool IsEnabled() = 0;
-
-  // Methods to register or remove observers.
-  void AddObserver(Observer* observer);
-  void RemoveObserver(Observer* observer);
-
- protected:
-  UrlKeyedAnonymizedDataCollectionConsentHelper();
-
-  // Fires |OnUrlKeyedDataCollectionConsentStateChanged| on all the observers.
-  void FireOnStateChanged();
-
- private:
-  base::ObserverList<Observer, true> observer_list_;
-
-  DISALLOW_COPY_AND_ASSIGN(UrlKeyedAnonymizedDataCollectionConsentHelper);
-};
-
-}  // namespace unified_consent
-
-#endif  // COMPONENTS_UNIFIED_CONSENT_URL_KEYED_ANONYMIZED_DATA_COLLECTION_CONSENT_HELPER_H_
diff --git a/components/unified_consent/url_keyed_anonymized_data_collection_consent_helper_unittest.cc b/components/unified_consent/url_keyed_anonymized_data_collection_consent_helper_unittest.cc
deleted file mode 100644
index 620c33b..0000000
--- a/components/unified_consent/url_keyed_anonymized_data_collection_consent_helper_unittest.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/unified_consent/url_keyed_anonymized_data_collection_consent_helper.h"
-
-#include <vector>
-
-#include "components/sync/driver/fake_sync_service.h"
-#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "components/unified_consent/pref_names.h"
-#include "components/unified_consent/unified_consent_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using unified_consent::UrlKeyedAnonymizedDataCollectionConsentHelper;
-
-namespace {
-class UrlKeyedDataCollectionConsentHelperTest
-    : public testing::Test,
-      public UrlKeyedAnonymizedDataCollectionConsentHelper::Observer {
- public:
-  // testing::Test:
-  void SetUp() override {
-    UnifiedConsentService::RegisterPrefs(pref_service_.registry());
-  }
-
-  void OnUrlKeyedDataCollectionConsentStateChanged(bool enabled) override {
-    state_changed_notifications.push_back(enabled);
-  }
-
- protected:
-  sync_preferences::TestingPrefServiceSyncable pref_service_;
-  std::vector<bool> state_changed_notifications;
-  syncer::FakeSyncService sync_service_;
-};
-
-TEST_F(UrlKeyedDataCollectionConsentHelperTest, UnifiedConsentEnabled) {
-  std::unique_ptr<UrlKeyedAnonymizedDataCollectionConsentHelper> helper =
-      UrlKeyedAnonymizedDataCollectionConsentHelper::NewInstance(
-          true, &pref_service_, &sync_service_);
-  helper->AddObserver(this);
-  EXPECT_FALSE(helper->IsEnabled());
-  EXPECT_TRUE(state_changed_notifications.empty());
-
-  pref_service_.SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
-                           true);
-  EXPECT_TRUE(helper->IsEnabled());
-  EXPECT_EQ(1U, state_changed_notifications.size());
-  EXPECT_TRUE(state_changed_notifications[0]);
-
-  state_changed_notifications.clear();
-  pref_service_.SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
-                           false);
-  EXPECT_FALSE(helper->IsEnabled());
-  EXPECT_EQ(1U, state_changed_notifications.size());
-  EXPECT_FALSE(state_changed_notifications[0]);
-  helper->RemoveObserver(this);
-}
-
-TEST_F(UrlKeyedDataCollectionConsentHelperTest, UnifiedConsentDisabled) {
-  std::unique_ptr<UrlKeyedAnonymizedDataCollectionConsentHelper> helper =
-      UrlKeyedAnonymizedDataCollectionConsentHelper::NewInstance(
-          false, &pref_service_, &sync_service_);
-  EXPECT_FALSE(helper->IsEnabled());
-}
-
-}  // namespace
diff --git a/components/unified_consent/url_keyed_anonymized_data_collection_consent_helper.cc b/components/unified_consent/url_keyed_data_collection_consent_helper.cc
similarity index 63%
rename from components/unified_consent/url_keyed_anonymized_data_collection_consent_helper.cc
rename to components/unified_consent/url_keyed_data_collection_consent_helper.cc
index ed19096..a504fdb 100644
--- a/components/unified_consent/url_keyed_anonymized_data_collection_consent_helper.cc
+++ b/components/unified_consent/url_keyed_data_collection_consent_helper.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/unified_consent/url_keyed_anonymized_data_collection_consent_helper.h"
+#include "components/unified_consent/url_keyed_data_collection_consent_helper.h"
 
 #include "base/bind.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -18,13 +18,13 @@
 namespace {
 
 class PrefBasedUrlKeyedDataCollectionConsentHelper
-    : public UrlKeyedAnonymizedDataCollectionConsentHelper {
+    : public UrlKeyedDataCollectionConsentHelper {
  public:
   explicit PrefBasedUrlKeyedDataCollectionConsentHelper(
       PrefService* pref_service);
   ~PrefBasedUrlKeyedDataCollectionConsentHelper() override = default;
 
-  // UrlKeyedAnonymizedDataCollectionConsentHelper:
+  // UrlKeyedDataCollectionConsentHelper:
   bool IsEnabled() override;
 
  private:
@@ -36,14 +36,15 @@
 };
 
 class SyncBasedUrlKeyedDataCollectionConsentHelper
-    : public UrlKeyedAnonymizedDataCollectionConsentHelper,
+    : public UrlKeyedDataCollectionConsentHelper,
       syncer::SyncServiceObserver {
  public:
-  explicit SyncBasedUrlKeyedDataCollectionConsentHelper(
-      syncer::SyncService* sync_service);
+  SyncBasedUrlKeyedDataCollectionConsentHelper(
+      syncer::SyncService* sync_service,
+      syncer::ModelType sync_data_type);
   ~SyncBasedUrlKeyedDataCollectionConsentHelper() override;
 
-  // UrlKeyedAnonymizedDataCollectionConsentHelper:
+  // UrlKeyedDataCollectionConsentHelper:
   bool IsEnabled() override;
 
   // syncer::SyncServiceObserver:
@@ -52,7 +53,8 @@
 
  private:
   syncer::SyncService* sync_service_;
-  syncer::UploadState sync_history_upload_state_;
+  syncer::ModelType sync_data_type_;
+  syncer::UploadState sync_data_type_upload_state_;
 
   DISALLOW_COPY_AND_ASSIGN(SyncBasedUrlKeyedDataCollectionConsentHelper);
 };
@@ -79,11 +81,12 @@
 
 SyncBasedUrlKeyedDataCollectionConsentHelper::
     SyncBasedUrlKeyedDataCollectionConsentHelper(
-        syncer::SyncService* sync_service)
+        syncer::SyncService* sync_service,
+        syncer::ModelType sync_data_type)
     : sync_service_(sync_service),
-      sync_history_upload_state_(syncer::GetUploadToGoogleState(
-          sync_service_,
-          syncer::ModelType::HISTORY_DELETE_DIRECTIVES)) {
+      sync_data_type_(sync_data_type),
+      sync_data_type_upload_state_(
+          syncer::GetUploadToGoogleState(sync_service_, sync_data_type_)) {
   DCHECK(sync_service_);
   sync_service_->AddObserver(this);
 }
@@ -95,15 +98,15 @@
 }
 
 bool SyncBasedUrlKeyedDataCollectionConsentHelper::IsEnabled() {
-  return sync_history_upload_state_ == syncer::UploadState::ACTIVE;
+  return sync_data_type_upload_state_ == syncer::UploadState::ACTIVE;
 }
 
 void SyncBasedUrlKeyedDataCollectionConsentHelper::OnStateChanged(
     syncer::SyncService* sync_service) {
   DCHECK_EQ(sync_service_, sync_service);
   bool enabled_before_state_updated = IsEnabled();
-  sync_history_upload_state_ = syncer::GetUploadToGoogleState(
-      sync_service_, syncer::ModelType::HISTORY_DELETE_DIRECTIVES);
+  sync_data_type_upload_state_ =
+      syncer::GetUploadToGoogleState(sync_service_, sync_data_type_);
 
   if (enabled_before_state_updated != IsEnabled())
     FireOnStateChanged();
@@ -118,13 +121,14 @@
 
 }  // namespace
 
-UrlKeyedAnonymizedDataCollectionConsentHelper::
-    UrlKeyedAnonymizedDataCollectionConsentHelper() = default;
-UrlKeyedAnonymizedDataCollectionConsentHelper::
-    ~UrlKeyedAnonymizedDataCollectionConsentHelper() = default;
+UrlKeyedDataCollectionConsentHelper::UrlKeyedDataCollectionConsentHelper() =
+    default;
+UrlKeyedDataCollectionConsentHelper::~UrlKeyedDataCollectionConsentHelper() =
+    default;
 
-std::unique_ptr<UrlKeyedAnonymizedDataCollectionConsentHelper>
-UrlKeyedAnonymizedDataCollectionConsentHelper::NewInstance(
+// static
+std::unique_ptr<UrlKeyedDataCollectionConsentHelper>
+UrlKeyedDataCollectionConsentHelper::NewAnonymizedDataCollectionConsentHelper(
     bool is_unified_consent_enabled,
     PrefService* pref_service,
     syncer::SyncService* sync_service) {
@@ -134,22 +138,31 @@
   }
 
   return std::make_unique<SyncBasedUrlKeyedDataCollectionConsentHelper>(
-      sync_service);
+      sync_service, syncer::ModelType::HISTORY_DELETE_DIRECTIVES);
 }
 
-void UrlKeyedAnonymizedDataCollectionConsentHelper::AddObserver(
-    Observer* observer) {
+// static
+std::unique_ptr<UrlKeyedDataCollectionConsentHelper>
+UrlKeyedDataCollectionConsentHelper::NewPersonalizedDataCollectionConsentHelper(
+    bool is_unified_consent_enabled,
+    syncer::SyncService* sync_service) {
+  syncer::ModelType sync_type =
+      is_unified_consent_enabled ? syncer::ModelType::USER_EVENTS
+                                 : syncer::ModelType::HISTORY_DELETE_DIRECTIVES;
+  return std::make_unique<SyncBasedUrlKeyedDataCollectionConsentHelper>(
+      sync_service, sync_type);
+}
+
+void UrlKeyedDataCollectionConsentHelper::AddObserver(Observer* observer) {
   observer_list_.AddObserver(observer);
 }
-void UrlKeyedAnonymizedDataCollectionConsentHelper::RemoveObserver(
-    Observer* observer) {
+void UrlKeyedDataCollectionConsentHelper::RemoveObserver(Observer* observer) {
   observer_list_.RemoveObserver(observer);
 }
 
-void UrlKeyedAnonymizedDataCollectionConsentHelper::FireOnStateChanged() {
-  bool is_enabled = IsEnabled();
+void UrlKeyedDataCollectionConsentHelper::FireOnStateChanged() {
   for (auto& observer : observer_list_)
-    observer.OnUrlKeyedDataCollectionConsentStateChanged(is_enabled);
+    observer.OnUrlKeyedDataCollectionConsentStateChanged(this);
 }
 
 }  // namespace unified_consent
diff --git a/components/unified_consent/url_keyed_data_collection_consent_helper.h b/components/unified_consent/url_keyed_data_collection_consent_helper.h
new file mode 100644
index 0000000..f4d8486
--- /dev/null
+++ b/components/unified_consent/url_keyed_data_collection_consent_helper.h
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_UNIFIED_CONSENT_URL_KEYED_DATA_COLLECTION_CONSENT_HELPER_H_
+#define COMPONENTS_UNIFIED_CONSENT_URL_KEYED_DATA_COLLECTION_CONSENT_HELPER_H_
+
+#include <memory>
+
+#include "base/observer_list.h"
+
+class PrefService;
+namespace syncer {
+class SyncService;
+}
+
+namespace unified_consent {
+
+// Helper class that allows clients to check whether the user has consented
+// for URL-keyed data collection.
+class UrlKeyedDataCollectionConsentHelper {
+ public:
+  class Observer {
+   public:
+    // Called when the state of the URL-keyed data collection changes.
+    virtual void OnUrlKeyedDataCollectionConsentStateChanged(
+        UrlKeyedDataCollectionConsentHelper* consent_helper) = 0;
+  };
+
+  // Creates a new |UrlKeyedDataCollectionConsentHelper| instance that checks
+  // whether *anonymized* data collection is enabled. This should be used when
+  // the client needs to check whether the user has granted consent for
+  // *anonymized* URL-keyed data collection.
+  //
+  // Implementation-wise we distinguish the following cases:
+  // 1. If |is_unified_consent_enabled| true, then the instance is backed by
+  //    |pref_service|. Url-keyed data collection is enabled if the preference
+  //    |prefs::kUrlKeyedAnonymizedDataCollectionEnabled| is set to true.
+  //
+  // 2. If |is_unified_consent_enabled| is false, then the instance is backed by
+  //    the sync service. Url-keyed data collection is enabled if sync is active
+  //    and if sync history is enabled.
+  //
+  // Note: |pref_service| must outlive the retuned instance.
+  static std::unique_ptr<UrlKeyedDataCollectionConsentHelper>
+  NewAnonymizedDataCollectionConsentHelper(bool is_unified_consent_enabled,
+                                           PrefService* pref_service,
+                                           syncer::SyncService* sync_service);
+
+  // Creates a new |UrlKeyedDataCollectionConsentHelper| instance that checks
+  // whether *personalized* data collection is enabled. This should be used when
+  // the client needs to check whether the user has granted consent for
+  // URL-keyed data collection keyed by their Google account.
+  //
+  // Implementation-wise we distinguish the following cases:
+  // 1. If |is_unified_consent_enabled| is true then URL-keyed data collection
+  //    is enabled if sync is active and if sync event logger is enabled.
+  // 2. If |is_unified_consent_enabled| is false then URL-keyed data collection
+  //    is enabled if sync is active and if sync history is enabled.
+  static std::unique_ptr<UrlKeyedDataCollectionConsentHelper>
+  NewPersonalizedDataCollectionConsentHelper(bool is_unified_consent_enabled,
+                                             syncer::SyncService* sync_service);
+
+  virtual ~UrlKeyedDataCollectionConsentHelper();
+
+  // Returns true if the user has consented for URL keyed anonymized data
+  // collection.
+  virtual bool IsEnabled() = 0;
+
+  // Methods to register or remove observers.
+  void AddObserver(Observer* observer);
+  void RemoveObserver(Observer* observer);
+
+ protected:
+  UrlKeyedDataCollectionConsentHelper();
+
+  // Fires |OnUrlKeyedDataCollectionConsentStateChanged| on all the observers.
+  void FireOnStateChanged();
+
+ private:
+  base::ObserverList<Observer, true> observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(UrlKeyedDataCollectionConsentHelper);
+};
+
+}  // namespace unified_consent
+
+#endif  // COMPONENTS_UNIFIED_CONSENT_URL_KEYED_DATA_COLLECTION_CONSENT_HELPER_H_
diff --git a/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc b/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc
new file mode 100644
index 0000000..fe58e83d
--- /dev/null
+++ b/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc
@@ -0,0 +1,176 @@
+// 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/unified_consent/url_keyed_data_collection_consent_helper.h"
+
+#include <vector>
+
+#include "components/sync/driver/fake_sync_service.h"
+#include "components/sync/engine/cycle/sync_cycle_snapshot.h"
+#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "components/unified_consent/pref_names.h"
+#include "components/unified_consent/unified_consent_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace unified_consent {
+namespace {
+
+class TestSyncService : public syncer::FakeSyncService {
+ public:
+  void set_sync_initialized(bool sync_initialized) {
+    sync_initialized_ = sync_initialized;
+  }
+  void set_sync_active_data_type(syncer::ModelType type) {
+    sync_active_data_type_ = type;
+  }
+  void FireOnStateChangeOnAllObservers() {
+    for (auto& observer : observers_)
+      observer.OnStateChanged(this);
+  }
+
+  // syncer::FakeSyncService:
+  bool IsSyncAllowed() const override { return true; }
+  bool CanSyncStart() const override { return true; }
+  syncer::ModelTypeSet GetPreferredDataTypes() const override {
+    return syncer::ModelTypeSet(syncer::ModelType::HISTORY_DELETE_DIRECTIVES,
+                                syncer::ModelType::USER_EVENTS);
+  }
+  bool IsSyncActive() const override { return true; }
+  bool ConfigurationDone() const override { return true; }
+
+  syncer::SyncCycleSnapshot GetLastCycleSnapshot() const override {
+    if (!sync_initialized_)
+      return syncer::SyncCycleSnapshot();
+    return syncer::SyncCycleSnapshot(
+        syncer::ModelNeutralState(), syncer::ProgressMarkerMap(), false, 5, 2,
+        7, false, 0, base::Time::Now(), base::Time::Now(),
+        std::vector<int>(syncer::MODEL_TYPE_COUNT, 0),
+        std::vector<int>(syncer::MODEL_TYPE_COUNT, 0),
+        sync_pb::SyncEnums::UNKNOWN_ORIGIN,
+        /*short_poll_interval=*/base::TimeDelta::FromMinutes(30),
+        /*long_poll_interval=*/base::TimeDelta::FromMinutes(180),
+        /*has_remaining_local_changes=*/false);
+  }
+
+  syncer::ModelTypeSet GetActiveDataTypes() const override {
+    if (sync_active_data_type_ != syncer::ModelType::UNSPECIFIED) {
+      return syncer::ModelTypeSet(sync_active_data_type_);
+    }
+    return syncer::ModelTypeSet();
+  }
+
+  void AddObserver(syncer::SyncServiceObserver* observer) override {
+    observers_.AddObserver(observer);
+  }
+  void RemoveObserver(syncer::SyncServiceObserver* observer) override {
+    observers_.RemoveObserver(observer);
+  }
+
+ private:
+  bool sync_initialized_ = false;
+  syncer::ModelType sync_active_data_type_ = syncer::ModelType::UNSPECIFIED;
+  base::ObserverList<syncer::SyncServiceObserver> observers_;
+};
+
+class UrlKeyedDataCollectionConsentHelperTest
+    : public testing::Test,
+      public UrlKeyedDataCollectionConsentHelper::Observer {
+ public:
+  // testing::Test:
+  void SetUp() override {
+    UnifiedConsentService::RegisterPrefs(pref_service_.registry());
+  }
+
+  void OnUrlKeyedDataCollectionConsentStateChanged(
+      UrlKeyedDataCollectionConsentHelper* consent_helper) override {
+    state_changed_notifications.push_back(consent_helper->IsEnabled());
+  }
+
+ protected:
+  sync_preferences::TestingPrefServiceSyncable pref_service_;
+  std::vector<bool> state_changed_notifications;
+  TestSyncService sync_service_;
+};
+
+TEST_F(UrlKeyedDataCollectionConsentHelperTest,
+       AnonymizedDataCollection_UnifiedConsentEnabled) {
+  std::unique_ptr<UrlKeyedDataCollectionConsentHelper> helper =
+      UrlKeyedDataCollectionConsentHelper::
+          NewAnonymizedDataCollectionConsentHelper(true, &pref_service_,
+                                                   &sync_service_);
+  helper->AddObserver(this);
+  EXPECT_FALSE(helper->IsEnabled());
+  EXPECT_TRUE(state_changed_notifications.empty());
+
+  pref_service_.SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
+                           true);
+  EXPECT_TRUE(helper->IsEnabled());
+  ASSERT_EQ(1U, state_changed_notifications.size());
+  EXPECT_TRUE(state_changed_notifications[0]);
+
+  state_changed_notifications.clear();
+  pref_service_.SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
+                           false);
+  EXPECT_FALSE(helper->IsEnabled());
+  ASSERT_EQ(1U, state_changed_notifications.size());
+  EXPECT_FALSE(state_changed_notifications[0]);
+  helper->RemoveObserver(this);
+}
+
+TEST_F(UrlKeyedDataCollectionConsentHelperTest,
+       AnonymizedDataCollection_UnifiedConsentDisabled) {
+  std::unique_ptr<UrlKeyedDataCollectionConsentHelper> helper =
+      UrlKeyedDataCollectionConsentHelper::
+          NewAnonymizedDataCollectionConsentHelper(false, &pref_service_,
+                                                   &sync_service_);
+  helper->AddObserver(this);
+  EXPECT_FALSE(helper->IsEnabled());
+  EXPECT_TRUE(state_changed_notifications.empty());
+
+  sync_service_.set_sync_initialized(true);
+  sync_service_.set_sync_active_data_type(
+      syncer::ModelType::HISTORY_DELETE_DIRECTIVES);
+  sync_service_.FireOnStateChangeOnAllObservers();
+  EXPECT_TRUE(helper->IsEnabled());
+  ASSERT_EQ(1U, state_changed_notifications.size());
+  helper->RemoveObserver(this);
+}
+
+TEST_F(UrlKeyedDataCollectionConsentHelperTest,
+       PersonalizeddDataCollection_UnifiedConsentEnabled) {
+  std::unique_ptr<UrlKeyedDataCollectionConsentHelper> helper =
+      UrlKeyedDataCollectionConsentHelper::
+          NewPersonalizedDataCollectionConsentHelper(true, &sync_service_);
+  helper->AddObserver(this);
+  EXPECT_FALSE(helper->IsEnabled());
+  EXPECT_TRUE(state_changed_notifications.empty());
+
+  sync_service_.set_sync_initialized(true);
+  sync_service_.set_sync_active_data_type(syncer::ModelType::USER_EVENTS);
+  sync_service_.FireOnStateChangeOnAllObservers();
+  EXPECT_TRUE(helper->IsEnabled());
+  ASSERT_EQ(1U, state_changed_notifications.size());
+  helper->RemoveObserver(this);
+}
+
+TEST_F(UrlKeyedDataCollectionConsentHelperTest,
+       PersonalizedDataCollection_UnifiedConsentDisabled) {
+  std::unique_ptr<UrlKeyedDataCollectionConsentHelper> helper =
+      UrlKeyedDataCollectionConsentHelper::
+          NewPersonalizedDataCollectionConsentHelper(false, &sync_service_);
+  helper->AddObserver(this);
+  EXPECT_FALSE(helper->IsEnabled());
+  EXPECT_TRUE(state_changed_notifications.empty());
+
+  sync_service_.set_sync_initialized(true);
+  sync_service_.set_sync_active_data_type(
+      syncer::ModelType::HISTORY_DELETE_DIRECTIVES);
+  sync_service_.FireOnStateChangeOnAllObservers();
+  EXPECT_TRUE(helper->IsEnabled());
+  ASSERT_EQ(1U, state_changed_notifications.size());
+  helper->RemoveObserver(this);
+}
+
+}  // namespace
+}  // namespace unified_consent
diff --git a/components/zucchini/buffer_source.cc b/components/zucchini/buffer_source.cc
index 721588a..d72d329 100644
--- a/components/zucchini/buffer_source.cc
+++ b/components/zucchini/buffer_source.cc
@@ -80,7 +80,7 @@
   for (int shift = 0; shift < shift_lim; shift += 7, ++cur) {
     uint32_t b = *cur;
     // When |shift == 28|, |(b & 0x7F) << shift| discards the "???" bits.
-    value |= static_cast<int32_t>(b & 0x7F) << shift;
+    value |= static_cast<int32_t>(static_cast<uint32_t>(b & 0x7F) << shift);
     if (!(b & 0x80)) {
       *ret = (shift == 28) ? value : SignExtend(shift + 6, value);
       seek(cur + 1);
diff --git a/components/zucchini/fuzzers/imposed_ensemble_matcher_fuzzer.cc b/components/zucchini/fuzzers/imposed_ensemble_matcher_fuzzer.cc
index 5c129a3..bbb06cab 100644
--- a/components/zucchini/fuzzers/imposed_ensemble_matcher_fuzzer.cc
+++ b/components/zucchini/fuzzers/imposed_ensemble_matcher_fuzzer.cc
@@ -63,7 +63,7 @@
   // as it is a failure in Zucchini's patch performance that is worth
   // investigating.
   size_t patch_size = patch_writer.SerializedSize();
-  CHECK_LE(patch_size, kMaxImageSize * 2);
+  CHECK_LE(patch_size, kMaxImageSize * 3);
 
   // Write to buffer to avoid IO.
   std::unique_ptr<uint8_t[]> patch_data(new uint8_t[patch_size]);
diff --git a/content/DEPS b/content/DEPS
index 1ec0d62..b35c12a 100644
--- a/content/DEPS
+++ b/content/DEPS
@@ -24,6 +24,7 @@
   # settings, packaging details, installation or crash reporting.
 
   "+components/services/filesystem",
+  "+components/services/font",
 
   "+crypto",
   "+grit/blink_resources.h",
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 1fec0c7..998a8a8 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -97,13 +97,11 @@
 #if defined(OS_LINUX)
 #include "base/native_library.h"
 #include "base/rand_util.h"
-#include "content/common/font_config_ipc_linux.h"
 #include "services/service_manager/zygote/common/common_sandbox_support_linux.h"
 #include "third_party/blink/public/platform/web_font_render_style.h"
 #include "third_party/boringssl/src/include/openssl/crypto.h"
 #include "third_party/boringssl/src/include/openssl/rand.h"
 #include "third_party/skia/include/core/SkFontMgr.h"
-#include "third_party/skia/include/ports/SkFontConfigInterface.h"
 #include "third_party/skia/include/ports/SkFontMgr_android.h"
 #include "third_party/webrtc_overrides/init_webrtc.h"  // nogncheck
 
@@ -389,9 +387,6 @@
 #endif
   InitializeWebRtcModule();
 
-  SkFontConfigInterface::SetGlobal(
-      sk_make_sp<FontConfigIPC>(service_manager::GetSandboxFD()));
-
   // Set the android SkFontMgr for blink. We need to ensure this is done
   // before the sandbox is initialized to allow the font manager to access
   // font configuration files on disk.
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 5ec37808..7eb6668 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -690,6 +690,8 @@
     "devtools/shared_worker_devtools_agent_host.h",
     "devtools/shared_worker_devtools_manager.cc",
     "devtools/shared_worker_devtools_manager.h",
+    "devtools/target_registry.cc",
+    "devtools/target_registry.h",
     "discardable_shared_memory_manager.cc",
     "dom_storage/dom_storage_area.cc",
     "dom_storage/dom_storage_area.h",
@@ -1245,8 +1247,6 @@
     "renderer_host/event_with_latency_info.h",
     "renderer_host/file_utilities_host_impl.cc",
     "renderer_host/file_utilities_host_impl.h",
-    "renderer_host/font_utils_linux.cc",
-    "renderer_host/font_utils_linux.h",
     "renderer_host/frame_connector_delegate.cc",
     "renderer_host/frame_connector_delegate.h",
     "renderer_host/frame_metadata_util.cc",
@@ -2042,6 +2042,9 @@
     if (use_pangocairo) {
       sources += [ "renderer_host/pepper/pepper_truetype_font_list_pango.cc" ]
     }
+    if (is_linux && !is_android) {
+      deps += [ "//components/services/font:ppapi_fontconfig_matching" ]
+    }
   }
 
   if (enable_library_cdms) {
diff --git a/content/browser/appcache/appcache_navigation_handle_core.cc b/content/browser/appcache/appcache_navigation_handle_core.cc
index a76f2dcb..57d00b1 100644
--- a/content/browser/appcache/appcache_navigation_handle_core.cc
+++ b/content/browser/appcache/appcache_navigation_handle_core.cc
@@ -93,7 +93,30 @@
 void AppCacheNavigationHandleCore::AddRequestToDebugLog(const GURL& url) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (debug_log_)
-    debug_log_->emplace_back("Req:" + url.spec().substr(0, 64));
+    debug_log_->emplace_back("Req:host=" + HostToString() +
+                             ",url=" + url.spec().substr(0, 64));
+}
+
+void AppCacheNavigationHandleCore::AddDefaultFactoryRunToDebugLog(
+    bool was_request_intercepted) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (debug_log_) {
+    debug_log_->emplace_back(
+        base::StringPrintf("Fac:host=%s,int=%s", HostToString().c_str(),
+                           was_request_intercepted ? "T" : "F"));
+  }
+}
+
+void AppCacheNavigationHandleCore::AddCreateURLLoaderToDebugLog() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (debug_log_)
+    debug_log_->emplace_back("Load:host=" + HostToString());
+}
+
+void AppCacheNavigationHandleCore::AddNavigationStartToDebugLog() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (debug_log_)
+    debug_log_->emplace_back("Start:host=" + HostToString());
 }
 
 std::string AppCacheNavigationHandleCore::GetDebugLog() {
@@ -161,4 +184,9 @@
   DCHECK(false);
 }
 
+std::string AppCacheNavigationHandleCore::HostToString() {
+  return precreated_host_ ? std::to_string(precreated_host_->host_id())
+                          : "null";
+}
+
 }  // namespace content
diff --git a/content/browser/appcache/appcache_navigation_handle_core.h b/content/browser/appcache/appcache_navigation_handle_core.h
index d93d91b..bb7eddc7 100644
--- a/content/browser/appcache/appcache_navigation_handle_core.h
+++ b/content/browser/appcache/appcache_navigation_handle_core.h
@@ -48,6 +48,9 @@
   AppCacheServiceImpl* GetAppCacheService();
 
   void AddRequestToDebugLog(const GURL& url);
+  void AddDefaultFactoryRunToDebugLog(bool was_request_intercepted);
+  void AddCreateURLLoaderToDebugLog();
+  void AddNavigationStartToDebugLog();
   std::string GetDebugLog();
 
  protected:
@@ -74,6 +77,8 @@
       network::mojom::URLLoaderFactoryPtr url_loader_factory) override;
 
  private:
+  std::string HostToString();
+
   std::unique_ptr<AppCacheHost> precreated_host_;
   scoped_refptr<ChromeAppCacheService> appcache_service_;
   int appcache_host_id_;
diff --git a/content/browser/background_fetch/storage/README.md b/content/browser/background_fetch/storage/README.md
index e21e9c3..a21b6bc 100644
--- a/content/browser/background_fetch/storage/README.md
+++ b/content/browser/background_fetch/storage/README.md
@@ -45,6 +45,19 @@
 value: "<serialized content::proto::BackgroundFetchCompletedRequest>"
 ```
 
+## Cache Storage UserData schema
+
+The downloaded responses of every fetch will be stored in their own private cache.
+
+### Cache identifiers
+* `origin`: `<origin>`
+* `owner`: `CacheStorageOwner::kBackgroundFetch`
+* `cache_name`: `<unique_id>`
+
+The cache will contain all the Request/Response key/value pairs of the fetch.
+Note that the Request value stored isn't comprehensive, and only the url value is
+used to as a key to find the matching Response.
+
 ### Expansions
 * `<unique_id>` is a GUID (v4) that identifies a background fetch registration.
 E.g.  `17467386-60b4-4c5b-b66c-aabf793fd39b`
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc
index 7e4243c..d361bc1 100644
--- a/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/guid.h"
+#include "base/json/json_reader.h"
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "content/browser/devtools/devtools_session.h"
@@ -18,6 +19,7 @@
 #include "content/browser/devtools/protocol/target_handler.h"
 #include "content/browser/devtools/protocol/tethering_handler.h"
 #include "content/browser/devtools/protocol/tracing_handler.h"
+#include "content/browser/devtools/target_registry.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 
 namespace content {
@@ -48,30 +50,37 @@
 BrowserDevToolsAgentHost::~BrowserDevToolsAgentHost() {
 }
 
-bool BrowserDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+bool BrowserDevToolsAgentHost::AttachSession(DevToolsSession* session,
+                                             TargetRegistry* parent_registry) {
+  DCHECK(!parent_registry);
+
   if (session->restricted())
     return false;
 
+  auto registry = std::make_unique<TargetRegistry>(session);
+  TargetRegistry* registry_ptr = registry.get();
+  target_registries_[session->client()] = std::move(registry);
   session->SetBrowserOnly(true);
-  session->AddHandler(base::WrapUnique(
-      new protocol::TargetHandler(true /* browser_only */, GetId())));
+  session->AddHandler(std::make_unique<protocol::TargetHandler>(
+      true /* browser_only */, GetId(), registry_ptr));
   if (only_discovery_)
     return true;
 
-  session->AddHandler(base::WrapUnique(new protocol::BrowserHandler()));
-  session->AddHandler(base::WrapUnique(new protocol::IOHandler(
-      GetIOContext())));
-  session->AddHandler(base::WrapUnique(new protocol::MemoryHandler()));
-  session->AddHandler(base::WrapUnique(new protocol::SecurityHandler()));
-  session->AddHandler(base::WrapUnique(new protocol::SystemInfoHandler()));
-  session->AddHandler(base::WrapUnique(new protocol::TetheringHandler(
-      socket_callback_, tethering_task_runner_)));
+  session->AddHandler(std::make_unique<protocol::BrowserHandler>());
+  session->AddHandler(std::make_unique<protocol::IOHandler>(GetIOContext()));
+  session->AddHandler(std::make_unique<protocol::MemoryHandler>());
+  session->AddHandler(std::make_unique<protocol::SecurityHandler>());
+  session->AddHandler(std::make_unique<protocol::SystemInfoHandler>());
+  session->AddHandler(std::make_unique<protocol::TetheringHandler>(
+      socket_callback_, tethering_task_runner_));
   session->AddHandler(
-      base::WrapUnique(new protocol::TracingHandler(nullptr, GetIOContext())));
+      std::make_unique<protocol::TracingHandler>(nullptr, GetIOContext()));
   return true;
 }
 
-void BrowserDevToolsAgentHost::DetachSession(DevToolsSession* session) {}
+void BrowserDevToolsAgentHost::DetachSession(DevToolsSession* session) {
+  target_registries_.erase(session->client());
+}
 
 std::string BrowserDevToolsAgentHost::GetType() {
   return kTypeBrowser;
@@ -96,10 +105,15 @@
 void BrowserDevToolsAgentHost::Reload() {
 }
 
-void BrowserDevToolsAgentHost::DispatchProtocolMessage(
-    DevToolsSession* session,
-    const std::string& message) {
-  session->DispatchProtocolMessage(message);
+bool BrowserDevToolsAgentHost::DispatchProtocolMessage(
+    DevToolsAgentHostClient* client,
+    const std::string& message,
+    base::DictionaryValue* parsed_message) {
+  auto* target_registry = target_registries_[client].get();
+  if (target_registry->DispatchMessageOnAgentHost(message, parsed_message))
+    return true;
+  return DevToolsAgentHostImpl::DispatchProtocolMessage(client, message,
+                                                        parsed_message);
 }
 
 }  // content
diff --git a/content/browser/devtools/browser_devtools_agent_host.h b/content/browser/devtools/browser_devtools_agent_host.h
index 7022e2d1..2996348 100644
--- a/content/browser/devtools/browser_devtools_agent_host.h
+++ b/content/browser/devtools/browser_devtools_agent_host.h
@@ -5,10 +5,13 @@
 #ifndef CONTENT_BROWSER_DEVTOOLS_BROWSER_DEVTOOLS_AGENT_HOST_H_
 #define CONTENT_BROWSER_DEVTOOLS_BROWSER_DEVTOOLS_AGENT_HOST_H_
 
+#include "base/containers/flat_map.h"
 #include "content/browser/devtools/devtools_agent_host_impl.h"
 
 namespace content {
 
+class TargetRegistry;
+
 class BrowserDevToolsAgentHost : public DevToolsAgentHostImpl {
  private:
   friend class DevToolsAgentHost;
@@ -18,11 +21,13 @@
       bool only_discovery);
   ~BrowserDevToolsAgentHost() override;
 
-  // DevToolsAgentHostImpl implementation.
-  bool AttachSession(DevToolsSession* session) override;
+  // DevToolsAgentHostImpl overrides.
+  bool AttachSession(DevToolsSession* session,
+                     TargetRegistry* registry) override;
   void DetachSession(DevToolsSession* session) override;
-  void DispatchProtocolMessage(DevToolsSession* session,
-                               const std::string& message) override;
+  bool DispatchProtocolMessage(DevToolsAgentHostClient* client,
+                               const std::string& message,
+                               base::DictionaryValue* parsed_message) override;
 
   // DevToolsAgentHost implementation.
   std::string GetType() override;
@@ -35,6 +40,8 @@
   scoped_refptr<base::SingleThreadTaskRunner> tethering_task_runner_;
   CreateServerSocketCallback socket_callback_;
   bool only_discovery_;
+  base::flat_map<DevToolsAgentHostClient*, std::unique_ptr<TargetRegistry>>
+      target_registries_;
 };
 
 }  // namespace content
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index 8d4373c3..273ca40 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/lazy_instance.h"
 #include "base/observer_list.h"
@@ -176,12 +177,13 @@
 }
 
 bool DevToolsAgentHostImpl::InnerAttachClient(DevToolsAgentHostClient* client,
+                                              TargetRegistry* registry,
                                               bool restricted) {
   scoped_refptr<DevToolsAgentHostImpl> protect(this);
   DevToolsSession* session = new DevToolsSession(this, client, restricted);
   sessions_.insert(session);
   session_by_client_[client].reset(session);
-  if (!AttachSession(session)) {
+  if (!AttachSession(session, registry)) {
     sessions_.erase(session);
     session_by_client_.erase(client);
     return false;
@@ -198,14 +200,22 @@
 void DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) {
   if (SessionByClient(client))
     return;
-  InnerAttachClient(client, false /* restricted */);
+  InnerAttachClient(client, nullptr, false /* restricted */);
+}
+
+void DevToolsAgentHostImpl::AttachSubtargetClient(
+    DevToolsAgentHostClient* client,
+    TargetRegistry* registry) {
+  if (SessionByClient(client))
+    return;
+  InnerAttachClient(client, registry, false /* restricted */);
 }
 
 bool DevToolsAgentHostImpl::AttachRestrictedClient(
     DevToolsAgentHostClient* client) {
   if (SessionByClient(client))
     return false;
-  return InnerAttachClient(client, true /* restricted */);
+  return InnerAttachClient(client, nullptr, true /* restricted */);
 }
 
 bool DevToolsAgentHostImpl::DetachClient(DevToolsAgentHostClient* client) {
@@ -220,16 +230,29 @@
 bool DevToolsAgentHostImpl::DispatchProtocolMessage(
     DevToolsAgentHostClient* client,
     const std::string& message) {
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
+  if (value && !value->is_dict())
+    value.reset();
+  return DispatchProtocolMessage(
+      client, message, static_cast<base::DictionaryValue*>(value.get()));
+}
+
+bool DevToolsAgentHostImpl::DispatchProtocolMessage(
+    DevToolsAgentHostClient* client,
+    const std::string& message,
+    base::DictionaryValue* parsed_message) {
   DevToolsSession* session = SessionByClient(client);
   if (!session)
     return false;
-  DispatchProtocolMessage(session, message);
+  session->DispatchProtocolMessage(message, parsed_message);
   return true;
 }
 
 void DevToolsAgentHostImpl::InnerDetachClient(DevToolsAgentHostClient* client) {
   std::unique_ptr<DevToolsSession> session =
       std::move(session_by_client_[client]);
+  // Make sure we dispose session prior to reporting it to the host.
+  session->Dispose();
   sessions_.erase(session.get());
   session_by_client_.erase(client);
   DetachSession(session.get());
@@ -321,16 +344,13 @@
   }
 }
 
-bool DevToolsAgentHostImpl::AttachSession(DevToolsSession* session) {
+bool DevToolsAgentHostImpl::AttachSession(DevToolsSession* session,
+                                          TargetRegistry* registry) {
   return false;
 }
 
 void DevToolsAgentHostImpl::DetachSession(DevToolsSession* session) {}
 
-void DevToolsAgentHostImpl::DispatchProtocolMessage(
-    DevToolsSession* session,
-    const std::string& message) {}
-
 // static
 void DevToolsAgentHost::DetachAllClients() {
   if (!g_devtools_instances.IsCreated())
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index a58af1fa..b258f84 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -23,6 +23,7 @@
 
 class BrowserContext;
 class DevToolsSession;
+class TargetRegistry;
 
 // Describes interface for managing devtools agents from the browser process.
 class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
@@ -65,10 +66,13 @@
   static bool ShouldForceCreation();
 
   // Returning |false| will block the attach.
-  virtual bool AttachSession(DevToolsSession* session);
+  virtual bool AttachSession(DevToolsSession* session,
+                             TargetRegistry* registry);
   virtual void DetachSession(DevToolsSession* session);
-  virtual void DispatchProtocolMessage(DevToolsSession* session,
-                                       const std::string& message);
+
+  virtual bool DispatchProtocolMessage(DevToolsAgentHostClient* client,
+                                       const std::string& message,
+                                       base::DictionaryValue* parsed_message);
 
   void NotifyCreated();
   void NotifyNavigated();
@@ -81,15 +85,23 @@
   base::flat_set<DevToolsSession*>& sessions() { return sessions_; }
 
  private:
-  friend class DevToolsAgentHost; // for static methods
+  friend class DevToolsAgentHost;  // for static methods
   friend class DevToolsSession;
-  bool InnerAttachClient(DevToolsAgentHostClient* client, bool restricted);
+  friend class TargetRegistry;  // for subtarget management
+
+  bool InnerAttachClient(DevToolsAgentHostClient* client,
+                         TargetRegistry* registry,
+                         bool restricted);
   void InnerDetachClient(DevToolsAgentHostClient* client);
   void NotifyAttached();
   void NotifyDetached();
   void NotifyDestroyed();
   DevToolsSession* SessionByClient(DevToolsAgentHostClient* client);
 
+  // TargetRegistry API for subtarget management.
+  void AttachSubtargetClient(DevToolsAgentHostClient* client,
+                             TargetRegistry* registry);
+
   const std::string id_;
   base::flat_set<DevToolsSession*> sessions_;
   base::flat_map<DevToolsAgentHostClient*, std::unique_ptr<DevToolsSession>>
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 10a84a5..a82213af 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -46,6 +46,13 @@
 }
 
 DevToolsSession::~DevToolsSession() {
+  // It is Ok for session to be deleted without the dispose -
+  // it can be kicked out by an extension connect / disconnect.
+  if (dispatcher_)
+    Dispose();
+}
+
+void DevToolsSession::Dispose() {
   dispatcher_.reset();
   for (auto& pair : handlers_)
     pair.second->Disable();
@@ -116,22 +123,19 @@
   io_session_ptr_.reset();
 }
 
-void DevToolsSession::DispatchProtocolMessage(const std::string& message) {
-  std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
-
+void DevToolsSession::DispatchProtocolMessage(
+    const std::string& message,
+    base::DictionaryValue* parsed_message) {
   DevToolsManagerDelegate* delegate =
       DevToolsManager::GetInstance()->delegate();
-  if (value && value->is_dict() && delegate) {
-    base::DictionaryValue* dict_value =
-        static_cast<base::DictionaryValue*>(value.get());
-
-    if (delegate->HandleCommand(agent_host_, client_, dict_value))
-      return;
+  if (delegate && parsed_message &&
+      delegate->HandleCommand(agent_host_, client_, parsed_message)) {
+    return;
   }
 
   int call_id;
   std::string method;
-  if (dispatcher_->dispatch(protocol::toProtocolValue(value.get(), 1000),
+  if (dispatcher_->dispatch(protocol::toProtocolValue(parsed_message, 1000),
                             &call_id,
                             &method) != protocol::Response::kFallThrough) {
     return;
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index 9ae28ad..2b2bccf 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -28,8 +28,10 @@
                   DevToolsAgentHostClient* client,
                   bool restricted);
   ~DevToolsSession() override;
+  void Dispose();
 
   bool restricted() { return restricted_; }
+  DevToolsAgentHost* agent_host() { return agent_host_; };
   DevToolsAgentHostClient* client() { return client_; };
 
   // Browser-only sessions do not talk to mojom::DevToolsAgent, but instead
@@ -41,7 +43,8 @@
   void SetRenderer(int process_host_id, RenderFrameHostImpl* frame_host);
 
   void AttachToAgent(const blink::mojom::DevToolsAgentAssociatedPtr& agent);
-  void DispatchProtocolMessage(const std::string& message);
+  void DispatchProtocolMessage(const std::string& message,
+                               base::DictionaryValue* parsed_message);
   void SuspendSendingMessagesToAgent();
   void ResumeSendingMessagesToAgent();
 
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index c96429d..4b9a8d2 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -9,11 +9,13 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/strings/stringprintf.h"
+#include "base/unguessable_token.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "content/browser/devtools/browser_devtools_agent_host.h"
 #include "content/browser/devtools/devtools_manager.h"
 #include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/target_registry.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/devtools_agent_host_client.h"
@@ -231,28 +233,41 @@
  public:
   static std::string Attach(TargetHandler* handler,
                             DevToolsAgentHost* agent_host,
-                            bool waiting_for_debugger) {
-    std::string id = base::StringPrintf("%s:%d", agent_host->GetId().c_str(),
-                                        ++handler->last_session_id_);
-    Session* session = new Session(handler, agent_host, id);
+                            bool waiting_for_debugger,
+                            bool flatten_protocol) {
+    std::string id = base::UnguessableToken::Create().ToString();
+    Session* session = new Session(handler, agent_host, id, flatten_protocol);
     handler->attached_sessions_[id].reset(session);
-    agent_host->AttachClient(session);
+    DevToolsAgentHostImpl* agent_host_impl =
+        static_cast<DevToolsAgentHostImpl*>(agent_host);
+    if (flatten_protocol) {
+      handler->target_registry_->AttachSubtargetSession(id, agent_host_impl,
+                                                        session);
+    } else {
+      agent_host_impl->AttachClient(session);
+    }
     handler->frontend_->AttachedToTarget(id, CreateInfo(agent_host),
                                          waiting_for_debugger);
     return id;
   }
 
   ~Session() override {
-    if (agent_host_)
-      agent_host_->DetachClient(this);
+    if (!agent_host_)
+      return;
+    if (handler_->target_registry_)
+      handler_->target_registry_->DetachSubtargetSession(id_);
+    agent_host_->DetachClient(this);
   }
 
   void Detach(bool host_closed) {
     handler_->frontend_->DetachedFromTarget(id_, agent_host_->GetId());
     if (host_closed)
       handler_->auto_attacher_.AgentHostClosed(agent_host_.get());
-    else
+    else {
+      if (handler_->target_registry_)
+        handler_->target_registry_->DetachSubtargetSession(id_);
       agent_host_->DetachClient(this);
+    }
     handler_->auto_attached_sessions_.erase(agent_host_.get());
     agent_host_ = nullptr;
     handler_->attached_sessions_.erase(id_);
@@ -281,15 +296,26 @@
   }
 
  private:
+  friend class TargetHandler;
+
   Session(TargetHandler* handler,
           DevToolsAgentHost* agent_host,
-          const std::string& id)
-      : handler_(handler), agent_host_(agent_host), id_(id) {}
+          const std::string& id,
+          bool flatten_protocol)
+      : handler_(handler),
+        agent_host_(agent_host),
+        id_(id),
+        flatten_protocol_(flatten_protocol) {}
 
   // DevToolsAgentHostClient implementation.
   void DispatchProtocolMessage(DevToolsAgentHost* agent_host,
                                const std::string& message) override {
     DCHECK(agent_host == agent_host_.get());
+    if (flatten_protocol_) {
+      handler_->target_registry_->SendMessageToClient(id_, message);
+      return;
+    }
+
     handler_->frontend_->ReceivedMessageFromTarget(id_, message,
                                                    agent_host_->GetId());
   }
@@ -302,6 +328,7 @@
   TargetHandler* handler_;
   scoped_refptr<DevToolsAgentHost> agent_host_;
   std::string id_;
+  bool flatten_protocol_;
   Throttle* throttle_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(Session);
@@ -366,7 +393,8 @@
 }
 
 TargetHandler::TargetHandler(bool browser_only,
-                             const std::string& owner_target_id)
+                             const std::string& owner_target_id,
+                             TargetRegistry* target_registry)
     : DevToolsDomainHandler(Target::Metainfo::domainName),
       auto_attacher_(
           base::Bind(&TargetHandler::AutoAttach, base::Unretained(this)),
@@ -374,6 +402,7 @@
       discover_(false),
       browser_only_(browser_only),
       owner_target_id_(owner_target_id),
+      target_registry_(target_registry),
       weak_factory_(this) {}
 
 TargetHandler::~TargetHandler() {
@@ -425,7 +454,8 @@
 
 void TargetHandler::AutoAttach(DevToolsAgentHost* host,
                                bool waiting_for_debugger) {
-  std::string session_id = Session::Attach(this, host, waiting_for_debugger);
+  std::string session_id =
+      Session::Attach(this, host, waiting_for_debugger, false);
   auto_attached_sessions_[host] = attached_sessions_[session_id].get();
 }
 
@@ -501,13 +531,19 @@
 }
 
 Response TargetHandler::AttachToTarget(const std::string& target_id,
+                                       Maybe<bool> flatten,
                                        std::string* out_session_id) {
   // TODO(dgozman): only allow reported hosts.
   scoped_refptr<DevToolsAgentHost> agent_host =
       DevToolsAgentHost::GetForId(target_id);
   if (!agent_host)
     return Response::InvalidParams("No target with given id found");
-  *out_session_id = Session::Attach(this, agent_host.get(), false);
+  if (flatten.fromMaybe(false) && !target_registry_) {
+    return Response::InvalidParams(
+        "Will only provide flatten access for browser endpoint");
+  }
+  *out_session_id =
+      Session::Attach(this, agent_host.get(), false, flatten.fromMaybe(false));
   return Response::OK();
 }
 
@@ -530,6 +566,11 @@
       FindSession(std::move(session_id), std::move(target_id), &session, true);
   if (!response.isSuccess())
     return response;
+  if (session->flatten_protocol_) {
+    return Response::Error(
+        "When using flat protocol, messages are routed to the target "
+        "via the sessionId attribute.");
+  }
   session->SendMessageToAgentHost(message);
   return Response::OK();
 }
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h
index 3f68113..3a49945 100644
--- a/content/browser/devtools/protocol/target_handler.h
+++ b/content/browser/devtools/protocol/target_handler.h
@@ -21,6 +21,7 @@
 class NavigationHandle;
 class NavigationThrottle;
 class RenderFrameHostImpl;
+class TargetRegistry;
 
 namespace protocol {
 
@@ -28,7 +29,9 @@
                       public Target::Backend,
                       public DevToolsAgentHostObserver {
  public:
-  TargetHandler(bool browser_only, const std::string& owner_target_id);
+  TargetHandler(bool browser_only,
+                const std::string& owner_target_id,
+                TargetRegistry* target_registry);
   ~TargetHandler() override;
 
   static std::vector<TargetHandler*> ForAgentHost(DevToolsAgentHostImpl* host);
@@ -50,6 +53,7 @@
   Response SetRemoteLocations(
       std::unique_ptr<protocol::Array<Target::RemoteLocation>>) override;
   Response AttachToTarget(const std::string& target_id,
+                          Maybe<bool> flatten,
                           std::string* out_session_id) override;
   Response DetachFromTarget(Maybe<std::string> session_id,
                             Maybe<std::string> target_id) override;
@@ -106,9 +110,9 @@
   std::map<std::string, std::unique_ptr<Session>> attached_sessions_;
   std::map<DevToolsAgentHost*, Session*> auto_attached_sessions_;
   std::set<DevToolsAgentHost*> reported_hosts_;
-  int last_session_id_ = 0;
   bool browser_only_;
   std::string owner_target_id_;
+  TargetRegistry* target_registry_;
   base::flat_set<Throttle*> throttles_;
   base::WeakPtrFactory<TargetHandler> weak_factory_;
 
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 85377848..db70cad 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -426,7 +426,8 @@
   return web_contents();
 }
 
-bool RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+bool RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session,
+                                                 TargetRegistry* registry) {
   const bool is_webui =
       frame_host_ && (frame_host_->web_ui() || frame_host_->pending_web_ui());
   if (!session->client()->MayAttachToRenderer(frame_host_, is_webui))
@@ -455,8 +456,8 @@
   session->AddHandler(base::WrapUnique(new protocol::ServiceWorkerHandler()));
   session->AddHandler(base::WrapUnique(new protocol::StorageHandler()));
   if (!session->restricted()) {
-    session->AddHandler(base::WrapUnique(
-        new protocol::TargetHandler(false /* browser_only */, GetId())));
+    session->AddHandler(base::WrapUnique(new protocol::TargetHandler(
+        false /* browser_only */, GetId(), registry)));
   }
   session->AddHandler(
       base::WrapUnique(new protocol::PageHandler(emulation_handler)));
@@ -495,12 +496,6 @@
   }
 }
 
-void RenderFrameDevToolsAgentHost::DispatchProtocolMessage(
-    DevToolsSession* session,
-    const std::string& message) {
-  session->DispatchProtocolMessage(message);
-}
-
 void RenderFrameDevToolsAgentHost::InspectElement(RenderFrameHost* frame_host,
                                                   int x,
                                                   int y) {
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index bfc4b0ab..b4184bb 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -161,11 +161,10 @@
   ~RenderFrameDevToolsAgentHost() override;
 
   // DevToolsAgentHostImpl overrides.
-  bool AttachSession(DevToolsSession* session) override;
+  bool AttachSession(DevToolsSession* session,
+                     TargetRegistry* registry) override;
   void DetachSession(DevToolsSession* session) override;
   void InspectElement(RenderFrameHost* frame_host, int x, int y) override;
-  void DispatchProtocolMessage(DevToolsSession* session,
-                               const std::string& message) override;
 
   // WebContentsObserver overrides.
   void DidStartNavigation(NavigationHandle* navigation_handle) override;
diff --git a/content/browser/devtools/service_worker_devtools_agent_host.cc b/content/browser/devtools/service_worker_devtools_agent_host.cc
index c78e468c..32f191e7 100644
--- a/content/browser/devtools/service_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -115,7 +115,8 @@
   ServiceWorkerDevToolsManager::GetInstance()->AgentHostDestroyed(this);
 }
 
-bool ServiceWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+bool ServiceWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session,
+                                                   TargetRegistry* registry) {
   if (state_ == WORKER_READY) {
     if (sessions().size() == 1) {
       BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
@@ -141,12 +142,6 @@
   }
 }
 
-void ServiceWorkerDevToolsAgentHost::DispatchProtocolMessage(
-    DevToolsSession* session,
-    const std::string& message) {
-  session->DispatchProtocolMessage(message);
-}
-
 void ServiceWorkerDevToolsAgentHost::WorkerReadyForInspection(
     blink::mojom::DevToolsAgentAssociatedPtrInfo devtools_agent_ptr_info) {
   DCHECK_EQ(WORKER_NOT_READY, state_);
diff --git a/content/browser/devtools/service_worker_devtools_agent_host.h b/content/browser/devtools/service_worker_devtools_agent_host.h
index 453f52c..b261209 100644
--- a/content/browser/devtools/service_worker_devtools_agent_host.h
+++ b/content/browser/devtools/service_worker_devtools_agent_host.h
@@ -47,10 +47,9 @@
   bool Close() override;
 
   // DevToolsAgentHostImpl overrides.
-  bool AttachSession(DevToolsSession* session) override;
+  bool AttachSession(DevToolsSession* session,
+                     TargetRegistry* registry) override;
   void DetachSession(DevToolsSession* session) override;
-  void DispatchProtocolMessage(DevToolsSession* session,
-                               const std::string& message) override;
 
   void WorkerRestarted(int worker_process_id, int worker_route_id);
   void WorkerReadyForInspection(
diff --git a/content/browser/devtools/shared_worker_devtools_agent_host.cc b/content/browser/devtools/shared_worker_devtools_agent_host.cc
index 12c913b..c09e04a 100644
--- a/content/browser/devtools/shared_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/shared_worker_devtools_agent_host.cc
@@ -66,7 +66,8 @@
   return true;
 }
 
-bool SharedWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+bool SharedWorkerDevToolsAgentHost::AttachSession(DevToolsSession* session,
+                                                  TargetRegistry* registry) {
   session->AddHandler(std::make_unique<protocol::InspectorHandler>());
   session->AddHandler(std::make_unique<protocol::NetworkHandler>(
       GetId(), devtools_worker_token_, GetIOContext()));
@@ -81,12 +82,6 @@
   // Destroying session automatically detaches in renderer.
 }
 
-void SharedWorkerDevToolsAgentHost::DispatchProtocolMessage(
-    DevToolsSession* session,
-    const std::string& message) {
-  session->DispatchProtocolMessage(message);
-}
-
 bool SharedWorkerDevToolsAgentHost::Matches(SharedWorkerHost* worker_host) {
   return instance_->Matches(*worker_host->instance());
 }
diff --git a/content/browser/devtools/shared_worker_devtools_agent_host.h b/content/browser/devtools/shared_worker_devtools_agent_host.h
index 6a1d8007..c0a867de 100644
--- a/content/browser/devtools/shared_worker_devtools_agent_host.h
+++ b/content/browser/devtools/shared_worker_devtools_agent_host.h
@@ -33,10 +33,9 @@
   bool Close() override;
 
   // DevToolsAgentHostImpl overrides.
-  bool AttachSession(DevToolsSession* session) override;
+  bool AttachSession(DevToolsSession* session,
+                     TargetRegistry* registry) override;
   void DetachSession(DevToolsSession* session) override;
-  void DispatchProtocolMessage(DevToolsSession* session,
-                               const std::string& message) override;
 
   bool Matches(SharedWorkerHost* worker_host);
   void WorkerReadyForInspection();
diff --git a/content/browser/devtools/target_registry.cc b/content/browser/devtools/target_registry.cc
new file mode 100644
index 0000000..07d168a
--- /dev/null
+++ b/content/browser/devtools/target_registry.cc
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/devtools/target_registry.h"
+
+#include "base/strings/stringprintf.h"
+#include "content/browser/devtools/devtools_session.h"
+
+namespace content {
+
+TargetRegistry::TargetRegistry(DevToolsSession* root_session)
+    : root_session_(root_session) {}
+
+TargetRegistry::~TargetRegistry() {}
+
+void TargetRegistry::AttachSubtargetSession(const std::string& session_id,
+                                            DevToolsAgentHostImpl* agent_host,
+                                            DevToolsAgentHostClient* client) {
+  sessions_[session_id] = std::make_pair(agent_host, client);
+  agent_host->AttachSubtargetClient(client, this);
+}
+void TargetRegistry::DetachSubtargetSession(const std::string& session_id) {
+  sessions_.erase(session_id);
+}
+
+bool TargetRegistry::DispatchMessageOnAgentHost(
+    const std::string& message,
+    base::DictionaryValue* parsed_message) {
+  std::string session_id;
+  if (!parsed_message->GetString("sessionId", &session_id))
+    return false;
+  auto it = sessions_.find(session_id);
+  if (it == sessions_.end()) {
+    LOG(ERROR) << "Unknown session " << session_id;
+    return true;
+  }
+  scoped_refptr<DevToolsAgentHostImpl> agent_host = it->second.first;
+  DevToolsAgentHostClient* client = it->second.second;
+  return agent_host->DispatchProtocolMessage(client, message, parsed_message);
+}
+
+void TargetRegistry::SendMessageToClient(const std::string& session_id,
+                                         const std::string& message) {
+  DCHECK(message[message.length() - 1] == '}');
+  std::string suffix =
+      base::StringPrintf(", \"sessionId\": \"%s\"}", session_id.c_str());
+  std::string patched;
+  patched.reserve(message.length() + suffix.length() - 1);
+  patched.append(message.data(), message.length() - 1);
+  patched.append(suffix);
+  root_session_->client()->DispatchProtocolMessage(root_session_->agent_host(),
+                                                   patched);
+}
+
+}  // namespace content
diff --git a/content/browser/devtools/target_registry.h b/content/browser/devtools/target_registry.h
new file mode 100644
index 0000000..d915e1f
--- /dev/null
+++ b/content/browser/devtools/target_registry.h
@@ -0,0 +1,44 @@
+// 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_DEVTOOLS_TARGET_REGISTRY_H_
+#define CONTENT_BROWSER_DEVTOOLS_TARGET_REGISTRY_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/containers/flat_map.h"
+#include "base/values.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
+
+namespace content {
+
+class DevToolsSession;
+
+class TargetRegistry {
+ public:
+  explicit TargetRegistry(DevToolsSession* root_session);
+  ~TargetRegistry();
+
+  void AttachSubtargetSession(const std::string& session_id,
+                              DevToolsAgentHostImpl* agent_host,
+                              DevToolsAgentHostClient* client);
+  void DetachSubtargetSession(const std::string& session_id);
+  bool DispatchMessageOnAgentHost(const std::string& message,
+                                  base::DictionaryValue* parsed_message);
+  void SendMessageToClient(const std::string& session_id,
+                           const std::string& message);
+
+ private:
+  DevToolsSession* root_session_;
+  base::flat_map<
+      std::string,
+      std::pair<scoped_refptr<DevToolsAgentHostImpl>, DevToolsAgentHostClient*>>
+      sessions_;
+  DISALLOW_COPY_AND_ASSIGN(TargetRegistry);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVTOOLS_TARGET_REGISTRY_H_
diff --git a/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc b/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc
index 138b8d1..48bf2ed 100644
--- a/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_pre_close_task_queue_unittest.cc
@@ -80,7 +80,7 @@
   bool done_called = false;
   bool metadata_called = false;
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   IndexedDBPreCloseTaskQueue queue(
       std::list<std::unique_ptr<PreCloseTask>>(),
       base::BindOnce(&SetBoolValue, &done_called, true), kTestMaxRunTime,
@@ -104,7 +104,7 @@
   EXPECT_CALL(*task,
               SetMetadata(testing::Pointee(testing::ContainerEq(metadata_))));
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   std::list<std::unique_ptr<PreCloseTask>> tasks;
   tasks.push_back(base::WrapUnique(task));
   IndexedDBPreCloseTaskQueue queue(
@@ -134,7 +134,7 @@
   EXPECT_CALL(*task,
               SetMetadata(testing::Pointee(testing::ContainerEq(metadata_))));
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   std::list<std::unique_ptr<PreCloseTask>> tasks;
   tasks.push_back(base::WrapUnique(task));
   IndexedDBPreCloseTaskQueue queue(
@@ -178,7 +178,7 @@
   EXPECT_CALL(*task1,
               SetMetadata(testing::Pointee(testing::ContainerEq(metadata_))));
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   std::list<std::unique_ptr<PreCloseTask>> tasks;
   tasks.push_back(base::WrapUnique(task1));
   tasks.push_back(base::WrapUnique(task2));
@@ -227,7 +227,7 @@
   EXPECT_CALL(*task1,
               SetMetadata(testing::Pointee(testing::ContainerEq(metadata_))));
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   std::list<std::unique_ptr<PreCloseTask>> tasks;
   tasks.push_back(base::WrapUnique(task1));
   tasks.push_back(base::WrapUnique(task2));
@@ -260,7 +260,7 @@
   EXPECT_CALL(*task,
               SetMetadata(testing::Pointee(testing::ContainerEq(metadata_))));
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   std::list<std::unique_ptr<PreCloseTask>> tasks;
   tasks.push_back(base::WrapUnique(task));
   IndexedDBPreCloseTaskQueue queue(
@@ -301,7 +301,7 @@
   EXPECT_CALL(*task1,
               SetMetadata(testing::Pointee(testing::ContainerEq(metadata_))));
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   std::list<std::unique_ptr<PreCloseTask>> tasks;
   tasks.push_back(base::WrapUnique(task1));
   tasks.push_back(base::WrapUnique(task2));
@@ -345,7 +345,7 @@
   EXPECT_CALL(*task1,
               SetMetadata(testing::Pointee(testing::ContainerEq(metadata_))));
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   std::list<std::unique_ptr<PreCloseTask>> tasks;
   tasks.push_back(base::WrapUnique(task1));
   tasks.push_back(base::WrapUnique(task2));
@@ -387,7 +387,7 @@
   MockPreCloseTask* task1 = new testing::StrictMock<MockPreCloseTask>();
   MockPreCloseTask* task2 = new testing::StrictMock<MockPreCloseTask>();
 
-  base::MockTimer* fake_timer = new base::MockTimer(true, false);
+  base::MockOneShotTimer* fake_timer = new base::MockOneShotTimer;
   std::list<std::unique_ptr<PreCloseTask>> tasks;
   tasks.push_back(base::WrapUnique(task1));
   tasks.push_back(base::WrapUnique(task2));
diff --git a/content/browser/linux_ipc_browsertest.cc b/content/browser/linux_ipc_browsertest.cc
deleted file mode 100644
index 7be0589..0000000
--- a/content/browser/linux_ipc_browsertest.cc
+++ /dev/null
@@ -1,91 +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 <map>
-#include <set>
-#include <string>
-
-#include "base/command_line.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "content/browser/sandbox_ipc_linux.h"
-#include "content/public/common/content_switches.h"
-#include "content/public/test/content_browser_test.h"
-#include "content/public/test/content_browser_test_utils.h"
-#include "services/service_manager/sandbox/switches.h"
-#include "testing/gmock/include/gmock/gmock-matchers.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace content {
-
-class LinuxIPCBrowserTest : public ContentBrowserTest,
-                            public SandboxIPCHandler::TestObserver,
-                            public testing::WithParamInterface<std::string> {
- public:
-  LinuxIPCBrowserTest() {
-    SandboxIPCHandler::SetObserverForTests(this);
-  }
-  ~LinuxIPCBrowserTest() override {}
-
- protected:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    ContentBrowserTest::SetUpCommandLine(command_line);
-    if (GetParam() == "no-zygote") {
-      command_line->AppendSwitch(service_manager::switches::kNoSandbox);
-      command_line->AppendSwitch(switches::kNoZygote);
-    }
-  }
-
-  void OnFontOpen(int id) override {
-    base::AutoLock lock(lock_);
-    opened_fonts_.insert(font_names_[id]);
-  }
-
-  void OnGetFallbackFontForChar(UChar32 c, std::string name, int id) override {
-    base::AutoLock lock(lock_);
-    fallback_fonts_[c] = name;
-    font_names_[id] = name;
-  }
-
-  std::string FallbackFontName(UChar32 c) {
-    base::AutoLock lock(lock_);
-    return fallback_fonts_[c];
-  }
-
-  std::set<std::string> OpenedFonts() {
-    base::AutoLock lock(lock_);
-    return opened_fonts_;
-  }
-
-  // These variables are accessed on the IPC thread and the test thread.
-  // All accesses on the IPC thread should be before the renderer process
-  // completes navigation, and all accesses on the test thread should be after.
-  // However we still need a mutex for the accesses to be sequenced according to
-  // the C++ memory model.
-  base::Lock lock_;
-  std::map<UChar32, std::string> fallback_fonts_;
-  std::map<int, std::string> font_names_;
-  std::set<std::string> opened_fonts_;
-
-  DISALLOW_COPY_AND_ASSIGN(LinuxIPCBrowserTest);
-};
-
-// Tests that Linux IPC font fallback code runs round-trip when Zygote is
-// disabled. It doesn't care what font is chosen, just that the IPC messages are
-// flowing. This test assumes that U+65E5 (CJK "Sun" character) will trigger the
-// font fallback codepath.
-IN_PROC_BROWSER_TEST_P(LinuxIPCBrowserTest, FontFallbackIPCWorks) {
-  GURL test_url = GetTestUrl("font", "font_fallback.html");
-  EXPECT_TRUE(NavigateToURL(shell(), test_url));
-  EXPECT_THAT(FallbackFontName(U'\U000065E5'), testing::Ne(""));
-  EXPECT_THAT(OpenedFonts(),
-              testing::Contains(FallbackFontName(U'\U000065E5')));
-}
-
-INSTANTIATE_TEST_CASE_P(LinuxIPCBrowserTest,
-                        LinuxIPCBrowserTest,
-                        ::testing::Values("zygote", "no-zygote"));
-
-}  // namespace
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index fa74eb01..d8eeafef 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -14,6 +14,7 @@
 #include "base/trace_event/trace_event.h"
 #include "components/download/public/common/download_stats.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
+#include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
@@ -358,6 +359,9 @@
       ServiceWorkerNavigationHandleCore* service_worker_navigation_handle_core,
       AppCacheNavigationHandleCore* appcache_handle_core,
       bool was_request_intercepted) const {
+    if (appcache_handle_core)
+      appcache_handle_core->AddDefaultFactoryRunToDebugLog(
+          was_request_intercepted);
     return base::BindOnce(
         &URLLoaderRequestController::CreateNonNetworkServiceURLLoader,
         weak_factory_.GetWeakPtr(),
@@ -388,6 +392,9 @@
     DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
+    if (appcache_handle_core)
+      appcache_handle_core->AddCreateURLLoaderToDebugLog();
+
     default_loader_used_ = true;
     if (signed_exchange_utils::IsSignedExchangeHandlingEnabled()) {
       DCHECK(!default_url_loader_factory_getter_);
@@ -452,6 +459,9 @@
     DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     DCHECK(!started_);
+    if (appcache_handle_core)
+      appcache_handle_core->AddNavigationStartToDebugLog();
+
     started_ = true;
     request_info_ = std::move(request_info);
     frame_tree_node_id_ = request_info_->frame_tree_node_id;
diff --git a/content/browser/renderer_host/font_utils_linux.cc b/content/browser/renderer_host/font_utils_linux.cc
deleted file mode 100644
index e5fd81a..0000000
--- a/content/browser/renderer_host/font_utils_linux.cc
+++ /dev/null
@@ -1,265 +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 <fcntl.h>
-#include <fontconfig/fontconfig.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include "base/posix/eintr_wrapper.h"
-
-// TODO(crbug/685022): Guard the inclusion of ppapi headers with
-// BUILDFLAG(ENABLE_PLUGINS).
-#include "ppapi/c/private/pp_private_font_charset.h"  // nogncheck
-#include "ppapi/c/trusted/ppb_browser_font_trusted.h"  // nogncheck
-
-namespace {
-
-// MSCharSetToFontconfig translates a Microsoft charset identifier to a
-// fontconfig language set by appending to |langset|.
-// Returns true if |langset| is Latin/Greek/Cyrillic.
-bool MSCharSetToFontconfig(FcLangSet* langset, unsigned fdwCharSet) {
-  // We have need to translate raw fdwCharSet values into terms that
-  // fontconfig can understand. (See the description of fdwCharSet in the MSDN
-  // documentation for CreateFont:
-  // http://msdn.microsoft.com/en-us/library/dd183499(VS.85).aspx )
-  //
-  // Although the argument is /called/ 'charset', the actual values conflate
-  // character sets (which are sets of Unicode code points) and character
-  // encodings (which are algorithms for turning a series of bits into a
-  // series of code points.) Sometimes the values will name a language,
-  // sometimes they'll name an encoding. In the latter case I'm assuming that
-  // they mean the set of code points in the domain of that encoding.
-  //
-  // fontconfig deals with ISO 639-1 language codes:
-  //   http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
-  //
-  // So, for each of the documented fdwCharSet values I've had to take a
-  // guess at the set of ISO 639-1 languages intended.
-
-  bool is_lgc = false;
-  switch (fdwCharSet) {
-    case PP_PRIVATEFONTCHARSET_ANSI:
-    // These values I don't really know what to do with, so I'm going to map
-    // them to English also.
-    case PP_PRIVATEFONTCHARSET_DEFAULT:
-    case PP_PRIVATEFONTCHARSET_MAC:
-    case PP_PRIVATEFONTCHARSET_OEM:
-    case PP_PRIVATEFONTCHARSET_SYMBOL:
-      is_lgc = true;
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("en"));
-      break;
-    case PP_PRIVATEFONTCHARSET_BALTIC:
-      // The three baltic languages.
-      is_lgc = true;
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("et"));
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lv"));
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lt"));
-      break;
-    case PP_PRIVATEFONTCHARSET_CHINESEBIG5:
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-tw"));
-      break;
-    case PP_PRIVATEFONTCHARSET_GB2312:
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-cn"));
-      break;
-    case PP_PRIVATEFONTCHARSET_EASTEUROPE:
-      // A scattering of eastern European languages.
-      is_lgc = true;
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("pl"));
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("cs"));
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("sk"));
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hu"));
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hr"));
-      break;
-    case PP_PRIVATEFONTCHARSET_GREEK:
-      is_lgc = true;
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("el"));
-      break;
-    case PP_PRIVATEFONTCHARSET_HANGUL:
-    case PP_PRIVATEFONTCHARSET_JOHAB:
-      // Korean
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ko"));
-      break;
-    case PP_PRIVATEFONTCHARSET_RUSSIAN:
-      is_lgc = true;
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ru"));
-      break;
-    case PP_PRIVATEFONTCHARSET_SHIFTJIS:
-      // Japanese
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ja"));
-      break;
-    case PP_PRIVATEFONTCHARSET_TURKISH:
-      is_lgc = true;
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("tr"));
-      break;
-    case PP_PRIVATEFONTCHARSET_VIETNAMESE:
-      is_lgc = true;
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("vi"));
-      break;
-    case PP_PRIVATEFONTCHARSET_ARABIC:
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ar"));
-      break;
-    case PP_PRIVATEFONTCHARSET_HEBREW:
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("he"));
-      break;
-    case PP_PRIVATEFONTCHARSET_THAI:
-      FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("th"));
-      break;
-      // default:
-      // Don't add any languages in that case that we don't recognise the
-      // constant.
-  }
-  return is_lgc;
-}
-
-}  // namespace
-
-namespace content {
-
-int MatchFontFaceWithFallback(const std::string& face,
-                              bool is_bold,
-                              bool is_italic,
-                              uint32_t charset,
-                              uint32_t fallback_family) {
-  FcLangSet* langset = FcLangSetCreate();
-  bool is_lgc = MSCharSetToFontconfig(langset, charset);
-  FcPattern* pattern = FcPatternCreate();
-  FcPatternAddString(
-      pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(face.c_str()));
-
-  // TODO(thestig) Check if we can access Chrome's per-script font preference
-  // here and select better default fonts for non-LGC case.
-  std::string generic_font_name;
-  if (is_lgc) {
-    switch (fallback_family) {
-      case PP_BROWSERFONT_TRUSTED_FAMILY_SERIF:
-        generic_font_name = "Times New Roman";
-        break;
-      case PP_BROWSERFONT_TRUSTED_FAMILY_SANSSERIF:
-        generic_font_name = "Arial";
-        break;
-      case PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE:
-        generic_font_name = "Courier New";
-        break;
-    }
-  }
-  if (!generic_font_name.empty()) {
-    const FcChar8* fc_generic_font_name =
-        reinterpret_cast<const FcChar8*>(generic_font_name.c_str());
-    FcPatternAddString(pattern, FC_FAMILY, fc_generic_font_name);
-  }
-
-  if (is_bold)
-    FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
-  if (is_italic)
-    FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
-  FcPatternAddLangSet(pattern, FC_LANG, langset);
-  FcPatternAddBool(pattern, FC_SCALABLE, FcTrue);
-  FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
-  FcDefaultSubstitute(pattern);
-
-  FcResult result;
-  FcFontSet* font_set = FcFontSort(nullptr, pattern, 0, nullptr, &result);
-  int font_fd = -1;
-  int good_enough_index = -1;
-  bool good_enough_index_set = false;
-
-  if (font_set) {
-    for (int i = 0; i < font_set->nfont; ++i) {
-      FcPattern* current = font_set->fonts[i];
-
-      // Older versions of fontconfig have a bug where they cannot select
-      // only scalable fonts so we have to manually filter the results.
-      FcBool is_scalable;
-      if (FcPatternGetBool(current, FC_SCALABLE, 0, &is_scalable) !=
-              FcResultMatch ||
-          !is_scalable) {
-        continue;
-      }
-
-      FcChar8* c_filename;
-      if (FcPatternGetString(current, FC_FILE, 0, &c_filename) !=
-          FcResultMatch) {
-        continue;
-      }
-
-      // We only want to return sfnt (TrueType) based fonts. We don't have a
-      // very good way of detecting this so we'll filter based on the
-      // filename.
-      bool is_sfnt = false;
-      static const char kSFNTExtensions[][5] = {".ttf", ".otc", ".TTF", ".ttc",
-                                                ""};
-      const size_t filename_len = strlen(reinterpret_cast<char*>(c_filename));
-      for (unsigned j = 0;; j++) {
-        if (kSFNTExtensions[j][0] == 0) {
-          // None of the extensions matched.
-          break;
-        }
-        const size_t ext_len = strlen(kSFNTExtensions[j]);
-        if (filename_len > ext_len &&
-            memcmp(c_filename + filename_len - ext_len,
-                   kSFNTExtensions[j],
-                   ext_len) == 0) {
-          is_sfnt = true;
-          break;
-        }
-      }
-
-      if (!is_sfnt)
-        continue;
-
-      // This font is good enough to pass muster, but we might be able to do
-      // better with subsequent ones.
-      if (!good_enough_index_set) {
-        good_enough_index = i;
-        good_enough_index_set = true;
-      }
-
-      FcValue matrix;
-      bool have_matrix = FcPatternGet(current, FC_MATRIX, 0, &matrix) == 0;
-
-      if (is_italic && have_matrix) {
-        // we asked for an italic font, but fontconfig is giving us a
-        // non-italic font with a transformation matrix.
-        continue;
-      }
-
-      FcValue embolden;
-      const bool have_embolden =
-          FcPatternGet(current, FC_EMBOLDEN, 0, &embolden) == 0;
-
-      if (is_bold && have_embolden) {
-        // we asked for a bold font, but fontconfig gave us a non-bold font
-        // and asked us to apply fake bolding.
-        continue;
-      }
-
-      font_fd =
-          HANDLE_EINTR(open(reinterpret_cast<char*>(c_filename), O_RDONLY));
-      if (font_fd >= 0)
-        break;
-    }
-  }
-
-  if (font_fd == -1 && good_enough_index_set) {
-    // We didn't find a font that we liked, so we fallback to something
-    // acceptable.
-    FcPattern* current = font_set->fonts[good_enough_index];
-    FcChar8* c_filename;
-    FcPatternGetString(current, FC_FILE, 0, &c_filename);
-    font_fd = HANDLE_EINTR(open(reinterpret_cast<char*>(c_filename), O_RDONLY));
-  }
-
-  if (font_set)
-    FcFontSetDestroy(font_set);
-  FcPatternDestroy(pattern);
-
-  return font_fd;
-}
-
-}  // namespace content
diff --git a/content/browser/renderer_host/font_utils_linux.h b/content/browser/renderer_host/font_utils_linux.h
deleted file mode 100644
index 33b31af6..0000000
--- a/content/browser/renderer_host/font_utils_linux.h
+++ /dev/null
@@ -1,22 +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 CONTENT_BROWSER_RENDERER_HOST_FONT_UTILS_LINUX_H_
-#define CONTENT_BROWSER_RENDERER_HOST_FONT_UTILS_LINUX_H_
-
-#include <stdint.h>
-
-#include <string>
-
-namespace content {
-
-int MatchFontFaceWithFallback(const std::string& face,
-                              bool is_bold,
-                              bool is_italic,
-                              uint32_t charset,
-                              uint32_t fallback_family);
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_FONT_UTILS_LINUX_H_
diff --git a/content/browser/renderer_host/pepper/pepper_truetype_font_linux.cc b/content/browser/renderer_host/pepper/pepper_truetype_font_linux.cc
index c9a8d3f..c71954e 100644
--- a/content/browser/renderer_host/pepper/pepper_truetype_font_linux.cc
+++ b/content/browser/renderer_host/pepper/pepper_truetype_font_linux.cc
@@ -14,8 +14,10 @@
 #include "base/macros.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/sys_byteorder.h"
-#include "content/browser/renderer_host/font_utils_linux.h"
+#include "build/build_config.h"
+#include "components/services/font/ppapi_fontconfig_matching.h"
 #include "content/public/common/common_sandbox_support_linux.h"
+#include "ppapi/buildflags/buildflags.h"
 #include "ppapi/c/dev/ppb_truetype_font_dev.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/trusted/ppb_browser_font_trusted.h"
@@ -74,12 +76,10 @@
     }
   }
 
-  fd_.reset(
-      MatchFontFaceWithFallback(desc->family,
-                                desc->weight >= PP_TRUETYPEFONTWEIGHT_BOLD,
-                                desc->style & PP_TRUETYPEFONTSTYLE_ITALIC,
-                                desc->charset,
-                                PP_BROWSERFONT_TRUSTED_FAMILY_DEFAULT));
+  fd_.reset(font_service::MatchFontFaceWithFallback(
+      desc->family, desc->weight >= PP_TRUETYPEFONTWEIGHT_BOLD,
+      desc->style & PP_TRUETYPEFONTSTYLE_ITALIC, desc->charset,
+      PP_BROWSERFONT_TRUSTED_FAMILY_DEFAULT));
   // TODO(bbudge) Modify content API to return results of font matching and
   // fallback, so we can update |desc| to reflect that.
   return fd_.is_valid() ? PP_OK : PP_ERROR_FAILED;
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 982ae3e1..582d8037 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -218,6 +218,8 @@
 
   bool HostHasNotBeenUsed() override;
   void LockToOrigin(const GURL& lock_url) override;
+  void BindCacheStorage(blink::mojom::CacheStorageRequest request,
+                        const url::Origin& origin) override;
 
   mojom::RouteProvider* GetRemoteRouteProvider();
 
@@ -405,11 +407,6 @@
 
   bool is_initialized() const { return is_initialized_; }
 
-  // Binds Mojo request to Mojo implementation CacheStorageDispatcherHost
-  // instance, binding is sent to IO thread.
-  void BindCacheStorage(blink::mojom::CacheStorageRequest request,
-                        const url::Origin& origin);
-
   // Ensures that this process is kept alive for the specified amount of time.
   // This is used to ensure that unload handlers have a chance to execute
   // before the process shuts down.
diff --git a/content/browser/sandbox_ipc_linux.cc b/content/browser/sandbox_ipc_linux.cc
index c37d0a53..a893d1b 100644
--- a/content/browser/sandbox_ipc_linux.cc
+++ b/content/browser/sandbox_ipc_linux.cc
@@ -21,69 +21,15 @@
 #include "base/posix/unix_domain_socket.h"
 #include "base/process/launch.h"
 #include "base/strings/string_number_conversions.h"
-#include "content/browser/renderer_host/font_utils_linux.h"
-#include "content/common/font_config_ipc_linux.h"
 #include "content/public/common/content_switches.h"
 #include "sandbox/linux/services/libc_interceptor.h"
 #include "services/service_manager/sandbox/linux/sandbox_linux.h"
-#include "skia/ext/skia_utils_base.h"
-#include "third_party/skia/include/ports/SkFontConfigInterface.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/font_fallback_linux.h"
-#include "ui/gfx/font_render_params.h"
 
 namespace content {
 
-namespace {
-
-SandboxIPCHandler::TestObserver* g_test_observer = nullptr;
-
-// Converts gfx::FontRenderParams::Hinting to WebFontRenderStyle::hintStyle.
-// Returns an int for serialization, but the underlying Blink type is a char.
-int ConvertHinting(gfx::FontRenderParams::Hinting hinting) {
-  switch (hinting) {
-    case gfx::FontRenderParams::HINTING_NONE:
-      return 0;
-    case gfx::FontRenderParams::HINTING_SLIGHT:
-      return 1;
-    case gfx::FontRenderParams::HINTING_MEDIUM:
-      return 2;
-    case gfx::FontRenderParams::HINTING_FULL:
-      return 3;
-  }
-  NOTREACHED() << "Unexpected hinting value " << hinting;
-  return 0;
-}
-
-// Converts gfx::FontRenderParams::SubpixelRendering to
-// WebFontRenderStyle::useSubpixelRendering. Returns an int for serialization,
-// but the underlying Blink type is a char.
-int ConvertSubpixelRendering(
-    gfx::FontRenderParams::SubpixelRendering rendering) {
-  switch (rendering) {
-    case gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE:
-      return 0;
-    case gfx::FontRenderParams::SUBPIXEL_RENDERING_RGB:
-      return 1;
-    case gfx::FontRenderParams::SUBPIXEL_RENDERING_BGR:
-      return 1;
-    case gfx::FontRenderParams::SUBPIXEL_RENDERING_VRGB:
-      return 1;
-    case gfx::FontRenderParams::SUBPIXEL_RENDERING_VBGR:
-      return 1;
-  }
-  NOTREACHED() << "Unexpected subpixel rendering value " << rendering;
-  return 0;
-}
-
-}  // namespace
+const size_t kMaxSandboxIPCMessagePayloadSize = 64;
 
 // static
-void SandboxIPCHandler::SetObserverForTests(
-    SandboxIPCHandler::TestObserver* observer) {
-  g_test_observer = observer;
-}
-
 SandboxIPCHandler::SandboxIPCHandler(int lifeline_fd, int browser_socket)
     : lifeline_fd_(lifeline_fd), browser_socket_(browser_socket) {}
 
@@ -136,17 +82,22 @@
 
   // A FontConfigIPC::METHOD_MATCH message could be kMaxFontFamilyLength
   // bytes long (this is the largest message type).
+  // The size limit  used to be FontConfigIPC::kMaxFontFamilyLength which was
+  // 2048, but we do not receive FontConfig IPC here anymore. The only payloads
+  // here are service_manager::SandboxLinux::METHOD_MAKE_SHARED_MEMORY_SEGMENT
+  // and HandleLocalTime from libc_interceptor for which
+  // kMaxSandboxIPCMessagePayloadSize set to 64 should be plenty.
   // 128 bytes padding are necessary so recvmsg() does not return MSG_TRUNC
   // error for a maximum length message.
-  char buf[FontConfigIPC::kMaxFontFamilyLength + 128];
+  char buf[kMaxSandboxIPCMessagePayloadSize + 128];
 
   const ssize_t len =
       base::UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds);
   if (len == -1) {
     // TODO: should send an error reply, or the sender might block forever.
     if (errno == EMSGSIZE) {
-      NOTREACHED()
-          << "Sandbox host message is larger than kMaxFontFamilyLength";
+      NOTREACHED() << "Sandbox host message is larger than "
+                      "kMaxSandboxIPCMessagePayloadSize";
     } else {
       PLOG(ERROR) << "Recvmsg failed";
       NOTREACHED();
@@ -168,167 +119,12 @@
   if (sandbox::HandleInterceptedCall(kind, fd, iter, fds))
     return;
 
-  if (kind == FontConfigIPC::METHOD_MATCH) {
-    HandleFontMatchRequest(fd, iter, fds);
-  } else if (kind == FontConfigIPC::METHOD_OPEN) {
-    HandleFontOpenRequest(fd, iter, fds);
-  } else if (kind ==
-             service_manager::SandboxLinux::METHOD_GET_FALLBACK_FONT_FOR_CHAR) {
-    HandleGetFallbackFontForChar(fd, iter, fds);
-  } else if (kind ==
-             service_manager::SandboxLinux::METHOD_GET_STYLE_FOR_STRIKE) {
-    HandleGetStyleForStrike(fd, iter, fds);
-  } else if (kind ==
-             service_manager::SandboxLinux::METHOD_MAKE_SHARED_MEMORY_SEGMENT) {
+  if (kind ==
+      service_manager::SandboxLinux::METHOD_MAKE_SHARED_MEMORY_SEGMENT) {
     HandleMakeSharedMemorySegment(fd, iter, fds);
-  } else if (kind ==
-             service_manager::SandboxLinux::METHOD_MATCH_WITH_FALLBACK) {
-    HandleMatchWithFallback(fd, iter, fds);
-  }
-}
-
-int SandboxIPCHandler::FindOrAddPath(const SkString& path) {
-  int count = paths_.size();
-  for (int i = 0; i < count; ++i) {
-    if (path == paths_[i])
-      return i;
-  }
-  paths_.emplace_back(path);
-  return count;
-}
-
-void SandboxIPCHandler::HandleFontMatchRequest(
-    int fd,
-    base::PickleIterator iter,
-    const std::vector<base::ScopedFD>& fds) {
-  SkFontStyle requested_style;
-  std::string family;
-  if (!iter.ReadString(&family) ||
-      !skia::ReadSkFontStyle(&iter, &requested_style))
-    return;
-
-  SkFontConfigInterface::FontIdentity result_identity;
-  SkString result_family;
-  SkFontStyle result_style;
-  SkFontConfigInterface* fc =
-      SkFontConfigInterface::GetSingletonDirectInterface();
-  const bool r =
-      fc->matchFamilyName(family.c_str(), requested_style, &result_identity,
-                          &result_family, &result_style);
-
-  base::Pickle reply;
-  if (!r) {
-    reply.WriteBool(false);
-  } else {
-    // Stash away the returned path, so we can give it an ID (index)
-    // which will later be given to us in a request to open the file.
-    int index = FindOrAddPath(result_identity.fString);
-    result_identity.fID = static_cast<uint32_t>(index);
-
-    reply.WriteBool(true);
-    skia::WriteSkString(&reply, result_family);
-    skia::WriteSkFontIdentity(&reply, result_identity);
-    skia::WriteSkFontStyle(&reply, result_style);
-  }
-  SendRendererReply(fds, reply, -1);
-}
-
-void SandboxIPCHandler::HandleFontOpenRequest(
-    int fd,
-    base::PickleIterator iter,
-    const std::vector<base::ScopedFD>& fds) {
-  uint32_t index;
-  if (!iter.ReadUInt32(&index))
-    return;
-  if (index >= static_cast<uint32_t>(paths_.size()))
-    return;
-  if (g_test_observer) {
-    g_test_observer->OnFontOpen(index);
-  }
-  const int result_fd = open(paths_[index].c_str(), O_RDONLY);
-
-  base::Pickle reply;
-  reply.WriteBool(result_fd != -1);
-
-  // The receiver will have its own access to the file, so we will close it
-  // after this send.
-  SendRendererReply(fds, reply, result_fd);
-
-  if (result_fd >= 0) {
-    int err = IGNORE_EINTR(close(result_fd));
-    DCHECK(!err);
-  }
-}
-
-void SandboxIPCHandler::HandleGetFallbackFontForChar(
-    int fd,
-    base::PickleIterator iter,
-    const std::vector<base::ScopedFD>& fds) {
-  // The other side of this call is
-  // content/common/child_process_sandbox_support_impl_linux.cc
-
-  UChar32 c;
-  if (!iter.ReadInt(&c))
-    return;
-
-  std::string preferred_locale;
-  if (!iter.ReadString(&preferred_locale))
-    return;
-
-  auto fallback_font = gfx::GetFallbackFontForChar(c, preferred_locale);
-  int fontconfig_interface_id =
-      FindOrAddPath(SkString(fallback_font.filename.data()));
-
-  if (g_test_observer) {
-    g_test_observer->OnGetFallbackFontForChar(c, fallback_font.name,
-                                              fontconfig_interface_id);
-  }
-  base::Pickle reply;
-  reply.WriteString(fallback_font.name);
-  reply.WriteString(fallback_font.filename);
-  reply.WriteInt(fontconfig_interface_id);
-  reply.WriteInt(fallback_font.ttc_index);
-  reply.WriteBool(fallback_font.is_bold);
-  reply.WriteBool(fallback_font.is_italic);
-  SendRendererReply(fds, reply, -1);
-}
-
-void SandboxIPCHandler::HandleGetStyleForStrike(
-    int fd,
-    base::PickleIterator iter,
-    const std::vector<base::ScopedFD>& fds) {
-  std::string family;
-  bool bold;
-  bool italic;
-  uint16_t pixel_size;
-  float device_scale_factor;
-
-  if (!iter.ReadString(&family) || !iter.ReadBool(&bold) ||
-      !iter.ReadBool(&italic) || !iter.ReadUInt16(&pixel_size) ||
-      !iter.ReadFloat(&device_scale_factor)) {
     return;
   }
-
-  gfx::FontRenderParamsQuery query;
-  query.families.push_back(family);
-  query.pixel_size = pixel_size;
-  query.style = italic ? gfx::Font::ITALIC : 0;
-  query.weight = bold ? gfx::Font::Weight::BOLD : gfx::Font::Weight::NORMAL;
-  query.device_scale_factor = device_scale_factor;
-  const gfx::FontRenderParams params = gfx::GetFontRenderParams(query, nullptr);
-
-  // These are passed as ints since they're interpreted as tri-state chars in
-  // Blink.
-  base::Pickle reply;
-  reply.WriteInt(params.use_bitmaps);
-  reply.WriteInt(params.autohinter);
-  reply.WriteInt(params.hinting != gfx::FontRenderParams::HINTING_NONE);
-  reply.WriteInt(ConvertHinting(params.hinting));
-  reply.WriteInt(params.antialiasing);
-  reply.WriteInt(ConvertSubpixelRendering(params.subpixel_rendering));
-  reply.WriteInt(params.subpixel_positioning);
-
-  SendRendererReply(fds, reply, -1);
+  NOTREACHED();
 }
 
 void SandboxIPCHandler::HandleMakeSharedMemorySegment(
@@ -350,34 +146,6 @@
   SendRendererReply(fds, reply, shm_fd);
 }
 
-void SandboxIPCHandler::HandleMatchWithFallback(
-    int fd,
-    base::PickleIterator iter,
-    const std::vector<base::ScopedFD>& fds) {
-  std::string face;
-  bool is_bold;
-  bool is_italic;
-  uint32_t charset;
-  uint32_t fallback_family;
-
-  if (!iter.ReadString(&face) || face.empty() || !iter.ReadBool(&is_bold) ||
-      !iter.ReadBool(&is_italic) || !iter.ReadUInt32(&charset) ||
-      !iter.ReadUInt32(&fallback_family)) {
-    return;
-  }
-
-  int font_fd = MatchFontFaceWithFallback(face, is_bold, is_italic, charset,
-                                          fallback_family);
-
-  base::Pickle reply;
-  SendRendererReply(fds, reply, font_fd);
-
-  if (font_fd >= 0) {
-    if (IGNORE_EINTR(close(font_fd)) < 0)
-      PLOG(ERROR) << "close";
-  }
-}
-
 void SandboxIPCHandler::SendRendererReply(
     const std::vector<base::ScopedFD>& fds,
     const base::Pickle& reply,
diff --git a/content/browser/sandbox_ipc_linux.h b/content/browser/sandbox_ipc_linux.h
index 06c2c604..684a6aa 100644
--- a/content/browser/sandbox_ipc_linux.h
+++ b/content/browser/sandbox_ipc_linux.h
@@ -18,8 +18,6 @@
 #include "content/common/content_export.h"
 #include "third_party/icu/source/common/unicode/uchar.h"
 
-class SkString;
-
 namespace content {
 
 class SandboxIPCHandler : public base::DelegateSimpleThread::Delegate {
@@ -32,55 +30,19 @@
 
   void Run() override;
 
-  class TestObserver {
-   public:
-    virtual void OnGetFallbackFontForChar(UChar32 c,
-                                          std::string name,
-                                          int id) = 0;
-    virtual void OnFontOpen(int id) = 0;
-  };
-  CONTENT_EXPORT static void SetObserverForTests(TestObserver* observer);
-
  private:
-  int FindOrAddPath(const SkString& path);
-
   void HandleRequestFromChild(int fd);
 
-  void HandleFontMatchRequest(int fd,
-                              base::PickleIterator iter,
-                              const std::vector<base::ScopedFD>& fds);
-
-  void HandleFontOpenRequest(int fd,
-                             base::PickleIterator iter,
-                             const std::vector<base::ScopedFD>& fds);
-
-  void HandleGetFallbackFontForChar(int fd,
-                                    base::PickleIterator iter,
-                                    const std::vector<base::ScopedFD>& fds);
-
-  void HandleGetStyleForStrike(int fd,
-                               base::PickleIterator iter,
-                               const std::vector<base::ScopedFD>& fds);
-
-  void HandleLocaltime(int fd,
-                       base::PickleIterator iter,
-                       const std::vector<base::ScopedFD>& fds);
-
   void HandleMakeSharedMemorySegment(int fd,
                                      base::PickleIterator iter,
                                      const std::vector<base::ScopedFD>& fds);
 
-  void HandleMatchWithFallback(int fd,
-                               base::PickleIterator iter,
-                               const std::vector<base::ScopedFD>& fds);
-
   void SendRendererReply(const std::vector<base::ScopedFD>& fds,
                          const base::Pickle& reply,
                          int reply_fd);
 
   const int lifeline_fd_;
   const int browser_socket_;
-  std::vector<SkString> paths_;
 
   DISALLOW_COPY_AND_ASSIGN(SandboxIPCHandler);
 };
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index c5be387..8b0f33aa 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -184,28 +184,44 @@
 
   static void CreateLoaderAndStartOnIOThread(
       scoped_refptr<ResourceMessageFilter> filter,
+      network::mojom::URLLoaderRequest request,
       int route_id,
       int request_id,
-      const network::ResourceRequest& request) {
-    network::mojom::URLLoaderPtr loader;
-    network::TestURLLoaderClient client;
+      const network::ResourceRequest& resource_request,
+      network::mojom::URLLoaderClientPtrInfo client) {
     filter->CreateLoaderAndStart(
-        mojo::MakeRequest(&loader), route_id, request_id,
-        network::mojom::kURLLoadOptionNone, request,
-        client.CreateInterfacePtr(),
+        std::move(request), route_id, request_id,
+        network::mojom::kURLLoadOptionNone, resource_request,
+        network::mojom::URLLoaderClientPtr(std::move(client)),
         net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
   }
 
-  static void CreateLoaderAndStart(RenderProcessHost* process,
-                                   int route_id,
-                                   int request_id,
-                                   const network::ResourceRequest& request) {
+  static void CreateLoaderAndStart(
+      RenderProcessHost* process,
+      int route_id,
+      int request_id,
+      const network::ResourceRequest& resource_request) {
+    network::mojom::URLLoaderPtr loader;
+    network::TestURLLoaderClient client;
+    CreateLoaderAndStart(process, mojo::MakeRequest(&loader), route_id,
+                         request_id, resource_request,
+                         client.CreateInterfacePtr().PassInterface());
+  }
+
+  static void CreateLoaderAndStart(
+      RenderProcessHost* process,
+      network::mojom::URLLoaderRequest request,
+      int route_id,
+      int request_id,
+      const network::ResourceRequest& resource_request,
+      network::mojom::URLLoaderClientPtrInfo client) {
     RenderProcessHostImpl* impl = static_cast<RenderProcessHostImpl*>(process);
     auto filter = impl->resource_message_filter_;
 
     process->GetChannel()->ipc_task_runner()->PostTask(
         FROM_HERE, base::BindOnce(CreateLoaderAndStartOnIOThread, filter,
-                                  route_id, request_id, request));
+                                  std::move(request), route_id, request_id,
+                                  resource_request, std::move(client)));
   }
 
   void TryCreateDuplicateRequestIds(Shell* shell, bool block_loaders) {
@@ -227,11 +243,16 @@
 
     // Use the same request id twice.
     RenderProcessHostKillWaiter kill_waiter(rfh->GetProcess());
+    // We need to keep loader and client to keep the requests alive.
+    network::mojom::URLLoaderPtr loader1, loader2;
+    network::TestURLLoaderClient client1, client2;
 
-    CreateLoaderAndStart(rfh->GetProcess(), rfh->GetRoutingID(),
-                         kRequestIdNotPreviouslyUsed, request);
-    CreateLoaderAndStart(rfh->GetProcess(), rfh->GetRoutingID(),
-                         kRequestIdNotPreviouslyUsed, request);
+    CreateLoaderAndStart(rfh->GetProcess(), mojo::MakeRequest(&loader1),
+                         rfh->GetRoutingID(), kRequestIdNotPreviouslyUsed,
+                         request, client1.CreateInterfacePtr().PassInterface());
+    CreateLoaderAndStart(rfh->GetProcess(), mojo::MakeRequest(&loader2),
+                         rfh->GetRoutingID(), kRequestIdNotPreviouslyUsed,
+                         request, client2.CreateInterfacePtr().PassInterface());
     EXPECT_EQ(bad_message::RDH_INVALID_REQUEST_ID, kill_waiter.Wait());
   }
 
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 75983185..6d3476f 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -81,7 +81,8 @@
     mojom::EmbeddedWorkerStartParamsPtr,
     std::unique_ptr<ServiceWorkerProcessManager::AllocatedProcessInfo>,
     std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy>,
-    std::unique_ptr<URLLoaderFactoryBundleInfo>)>;
+    std::unique_ptr<URLLoaderFactoryBundleInfo>,
+    blink::mojom::CacheStoragePtrInfo)>;
 
 // Allocates a renderer process for starting a worker and does setup like
 // registering with DevTools. Called on the UI thread. Calls |callback| on the
@@ -106,7 +107,8 @@
         base::BindOnce(std::move(callback),
                        blink::ServiceWorkerStatusCode::kErrorAbort,
                        std::move(params), std::move(process_info),
-                       std::move(devtools_proxy), std::move(factory_bundle)));
+                       std::move(devtools_proxy), std::move(factory_bundle),
+                       nullptr /* cache_storage */));
     return;
   }
 
@@ -120,7 +122,7 @@
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(std::move(callback), status, std::move(params),
                        std::move(process_info), std::move(devtools_proxy),
-                       std::move(factory_bundle)));
+                       std::move(factory_bundle), nullptr /* cache_storage */));
     return;
   }
   const int process_id = process_info->process_id;
@@ -130,6 +132,17 @@
   // rph->IsInitializedAndNotDead().
   CHECK(rph);
 
+  // Create cache storage now as an optimization, so the service worker can use
+  // the Cache Storage API immediately on startup. Don't do this when
+  // byte-to-byte check will be performed on the worker (|pause_after_download|)
+  // as most of those workers will have byte-to-byte equality and abort instead
+  // of running.
+  blink::mojom::CacheStoragePtr cache_storage;
+  if (!params->pause_after_download) {
+    rph->BindCacheStorage(mojo::MakeRequest(&cache_storage),
+                          url::Origin::Create(params->script_url));
+  }
+
   // Bind |request|, which is attached to |EmbeddedWorkerInstance::client_|, to
   // the process. If the process dies, |client_|'s connection error callback
   // will be called on the IO thread.
@@ -209,7 +222,7 @@
       BrowserThread::IO, FROM_HERE,
       base::BindOnce(std::move(callback), status, std::move(params),
                      std::move(process_info), std::move(devtools_proxy),
-                     std::move(factory_bundle)));
+                     std::move(factory_bundle), cache_storage.PassInterface()));
 }
 
 bool HasSentStartWorker(EmbeddedWorkerInstance::StartingPhase phase) {
@@ -407,6 +420,7 @@
              StatusCallback callback) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
     DCHECK(instance_->context_);
+    base::WeakPtr<ServiceWorkerContextCore> context = instance_->context_;
     state_ = ProcessAllocationState::ALLOCATING;
     start_callback_ = std::move(callback);
     is_installed_ = params->is_installed;
@@ -415,12 +429,11 @@
       started_during_browser_startup_ = true;
 
     bool can_use_existing_process =
-        instance_->context_->GetVersionFailureCount(
-            params->service_worker_version_id) < kMaxSameProcessFailureCount;
+        context->GetVersionFailureCount(params->service_worker_version_id) <
+        kMaxSameProcessFailureCount;
     DCHECK_EQ(params->embedded_worker_id, instance_->embedded_worker_id_);
     TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("ServiceWorker", "ALLOCATING_PROCESS",
                                       this);
-    base::WeakPtr<ServiceWorkerContextCore> context = instance_->context_;
     base::WeakPtr<ServiceWorkerProcessManager> process_manager =
         context->process_manager()->AsWeakPtr();
 
@@ -457,7 +470,8 @@
       std::unique_ptr<ServiceWorkerProcessManager::AllocatedProcessInfo>
           process_info,
       std::unique_ptr<EmbeddedWorkerInstance::DevToolsProxy> devtools_proxy,
-      std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle) {
+      std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle,
+      blink::mojom::CacheStoragePtrInfo cache_storage) {
     DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
     std::unique_ptr<WorkerProcessHandle> process_handle;
@@ -513,7 +527,8 @@
     }
 
     instance_->SendStartWorker(std::move(params),
-                               std::move(factory_for_new_scripts));
+                               std::move(factory_for_new_scripts),
+                               std::move(cache_storage));
 
     TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("ServiceWorker",
                                       "INITIALIZING_ON_RENDERER", this);
@@ -558,12 +573,8 @@
 void EmbeddedWorkerInstance::Start(mojom::EmbeddedWorkerStartParamsPtr params,
                                    ProviderInfoGetter provider_info_getter,
                                    StatusCallback callback) {
+  DCHECK(context_);
   restart_count_++;
-  if (!context_) {
-    std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort);
-    // |this| may be destroyed by the callback.
-    return;
-  }
   DCHECK_EQ(EmbeddedWorkerStatus::STOPPED, status_);
 
   DCHECK(!params->pause_after_download || !params->is_installed);
@@ -688,7 +699,8 @@
 
 void EmbeddedWorkerInstance::SendStartWorker(
     mojom::EmbeddedWorkerStartParamsPtr params,
-    scoped_refptr<network::SharedURLLoaderFactory> factory) {
+    scoped_refptr<network::SharedURLLoaderFactory> factory,
+    blink::mojom::CacheStoragePtrInfo cache_storage) {
   DCHECK(context_);
   DCHECK(params->dispatcher_request.is_pending());
   DCHECK(params->controller_request.is_pending());
@@ -704,6 +716,7 @@
   inflight_start_task_->set_start_worker_sent_time(base::TimeTicks::Now());
   params->provider_info =
       std::move(provider_info_getter_).Run(process_id(), std::move(factory));
+  params->provider_info->cache_storage = std::move(cache_storage);
   client_->StartWorker(std::move(params));
   registry_->BindWorkerToProcess(process_id(), embedded_worker_id());
 
@@ -776,7 +789,7 @@
 }
 
 void EmbeddedWorkerInstance::OnThreadStarted(int thread_id) {
-  if (!context_ || !inflight_start_task_)
+  if (!inflight_start_task_)
     return;
 
   starting_phase_ = THREAD_STARTED;
diff --git a/content/browser/service_worker/embedded_worker_instance.h b/content/browser/service_worker/embedded_worker_instance.h
index d8e4697be..fd99f95 100644
--- a/content/browser/service_worker/embedded_worker_instance.h
+++ b/content/browser/service_worker/embedded_worker_instance.h
@@ -31,6 +31,7 @@
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_installed_scripts_manager.mojom.h"
+#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -239,12 +240,16 @@
 
   // Sends the StartWorker message to the renderer.
   //
+  // |cache_storage| is an optional optimization so the service worker can
+  // use the Cache Storage API immediately upon startup.
+  //
   // S13nServiceWorker:
   // |factory| is used for loading non-installed scripts. It can internally be a
   // bundle of factories instead of just the direct network factory to support
   // non-NetworkService schemes like chrome-extension:// URLs.
   void SendStartWorker(mojom::EmbeddedWorkerStartParamsPtr params,
-                       scoped_refptr<network::SharedURLLoaderFactory> factory);
+                       scoped_refptr<network::SharedURLLoaderFactory> factory,
+                       blink::mojom::CacheStoragePtrInfo cache_storage);
 
   // Implements mojom::EmbeddedWorkerInstanceHost.
   // These functions all run on the IO thread.
diff --git a/content/browser/service_worker/embedded_worker_instance_unittest.cc b/content/browser/service_worker/embedded_worker_instance_unittest.cc
index a4a1b058..f5d2cbe 100644
--- a/content/browser/service_worker/embedded_worker_instance_unittest.cc
+++ b/content/browser/service_worker/embedded_worker_instance_unittest.cc
@@ -948,4 +948,99 @@
   EXPECT_EQ(EmbeddedWorkerStatus::STOPPED, worker->status());
 }
 
+// Records whether a CacheStoragePtr was sent as part of StartWorker.
+class RecordCacheStorageHelper : public EmbeddedWorkerTestHelper {
+ public:
+  RecordCacheStorageHelper() : EmbeddedWorkerTestHelper(base::FilePath()) {}
+  ~RecordCacheStorageHelper() override {}
+
+  void OnStartWorker(
+      int embedded_worker_id,
+      int64_t service_worker_version_id,
+      const GURL& scope,
+      const GURL& script_url,
+      bool pause_after_download,
+      mojom::ServiceWorkerEventDispatcherRequest dispatcher_request,
+      mojom::ControllerServiceWorkerRequest controller_request,
+      mojom::EmbeddedWorkerInstanceHostAssociatedPtrInfo instance_host,
+      mojom::ServiceWorkerProviderInfoForStartWorkerPtr provider_info,
+      blink::mojom::ServiceWorkerInstalledScriptsInfoPtr installed_scripts_info)
+      override {
+    had_cache_storage_ = !!provider_info->cache_storage;
+    EmbeddedWorkerTestHelper::OnStartWorker(
+        embedded_worker_id, service_worker_version_id, scope, script_url,
+        pause_after_download, std::move(dispatcher_request),
+        std::move(controller_request), std::move(instance_host),
+        std::move(provider_info), std::move(installed_scripts_info));
+  }
+
+  bool had_cache_storage() const { return had_cache_storage_; }
+
+ private:
+  bool had_cache_storage_ = false;
+};
+
+// Test that the worker is given a CacheStoragePtr during startup, when
+// |pause_after_download| is false.
+TEST_F(EmbeddedWorkerInstanceTest, CacheStorageOptimization) {
+  const GURL scope("http://example.com/");
+  const GURL url("http://example.com/worker.js");
+  auto helper = std::make_unique<RecordCacheStorageHelper>();
+  auto* helper_rawptr = helper.get();
+  helper_ = std::move(helper);
+
+  RegistrationAndVersionPair pair = PrepareRegistrationAndVersion(scope, url);
+  const int64_t version_id = pair.second->version_id();
+  std::unique_ptr<EmbeddedWorkerInstance> worker =
+      embedded_worker_registry()->CreateWorker(pair.second.get());
+
+  // First, test a worker without pause after download.
+  {
+    // Start the worker.
+    blink::ServiceWorkerStatusCode status =
+        blink::ServiceWorkerStatusCode::kMax;
+    base::RunLoop run_loop;
+    mojom::EmbeddedWorkerStartParamsPtr params =
+        CreateStartParams(version_id, scope, url);
+    worker->Start(
+        std::move(params), CreateProviderInfoGetter(),
+        base::BindOnce(&SaveStatusAndCall, &status, run_loop.QuitClosure()));
+    run_loop.Run();
+    EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
+
+    // Cache storage should have been sent.
+    EXPECT_TRUE(helper_rawptr->had_cache_storage());
+
+    // Stop the worker.
+    worker->Stop();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // Second, test a worker with pause after download.
+  {
+    // Start the worker until paused.
+    blink::ServiceWorkerStatusCode status =
+        blink::ServiceWorkerStatusCode::kMax;
+    mojom::EmbeddedWorkerStartParamsPtr params =
+        CreateStartParams(version_id, scope, url);
+    params->pause_after_download = true;
+    worker->Start(
+        std::move(params), CreateProviderInfoGetter(),
+        base::BindOnce(&SaveStatusAndCall, &status, base::DoNothing::Once<>()));
+    base::RunLoop().RunUntilIdle();
+
+    // Finish starting.
+    worker->ResumeAfterDownload();
+    base::RunLoop().RunUntilIdle();
+    EXPECT_EQ(blink::ServiceWorkerStatusCode::kOk, status);
+
+    // Cache storage should not have been sent.
+    EXPECT_FALSE(helper_rawptr->had_cache_storage());
+
+    // Stop the worker.
+    worker->Stop();
+    base::RunLoop().RunUntilIdle();
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 3f2f3ac..f2ada9ea 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -1484,6 +1484,7 @@
 }
 
 void ServiceWorkerVersion::StartWorkerInternal() {
+  DCHECK(context_);
   DCHECK_EQ(EmbeddedWorkerStatus::STOPPED, running_status());
   DCHECK(inflight_requests_.IsEmpty());
   DCHECK(request_timeouts_.empty());
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index 3f781bc..8319876 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -140,6 +140,13 @@
     ]
   }
 
+  if (is_linux && !is_android) {
+    deps += [
+      "//components/services/font:lib",
+      "//components/services/font/public/cpp",
+    ]
+  }
+
   if (is_android) {
     deps += [ "//third_party/android_tools:cpu_features" ]
   }
diff --git a/content/child/DEPS b/content/child/DEPS
index c6e3f2d..e280e35f 100644
--- a/content/child/DEPS
+++ b/content/child/DEPS
@@ -4,6 +4,7 @@
   "+components/tracing",
   "+components/variations/child_process_field_trial_syncer.h",
   "+components/webcrypto",
+  "+components/services/font",
 
   "+content/app/strings/grit",  # For generated headers
   "+content/public/child",
diff --git a/content/child/child_process_sandbox_support_impl_linux.cc b/content/child/child_process_sandbox_support_impl_linux.cc
index 046e064..32dfe1a 100644
--- a/content/child/child_process_sandbox_support_impl_linux.cc
+++ b/content/child/child_process_sandbox_support_impl_linux.cc
@@ -15,6 +15,10 @@
 #include "base/posix/unix_domain_socket.h"
 #include "base/sys_byteorder.h"
 #include "base/trace_event/trace_event.h"
+#include "components/services/font/public/cpp/font_loader.h"
+#include "components/services/font/public/interfaces/constants.mojom.h"
+#include "components/services/font/public/interfaces/font_service.mojom.h"
+#include "content/public/common/common_sandbox_support_linux.h"
 #include "services/service_manager/sandbox/linux/sandbox_linux.h"
 #include "services/service_manager/zygote/common/common_sandbox_support_linux.h"
 #include "third_party/blink/public/platform/linux/web_fallback_font.h"
@@ -24,111 +28,64 @@
 
 namespace content {
 
-void GetFallbackFontForCharacter(int32_t character,
+void GetFallbackFontForCharacter(sk_sp<font_service::FontLoader> font_loader,
+                                 int32_t character,
                                  const char* preferred_locale,
-                                 blink::WebFallbackFont* fallbackFont) {
-  TRACE_EVENT0("sandbox_ipc", "GetFontFamilyForCharacter");
-
-  base::Pickle request;
-  request.WriteInt(
-      service_manager::SandboxLinux::METHOD_GET_FALLBACK_FONT_FOR_CHAR);
-  request.WriteInt(character);
-  request.WriteString(preferred_locale);
-
-  uint8_t buf[512];
-  const ssize_t n = base::UnixDomainSocket::SendRecvMsg(
-      service_manager::GetSandboxFD(), buf, sizeof(buf), nullptr, request);
-
+                                 blink::WebFallbackFont* fallback_font) {
+  DCHECK(font_loader.get());
+  font_service::mojom::FontIdentityPtr font_identity;
+  bool is_bold = false;
+  bool is_italic = false;
   std::string family_name;
-  std::string filename;
-  int fontconfigInterfaceId = 0;
-  int ttcIndex = 0;
-  bool isBold = false;
-  bool isItalic = false;
-  if (n != -1) {
-    base::Pickle reply(reinterpret_cast<char*>(buf), n);
-    base::PickleIterator pickle_iter(reply);
-    if (pickle_iter.ReadString(&family_name) &&
-        pickle_iter.ReadString(&filename) &&
-        pickle_iter.ReadInt(&fontconfigInterfaceId) &&
-        pickle_iter.ReadInt(&ttcIndex) && pickle_iter.ReadBool(&isBold) &&
-        pickle_iter.ReadBool(&isItalic)) {
-      fallbackFont->name = blink::WebString::FromUTF8(family_name);
-      fallbackFont->filename = blink::WebVector<char>(filename);
-      fallbackFont->fontconfig_interface_id = fontconfigInterfaceId;
-      fallbackFont->ttc_index = ttcIndex;
-      fallbackFont->is_bold = isBold;
-      fallbackFont->is_italic = isItalic;
-    }
+  if (!font_loader->FallbackFontForCharacter(character, preferred_locale,
+                                             &font_identity, &family_name,
+                                             &is_bold, &is_italic)) {
+    LOG(ERROR) << "FontService fallback request does not receive a response.";
+    return;
   }
+
+  // TODO(drott): Perhaps take WebFallbackFont out of the picture here and pass
+  // mojo FontIdentityPtr directly?
+  fallback_font->name =
+      blink::WebString::FromUTF8(family_name.c_str(), family_name.length());
+  fallback_font->fontconfig_interface_id = font_identity->id;
+  fallback_font->filename.Assign(font_identity->str_representation.c_str(),
+                                 font_identity->str_representation.length());
+  fallback_font->ttc_index = font_identity->ttc_index;
+  fallback_font->is_bold = is_bold;
+  fallback_font->is_italic = is_italic;
+  return;
 }
 
-void GetRenderStyleForStrike(const char* family,
+void GetRenderStyleForStrike(sk_sp<font_service::FontLoader> font_loader,
+                             const char* family,
                              int size,
                              bool is_bold,
                              bool is_italic,
                              float device_scale_factor,
                              blink::WebFontRenderStyle* out) {
-  TRACE_EVENT0("sandbox_ipc", "GetRenderStyleForStrike");
+  DCHECK(font_loader.get());
+  font_service::mojom::FontIdentityPtr font_identity;
 
   *out = blink::WebFontRenderStyle();
 
   if (size < 0 || size > std::numeric_limits<uint16_t>::max())
     return;
 
-  base::Pickle request;
-  request.WriteInt(service_manager::SandboxLinux::METHOD_GET_STYLE_FOR_STRIKE);
-  request.WriteString(family);
-  request.WriteBool(is_bold);
-  request.WriteBool(is_italic);
-  request.WriteUInt16(size);
-  request.WriteFloat(device_scale_factor);
+  font_service::mojom::FontRenderStylePtr font_render_style;
+  font_loader->FontRenderStyleForStrike(family, size, is_bold, is_italic,
+                                        device_scale_factor,
+                                        &font_render_style);
 
-  uint8_t buf[512];
-  const ssize_t n = base::UnixDomainSocket::SendRecvMsg(
-      service_manager::GetSandboxFD(), buf, sizeof(buf), nullptr, request);
-  if (n == -1)
-    return;
-
-  base::Pickle reply(reinterpret_cast<char*>(buf), n);
-  base::PickleIterator pickle_iter(reply);
-  int use_bitmaps, use_autohint, use_hinting, hint_style, use_antialias;
-  int use_subpixel_rendering, use_subpixel_positioning;
-  if (pickle_iter.ReadInt(&use_bitmaps) && pickle_iter.ReadInt(&use_autohint) &&
-      pickle_iter.ReadInt(&use_hinting) && pickle_iter.ReadInt(&hint_style) &&
-      pickle_iter.ReadInt(&use_antialias) &&
-      pickle_iter.ReadInt(&use_subpixel_rendering) &&
-      pickle_iter.ReadInt(&use_subpixel_positioning)) {
-    out->use_bitmaps = use_bitmaps;
-    out->use_auto_hint = use_autohint;
-    out->use_hinting = use_hinting;
-    out->hint_style = hint_style;
-    out->use_anti_alias = use_antialias;
-    out->use_subpixel_rendering = use_subpixel_rendering;
-    out->use_subpixel_positioning = use_subpixel_positioning;
-  }
-}
-
-int MatchFontWithFallback(const std::string& face,
-                          bool bold,
-                          bool italic,
-                          int charset,
-                          PP_BrowserFont_Trusted_Family fallback_family) {
-  TRACE_EVENT0("sandbox_ipc", "MatchFontWithFallback");
-
-  base::Pickle request;
-  request.WriteInt(service_manager::SandboxLinux::METHOD_MATCH_WITH_FALLBACK);
-  request.WriteString(face);
-  request.WriteBool(bold);
-  request.WriteBool(italic);
-  request.WriteUInt32(charset);
-  request.WriteUInt32(fallback_family);
-  uint8_t reply_buf[64];
-  int fd = -1;
-  base::UnixDomainSocket::SendRecvMsg(service_manager::GetSandboxFD(),
-                                      reply_buf, sizeof(reply_buf), &fd,
-                                      request);
-  return fd;
+  out->use_bitmaps = static_cast<char>(font_render_style->use_bitmaps);
+  out->use_auto_hint = static_cast<char>(font_render_style->use_autohint);
+  out->use_hinting = static_cast<char>(font_render_style->use_hinting);
+  out->hint_style = font_render_style->hint_style;
+  out->use_anti_alias = static_cast<char>(font_render_style->use_antialias);
+  out->use_subpixel_rendering =
+      static_cast<char>(font_render_style->use_subpixel_rendering);
+  out->use_subpixel_positioning =
+      static_cast<char>(font_render_style->use_subpixel_positioning);
 }
 
 }  // namespace content
diff --git a/content/child/child_process_sandbox_support_impl_linux.h b/content/child/child_process_sandbox_support_impl_linux.h
index 293c527..140060c 100644
--- a/content/child/child_process_sandbox_support_impl_linux.h
+++ b/content/child/child_process_sandbox_support_impl_linux.h
@@ -7,7 +7,8 @@
 
 #include <stdint.h>
 
-#include "content/public/child/child_process_sandbox_support_linux.h"
+#include "components/services/font/public/cpp/font_loader.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
 
 namespace blink {
 struct WebFallbackFont;
@@ -20,7 +21,8 @@
 // specified by |character|, a UTF-32 character. |preferred_locale| contains the
 // preferred locale identifier for |character|. The instance has an empty font
 // name if the request could not be satisfied.
-void GetFallbackFontForCharacter(const int32_t character,
+void GetFallbackFontForCharacter(sk_sp<font_service::FontLoader> font_loader,
+                                 const int32_t character,
                                  const char* preferred_locale,
                                  blink::WebFallbackFont* family);
 
@@ -28,7 +30,8 @@
 // |size_and_style| stores the bold setting in its least-significant bit, the
 // italic setting in its second-least-significant bit, and holds the requested
 // size in pixels into its remaining bits.
-void GetRenderStyleForStrike(const char* family,
+void GetRenderStyleForStrike(sk_sp<font_service::FontLoader> font_loader,
+                             const char* family,
                              int size,
                              bool is_bold,
                              bool is_italic,
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index bdda69a..4c3fa75e1 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -116,8 +116,6 @@
     "fileapi/file_system_messages.h",
     "fileapi/webblob_messages.h",
     "font_cache_dispatcher_win.cc",
-    "font_config_ipc_linux.cc",
-    "font_config_ipc_linux.h",
     "font_list.cc",
     "font_list.h",
     "font_list_android.cc",
diff --git a/content/common/common_sandbox_support_linux.cc b/content/common/common_sandbox_support_linux.cc
index 1c05b650..507c3558 100644
--- a/content/common/common_sandbox_support_linux.cc
+++ b/content/common/common_sandbox_support_linux.cc
@@ -15,6 +15,9 @@
 
 namespace content {
 
+// TODO(drott): This should be removed once we don't need to support PPAPI
+// TrueType functionality anymore, and before that, it should be replaced with
+// using FreeType for the purpose instead of reimplementing table parsing.
 bool GetFontTable(int fd,
                   uint32_t table_tag,
                   off_t offset,
diff --git a/content/common/font_config_ipc_linux.cc b/content/common/font_config_ipc_linux.cc
deleted file mode 100644
index 2596c992..0000000
--- a/content/common/font_config_ipc_linux.cc
+++ /dev/null
@@ -1,179 +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/common/font_config_ipc_linux.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <functional>
-#include <memory>
-#include <utility>
-
-#include "base/files/file_util.h"
-#include "base/files/memory_mapped_file.h"
-#include "base/memory/ref_counted.h"
-#include "base/pickle.h"
-#include "base/posix/unix_domain_socket.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/trace_event/trace_event.h"
-#include "skia/ext/skia_utils_base.h"
-#include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-#include "third_party/skia/include/core/SkStream.h"
-#include "third_party/skia/include/core/SkTypeface.h"
-
-namespace content {
-
-std::size_t SkFontConfigInterfaceFontIdentityHash::operator()(
-    const SkFontConfigInterface::FontIdentity& sp) const {
-  std::hash<std::string> stringhash;
-  std::hash<int> inthash;
-  size_t r = inthash(sp.fID);
-  r = r * 41 + inthash(sp.fTTCIndex);
-  r = r * 41 + stringhash(sp.fString.c_str());
-  r = r * 41 + inthash(sp.fStyle.weight());
-  r = r * 41 + inthash(sp.fStyle.slant());
-  r = r * 41 + inthash(sp.fStyle.width());
-  return r;
-}
-
-// Wikpedia's main country selection page activates 21 fallback fonts,
-// doubling this we should be on the generous side as an upper bound,
-// but nevertheless not have the mapped typefaces cache grow excessively.
-const size_t kMaxMappedTypefaces = 42;
-
-void CloseFD(int fd) {
-  int err = IGNORE_EINTR(close(fd));
-  DCHECK(!err);
-}
-
-FontConfigIPC::FontConfigIPC(int fd)
-    : fd_(fd)
-    , mapped_typefaces_(kMaxMappedTypefaces) {
-}
-
-FontConfigIPC::~FontConfigIPC() {
-  CloseFD(fd_);
-}
-
-bool FontConfigIPC::matchFamilyName(const char familyName[],
-                                    SkFontStyle requestedStyle,
-                                    FontIdentity* outFontIdentity,
-                                    SkString* outFamilyName,
-                                    SkFontStyle* outStyle) {
-  TRACE_EVENT0("sandbox_ipc", "FontConfigIPC::matchFamilyName");
-  size_t familyNameLen = familyName ? strlen(familyName) : 0;
-  if (familyNameLen > kMaxFontFamilyLength)
-    return false;
-
-  base::Pickle request;
-  request.WriteInt(METHOD_MATCH);
-  request.WriteData(familyName, familyNameLen);
-  skia::WriteSkFontStyle(&request, requestedStyle);
-
-  uint8_t reply_buf[2048];
-  const ssize_t r = base::UnixDomainSocket::SendRecvMsg(
-      fd_, reply_buf, sizeof(reply_buf), nullptr, request);
-  if (r == -1)
-    return false;
-
-  base::Pickle reply(reinterpret_cast<char*>(reply_buf), r);
-  base::PickleIterator iter(reply);
-  bool result;
-  if (!iter.ReadBool(&result))
-    return false;
-  if (!result)
-    return false;
-
-  SkString     reply_family;
-  FontIdentity reply_identity;
-  SkFontStyle  reply_style;
-  if (!skia::ReadSkString(&iter, &reply_family) ||
-      !skia::ReadSkFontIdentity(&iter, &reply_identity) ||
-      !skia::ReadSkFontStyle(&iter, &reply_style)) {
-    return false;
-  }
-
-  if (outFontIdentity)
-    *outFontIdentity = reply_identity;
-  if (outFamilyName)
-    *outFamilyName = reply_family;
-  if (outStyle)
-    *outStyle = reply_style;
-
-  return true;
-}
-
-static void DestroyMemoryMappedFile(const void*, void* context) {
-  base::ThreadRestrictions::ScopedAllowIO allow_munmap;
-  delete static_cast<base::MemoryMappedFile*>(context);
-}
-
-SkMemoryStream* FontConfigIPC::mapFileDescriptorToStream(int fd) {
-  std::unique_ptr<base::MemoryMappedFile> mapped_font_file(
-      new base::MemoryMappedFile);
-  base::ThreadRestrictions::ScopedAllowIO allow_mmap;
-  mapped_font_file->Initialize(base::File(fd));
-  DCHECK(mapped_font_file->IsValid());
-
-  sk_sp<SkData> data =
-      SkData::MakeWithProc(mapped_font_file->data(), mapped_font_file->length(),
-                           &DestroyMemoryMappedFile, mapped_font_file.get());
-  if (!data)
-    return nullptr;
-  ignore_result(mapped_font_file.release()); // Ownership transferred to SkDataB
-  return new SkMemoryStream(std::move(data));
-}
-
-SkStreamAsset* FontConfigIPC::openStream(const FontIdentity& identity) {
-  TRACE_EVENT0("sandbox_ipc", "FontConfigIPC::openStream");
-
-  base::Pickle request;
-  request.WriteInt(METHOD_OPEN);
-  request.WriteUInt32(identity.fID);
-
-  int result_fd = -1;
-  uint8_t reply_buf[256];
-  const ssize_t r = base::UnixDomainSocket::SendRecvMsg(
-      fd_, reply_buf, sizeof(reply_buf), &result_fd, request);
-  if (r == -1)
-    return nullptr;
-
-  base::Pickle reply(reinterpret_cast<char*>(reply_buf), r);
-  bool result;
-  base::PickleIterator iter(reply);
-  if (!iter.ReadBool(&result) || !result) {
-    if (result_fd)
-      CloseFD(result_fd);
-    return nullptr;
-  }
-
-  return mapFileDescriptorToStream(result_fd);
-}
-
-sk_sp<SkTypeface> FontConfigIPC::makeTypeface(
-    const SkFontConfigInterface::FontIdentity& identity) {
-  base::AutoLock lock(lock_);
-  auto mapped_typefaces_it = mapped_typefaces_.Get(identity);
-  if (mapped_typefaces_it != mapped_typefaces_.end())
-    return mapped_typefaces_it->second;
-
-  SkStreamAsset* typeface_stream = openStream(identity);
-  if (!typeface_stream)
-    return nullptr;
-  sk_sp<SkTypeface> typeface_from_stream(
-      SkTypeface::MakeFromStream(typeface_stream, identity.fTTCIndex));
-  auto mapped_typefaces_insert_it =
-      mapped_typefaces_.Put(identity, std::move(typeface_from_stream));
-  return mapped_typefaces_insert_it->second;
-}
-
-}  // namespace content
diff --git a/content/common/font_config_ipc_linux.h b/content/common/font_config_ipc_linux.h
deleted file mode 100644
index 0fc85ec5..0000000
--- a/content/common/font_config_ipc_linux.h
+++ /dev/null
@@ -1,81 +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_COMMON_FONT_CONFIG_IPC_LINUX_H_
-#define CONTENT_COMMON_FONT_CONFIG_IPC_LINUX_H_
-
-#include "base/compiler_specific.h"
-#include "base/containers/mru_cache.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-#include "third_party/skia/include/core/SkStream.h"
-#include "third_party/skia/include/core/SkTypeface.h"
-#include "third_party/skia/include/ports/SkFontConfigInterface.h"
-
-#include <stddef.h>
-
-#include <string>
-
-class SkString;
-
-namespace content {
-
-struct SkFontConfigInterfaceFontIdentityHash {
-  std::size_t operator()(const SkFontConfigInterface::FontIdentity& sp) const;
-};
-
-// FontConfig implementation for Skia that proxies out of process to get out
-// of the sandbox. See https://chromium.googlesource.com/chromium/src/+/master/docs/linux_sandbox_ipc.md
-class FontConfigIPC : public SkFontConfigInterface {
- public:
-  explicit FontConfigIPC(int fd);
-  ~FontConfigIPC() override;
-
-  bool matchFamilyName(const char familyName[],
-                       SkFontStyle requested,
-                       FontIdentity* outFontIdentifier,
-                       SkString* outFamilyName,
-                       SkFontStyle* outStyle) override;
-
-  sk_sp<SkTypeface> makeTypeface(const FontIdentity& identity) override
-      WARN_UNUSED_RESULT;
-
-  enum Method {
-    METHOD_MATCH = 0,
-    METHOD_OPEN = 1,
-  };
-
-  enum {
-    kMaxFontFamilyLength = 2048
-  };
-
- private:
-  // Marking this private in Blink's implementation of SkFontConfigInterface
-  // since our caching implementation's efficacy is impaired if both
-  // createTypeface and openStream are used in parallel.
-  SkStreamAsset* openStream(const FontIdentity&) override;
-
-  SkMemoryStream* mapFileDescriptorToStream(int fd);
-
-  const int fd_;
-  // Lock preventing multiple threads from creating a typeface and removing
-  // an element from |mapped_typefaces_| map at the same time.
-  base::Lock lock_;
-  // Practically, this hash_map definition means that we re-map the same font
-  // file multiple times if we receive createTypeface requests for multiple
-  // ttc-indices or styles but the same fontconfig interface id. Since the usage
-  // frequency of ttc indices is very low, and style is not used by clients of
-  // this API, this seems okay.
-  base::HashingMRUCache<FontIdentity,
-                        sk_sp<SkTypeface>,
-                        SkFontConfigInterfaceFontIdentityHash>
-      mapped_typefaces_;
-
-  DISALLOW_COPY_AND_ASSIGN(FontConfigIPC);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_FONT_CONFIG_IPC_LINUX_H_
diff --git a/content/common/service_worker/service_worker_provider.mojom b/content/common/service_worker/service_worker_provider.mojom
index ee663f7..c5d10570 100644
--- a/content/common/service_worker/service_worker_provider.mojom
+++ b/content/common/service_worker/service_worker_provider.mojom
@@ -10,6 +10,7 @@
 import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_provider_type.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom";
+import "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom";
 
 // The name of the InterfaceProviderSpec in service manifests used by the
 // frame tree to expose service-worker-specific interfaces between renderer
@@ -40,6 +41,13 @@
   // importScripts().
   associated network.mojom.URLLoaderFactory? script_loader_factory_ptr_info;
 
+  // |cache_storage| is an optional optimization so the service worker can use
+  // the Cache Storage API immediately without using InterfaceProvider. May be
+  // null for service workers created for update checks, as the optimization
+  // would be wasteful because these workers usually are aborted after the
+  // byte-to-byte update check before running.
+  blink.mojom.CacheStorage? cache_storage;
+
   service_manager.mojom.InterfaceProvider interface_provider;
 };
 
diff --git a/content/ppapi_plugin/BUILD.gn b/content/ppapi_plugin/BUILD.gn
index b34b076..f356fcf 100644
--- a/content/ppapi_plugin/BUILD.gn
+++ b/content/ppapi_plugin/BUILD.gn
@@ -51,6 +51,7 @@
   deps = [
     "//base",
     "//components/discardable_memory/client",
+    "//components/services/font/public/cpp:cpp",
     "//content:export",
     "//content/child",
     "//content/public/child:child_sources",
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.cc b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
index 9e0474e..6813855 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.cc
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
@@ -40,11 +40,15 @@
 
 class PpapiBlinkPlatformImpl::SandboxSupport : public WebSandboxSupport {
  public:
+#if defined(OS_LINUX)
+  explicit SandboxSupport(sk_sp<font_service::FontLoader> font_loader)
+      : font_loader_(std::move(font_loader)) {}
+#endif
   ~SandboxSupport() override {}
 
 #if defined(OS_MACOSX)
   bool LoadFont(CTFontRef srcFont, CGFontRef* out, uint32_t* fontID) override;
-#elif defined(OS_POSIX)
+#elif defined(OS_LINUX)
   SandboxSupport();
   void GetFallbackFontForCharacter(
       WebUChar32 character,
@@ -64,6 +68,7 @@
   std::map<int32_t, blink::WebFallbackFont> unicode_font_families_;
   // For debugging crbug.com/312965
   base::PlatformThreadId creation_thread_;
+  sk_sp<font_service::FontLoader> font_loader_;
 #endif
 };
 
@@ -105,8 +110,8 @@
     return;
   }
 
-  content::GetFallbackFontForCharacter(character, preferred_locale,
-                                       fallbackFont);
+  content::GetFallbackFontForCharacter(font_loader_, character,
+                                       preferred_locale, fallbackFont);
   unicode_font_families_.insert(std::make_pair(character, *fallbackFont));
 }
 
@@ -117,8 +122,8 @@
     bool is_italic,
     float device_scale_factor,
     blink::WebFontRenderStyle* out) {
-  GetRenderStyleForStrike(family, size, is_bold, is_italic, device_scale_factor,
-                          out);
+  GetRenderStyleForStrike(font_loader_, family, size, is_bold, is_italic,
+                          device_scale_factor, out);
 }
 
 #endif
@@ -126,8 +131,14 @@
 #endif  // !defined(OS_ANDROID) && !defined(OS_WIN)
 
 PpapiBlinkPlatformImpl::PpapiBlinkPlatformImpl() {
-#if !defined(OS_ANDROID) && !defined(OS_WIN)
-  sandbox_support_.reset(new PpapiBlinkPlatformImpl::SandboxSupport);
+#if defined(OS_LINUX) && !defined(OS_ANDROID)
+  font_loader_ =
+      sk_make_sp<font_service::FontLoader>(ChildThread::Get()->GetConnector());
+  SkFontConfigInterface::SetGlobal(font_loader_);
+  sandbox_support_.reset(
+      new PpapiBlinkPlatformImpl::SandboxSupport(font_loader_));
+#elif defined(OS_MACOSX)
+  sandbox_support_.reset(new PpapiBlinkPlatformImpl::SandboxSupport());
 #endif
 }
 
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.h b/content/ppapi_plugin/ppapi_blink_platform_impl.h
index d38cfcf..aea9579 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.h
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.h
@@ -13,6 +13,11 @@
 #include "build/build_config.h"
 #include "content/child/blink_platform_impl.h"
 
+#if defined(OS_LINUX)
+#include "components/services/font/public/cpp/font_loader.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+#endif
+
 namespace content {
 
 class PpapiBlinkPlatformImpl : public BlinkPlatformImpl {
@@ -53,6 +58,10 @@
   std::unique_ptr<SandboxSupport> sandbox_support_;
 #endif
 
+#if defined(OS_LINUX)
+  sk_sp<font_service::FontLoader> font_loader_;
+#endif
+
   DISALLOW_COPY_AND_ASSIGN(PpapiBlinkPlatformImpl);
 };
 
diff --git a/content/public/app/BUILD.gn b/content/public/app/BUILD.gn
index e5518f5..28d5f8d 100644
--- a/content/public/app/BUILD.gn
+++ b/content/public/app/BUILD.gn
@@ -197,6 +197,10 @@
     "//services/video_capture:manifest",
     "//services/viz:manifest",
   ]
+
+  if (is_linux && !is_android) {
+    packaged_services += [ "//components/services/font:manifest" ]
+  }
 }
 
 service_manifest("browser_manifest") {
diff --git a/content/public/app/mojo/content_plugin_manifest.json b/content/public/app/mojo/content_plugin_manifest.json
index 44c6d2ba..c00ea402 100644
--- a/content/public/app/mojo/content_plugin_manifest.json
+++ b/content/public/app/mojo/content_plugin_manifest.json
@@ -25,6 +25,7 @@
           "plugin"
         ],
         "device": [ "device:power_monitor" ],
+        "font_service": [ "font_service" ],
         "ui": [ "discardable_memory" ]
       }
     }
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json
index 71bc81d..70c67820 100644
--- a/content/public/app/mojo/content_renderer_manifest.json
+++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -33,6 +33,7 @@
           "font_loader",
           "renderer"
         ],
+        "font_service": [ "font_service" ],
         "metrics": [ "url_keyed_metrics" ],
         "device": [
           "device:power_monitor",
diff --git a/content/public/app/mojo/content_utility_manifest.json b/content/public/app/mojo/content_utility_manifest.json
index 563c885..2c4dcb1 100644
--- a/content/public/app/mojo/content_utility_manifest.json
+++ b/content/public/app/mojo/content_utility_manifest.json
@@ -29,7 +29,8 @@
         "device": [
           "device:power_monitor",
           "device:time_zone_monitor"
-        ]
+        ],
+        "font_service": [ "font_service" ]
       }
     }
   },
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index a39bf379..19d9c106 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -23,6 +23,7 @@
 #include "ipc/ipc_sender.h"
 #include "media/media_buildflags.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h"
 #include "ui/gfx/native_widget_types.h"
 
 #if defined(OS_ANDROID)
@@ -435,6 +436,12 @@
   // https://crbug.com/846155.
   virtual void LockToOrigin(const GURL& lock_url) = 0;
 
+  // Binds |request| to the CacheStorageDispatcherHost instance. The binding is
+  // sent to the IO thread. This is for internal use only, and is only exposed
+  // here to support MockRenderProcessHost usage in tests.
+  virtual void BindCacheStorage(blink::mojom::CacheStorageRequest request,
+                                const url::Origin& origin) = 0;
+
   // Returns the current number of active views in this process.  Excludes
   // any RenderViewHosts that are swapped out.
   size_t GetActiveViewCount();
diff --git a/content/public/child/BUILD.gn b/content/public/child/BUILD.gn
index 296eca9..c7f6f6a 100644
--- a/content/public/child/BUILD.gn
+++ b/content/public/child/BUILD.gn
@@ -29,7 +29,6 @@
   visibility = [ "//content/*" ]
 
   sources = [
-    "child_process_sandbox_support_linux.h",
     "child_thread.h",
     "dwrite_font_proxy_init_win.h",
     "image_decoder_utils.h",
diff --git a/content/public/child/child_process_sandbox_support_linux.h b/content/public/child/child_process_sandbox_support_linux.h
deleted file mode 100644
index 5f0577c..0000000
--- a/content/public/child/child_process_sandbox_support_linux.h
+++ /dev/null
@@ -1,33 +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 CONTENT_PUBLIC_CHILD_CHILD_PROCESS_SANDBOX_SUPPORT_LINUX_H_
-#define CONTENT_PUBLIC_CHILD_CHILD_PROCESS_SANDBOX_SUPPORT_LINUX_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <string>
-
-#include "content/common/content_export.h"
-#include "ppapi/c/trusted/ppb_browser_font_trusted.h"
-
-namespace content {
-
-// Return a read-only file descriptor to the font which best matches the given
-// properties or -1 on failure.
-//   charset: specifies the language(s) that the font must cover. See
-// render_sandbox_host_linux.cc for more information.
-// fallback_family: If not set to PP_BROWSERFONT_TRUSTED_FAMILY_DEFAULT, font
-// selection should fall back to generic Windows font names like Arial and
-// Times New Roman.
-CONTENT_EXPORT int MatchFontWithFallback(
-    const std::string& face,
-    bool bold,
-    bool italic,
-    int charset,
-    PP_BrowserFont_Trusted_Family fallback_family);
-
-};  // namespace content
-
-#endif  // CONTENT_PUBLIC_CHILD_CHILD_PROCESS_SANDBOX_SUPPORT_LINUX_H_
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index 434ec69..95d09af 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -424,6 +424,12 @@
     is_renderer_locked_to_site_ = true;
 }
 
+void MockRenderProcessHost::BindCacheStorage(
+    blink::mojom::CacheStorageRequest request,
+    const url::Origin& origin) {
+  cache_storage_request_ = std::move(request);
+}
+
 void MockRenderProcessHost::FilterURL(bool empty_allowed, GURL* url) {
   RenderProcessHostImpl::FilterURL(this, empty_allowed, url);
 }
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 1088de8..acfb2cc 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -144,6 +144,8 @@
 
   bool HostHasNotBeenUsed() override;
   void LockToOrigin(const GURL& lock_url) override;
+  void BindCacheStorage(blink::mojom::CacheStorageRequest request,
+                        const url::Origin& origin) override;
 
   // IPC::Sender via RenderProcessHost.
   bool Send(IPC::Message* msg) override;
@@ -212,6 +214,7 @@
   service_manager::Identity child_identity_;
   bool is_renderer_locked_to_site_ = false;
   network::mojom::URLLoaderFactory* url_loader_factory_;
+  blink::mojom::CacheStorageRequest cache_storage_request_;
   base::WeakPtrFactory<MockRenderProcessHost> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MockRenderProcessHost);
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 43e3f295..aaa4a9c 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -1018,6 +1018,16 @@
     deps += [ "//sandbox:sandbox_buildflags" ]
   }
 
+  if (is_linux && !is_android) {
+    deps += [
+      "//components/services/font:lib",
+      "//components/services/font/public/cpp",
+    ]
+    data_deps = [
+      "//components/services/font:font_service",
+    ]
+  }
+
   if (use_ozone) {
     deps += [ "//ui/ozone" ]
   }
diff --git a/content/renderer/media/webrtc/media_stream_track_metrics.cc b/content/renderer/media/webrtc/media_stream_track_metrics.cc
index e84c5e83b..30ea304 100644
--- a/content/renderer/media/webrtc/media_stream_track_metrics.cc
+++ b/content/renderer/media/webrtc/media_stream_track_metrics.cc
@@ -5,7 +5,6 @@
 #include "content/renderer/media/webrtc/media_stream_track_metrics.h"
 
 #include <inttypes.h>
-#include <set>
 #include <string>
 
 #include "base/md5.h"
@@ -14,133 +13,44 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/renderer/render_thread_impl.h"
 #include "services/service_manager/public/cpp/connector.h"
-#include "third_party/webrtc/api/mediastreaminterface.h"
-
-using webrtc::AudioTrackVector;
-using webrtc::MediaStreamInterface;
-using webrtc::MediaStreamTrackInterface;
-using webrtc::PeerConnectionInterface;
-using webrtc::VideoTrackVector;
 
 namespace content {
-namespace {
-typedef std::set<std::string> IdSet;
-
-template <class T>
-IdSet GetTrackIds(const std::vector<rtc::scoped_refptr<T>>& tracks) {
-  IdSet track_ids;
-  for (const auto& track : tracks)
-    track_ids.insert(track->id());
-  return track_ids;
-}
-
-// TODO(tommi): Consolidate this and TrackObserver since these implementations
-// are fundamentally achieving the same thing (aside from specific logic inside
-// the OnChanged callbacks).
-class MediaStreamObserver
-    : public base::RefCountedThreadSafe<MediaStreamObserver>,
-      public webrtc::ObserverInterface {
- public:
-  typedef base::Callback<
-      void(const IdSet& audio_track_ids, const IdSet& video_track_ids)>
-          OnChangedCallback;
-
-  MediaStreamObserver(
-      const OnChangedCallback& callback,
-      const scoped_refptr<base::SingleThreadTaskRunner>& main_thread,
-      webrtc::MediaStreamInterface* stream)
-      : main_thread_(main_thread), stream_(stream), callback_(callback) {
-    signaling_thread_.DetachFromThread();
-    stream_->RegisterObserver(this);
-  }
-
-  const scoped_refptr<webrtc::MediaStreamInterface>& stream() const {
-    DCHECK(main_thread_->BelongsToCurrentThread());
-    return stream_;
-  }
-
-  void Unregister() {
-    DCHECK(main_thread_->BelongsToCurrentThread());
-    callback_.Reset();
-    stream_->UnregisterObserver(this);
-    stream_ = nullptr;
-  }
-
- private:
-  friend class base::RefCountedThreadSafe<MediaStreamObserver>;
-  ~MediaStreamObserver() override {
-    DCHECK(!stream_.get()) << "must have been unregistered before deleting";
-  }
-
-  // webrtc::ObserverInterface implementation.
-  void OnChanged() override {
-    DCHECK(signaling_thread_.CalledOnValidThread());
-    main_thread_->PostTask(
-        FROM_HERE, base::BindOnce(&MediaStreamObserver::OnChangedOnMainThread,
-                                  this, GetTrackIds(stream_->GetAudioTracks()),
-                                  GetTrackIds(stream_->GetVideoTracks())));
-  }
-
-  void OnChangedOnMainThread(const IdSet& audio_track_ids,
-                             const IdSet& video_track_ids) {
-    DCHECK(main_thread_->BelongsToCurrentThread());
-    if (!callback_.is_null())
-      callback_.Run(audio_track_ids, video_track_ids);
-  }
-
-  const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
-  scoped_refptr<webrtc::MediaStreamInterface> stream_;
-  OnChangedCallback callback_;  // Only touched on the main thread.
-  base::ThreadChecker signaling_thread_;
-};
-
-}  // namespace
 
 class MediaStreamTrackMetricsObserver {
  public:
-  MediaStreamTrackMetricsObserver(
-      MediaStreamTrackMetrics::StreamType stream_type,
-      MediaStreamInterface* stream,
-      MediaStreamTrackMetrics* owner);
+  MediaStreamTrackMetricsObserver(MediaStreamTrackMetrics::Direction direction,
+                                  MediaStreamTrackMetrics::Kind kind,
+                                  std::string track_id,
+                                  MediaStreamTrackMetrics* owner);
   ~MediaStreamTrackMetricsObserver();
 
-  // Sends begin/end messages for all tracks currently tracked.
-  void SendLifetimeMessages(MediaStreamTrackMetrics::LifetimeEvent event);
+  // Sends begin/end messages for the track if not already reported.
+  void SendLifetimeMessageForTrack(
+      MediaStreamTrackMetrics::LifetimeEvent event);
 
-  MediaStreamInterface* stream() {
+  MediaStreamTrackMetrics::Direction direction() {
     DCHECK(thread_checker_.CalledOnValidThread());
-    return observer_->stream().get();
+    return direction_;
   }
 
-  MediaStreamTrackMetrics::StreamType stream_type() {
+  MediaStreamTrackMetrics::Kind kind() {
     DCHECK(thread_checker_.CalledOnValidThread());
-    return stream_type_;
+    return kind_;
+  }
+
+  std::string track_id() const {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    return track_id_;
   }
 
  private:
-  void OnChanged(const IdSet& audio_track_ids, const IdSet& video_track_ids);
-
-  void ReportAddedAndRemovedTracks(
-      const IdSet& new_ids,
-      const IdSet& old_ids,
-      MediaStreamTrackMetrics::TrackType track_type);
-
-  // Sends a lifetime message for the given tracks. OK to call with an
-  // empty |ids|, in which case the method has no side effects.
-  void ReportTracks(const IdSet& ids,
-                    MediaStreamTrackMetrics::TrackType track_type,
-                    MediaStreamTrackMetrics::LifetimeEvent event);
-
   // False until start/end of lifetime messages have been sent.
   bool has_reported_start_;
   bool has_reported_end_;
 
-  // IDs of audio and video tracks in the stream being observed.
-  IdSet audio_track_ids_;
-  IdSet video_track_ids_;
-
-  MediaStreamTrackMetrics::StreamType stream_type_;
-  scoped_refptr<MediaStreamObserver> observer_;
+  MediaStreamTrackMetrics::Direction direction_;
+  MediaStreamTrackMetrics::Kind kind_;
+  std::string track_id_;
 
   // Non-owning.
   MediaStreamTrackMetrics* owner_;
@@ -151,47 +61,46 @@
 
 // Used with std::find_if.
 struct ObserverFinder {
-  ObserverFinder(MediaStreamTrackMetrics::StreamType stream_type,
-                 MediaStreamInterface* stream)
-      : stream_type(stream_type), stream_(stream) {}
+  ObserverFinder(MediaStreamTrackMetrics::Direction direction,
+                 MediaStreamTrackMetrics::Kind kind,
+                 const std::string& track_id)
+      : direction_(direction), kind_(kind), track_id_(track_id) {}
   bool operator()(
       const std::unique_ptr<MediaStreamTrackMetricsObserver>& observer) {
-    return stream_ == observer->stream() &&
-           stream_type == observer->stream_type();
+    return direction_ == observer->direction() && kind_ == observer->kind() &&
+           track_id_ == observer->track_id();
   }
-  MediaStreamTrackMetrics::StreamType stream_type;
-  MediaStreamInterface* stream_;
+  MediaStreamTrackMetrics::Direction direction_;
+  MediaStreamTrackMetrics::Kind kind_;
+  std::string track_id_;
 };
 
 }  // namespace
 
 MediaStreamTrackMetricsObserver::MediaStreamTrackMetricsObserver(
-    MediaStreamTrackMetrics::StreamType stream_type,
-    MediaStreamInterface* stream,
+    MediaStreamTrackMetrics::Direction direction,
+    MediaStreamTrackMetrics::Kind kind,
+    std::string track_id,
     MediaStreamTrackMetrics* owner)
     : has_reported_start_(false),
       has_reported_end_(false),
-      audio_track_ids_(GetTrackIds(stream->GetAudioTracks())),
-      video_track_ids_(GetTrackIds(stream->GetVideoTracks())),
-      stream_type_(stream_type),
-      observer_(new MediaStreamObserver(
-            base::Bind(&MediaStreamTrackMetricsObserver::OnChanged,
-                       base::Unretained(this)),
-            base::ThreadTaskRunnerHandle::Get(),
-            stream)),
+      direction_(direction),
+      kind_(kind),
+      track_id_(std::move(track_id)),
       owner_(owner) {
+  DCHECK(owner);
 }
 
 MediaStreamTrackMetricsObserver::~MediaStreamTrackMetricsObserver() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  observer_->Unregister();
-  SendLifetimeMessages(MediaStreamTrackMetrics::DISCONNECTED);
+  SendLifetimeMessageForTrack(
+      MediaStreamTrackMetrics::LifetimeEvent::kDisconnected);
 }
 
-void MediaStreamTrackMetricsObserver::SendLifetimeMessages(
+void MediaStreamTrackMetricsObserver::SendLifetimeMessageForTrack(
     MediaStreamTrackMetrics::LifetimeEvent event) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (event == MediaStreamTrackMetrics::CONNECTED) {
+  if (event == MediaStreamTrackMetrics::LifetimeEvent::kConnected) {
     // Both ICE CONNECTED and COMPLETED can trigger the first
     // start-of-life event, so we only report the first.
     if (has_reported_start_)
@@ -199,7 +108,7 @@
     DCHECK(!has_reported_start_ && !has_reported_end_);
     has_reported_start_ = true;
   } else {
-    DCHECK(event == MediaStreamTrackMetrics::DISCONNECTED);
+    DCHECK(event == MediaStreamTrackMetrics::LifetimeEvent::kDisconnected);
 
     // We only report the first end-of-life event, since there are
     // several cases where end-of-life can be reached. We also don't
@@ -209,10 +118,9 @@
     has_reported_end_ = true;
   }
 
-  ReportTracks(audio_track_ids_, MediaStreamTrackMetrics::AUDIO_TRACK, event);
-  ReportTracks(video_track_ids_, MediaStreamTrackMetrics::VIDEO_TRACK, event);
+  owner_->SendLifetimeMessage(track_id_, kind_, event, direction_);
 
-  if (event == MediaStreamTrackMetrics::DISCONNECTED) {
+  if (event == MediaStreamTrackMetrics::LifetimeEvent::kDisconnected) {
     // After disconnection, we can get reconnected, so we need to
     // forget that we've sent lifetime events, while retaining all
     // other state.
@@ -222,76 +130,33 @@
   }
 }
 
-void MediaStreamTrackMetricsObserver::OnChanged(
-    const IdSet& audio_track_ids, const IdSet& video_track_ids) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  // We only report changes after our initial report, and never after
-  // our last report.
-  if (has_reported_start_ && !has_reported_end_) {
-    ReportAddedAndRemovedTracks(audio_track_ids,
-                                audio_track_ids_,
-                                MediaStreamTrackMetrics::AUDIO_TRACK);
-    ReportAddedAndRemovedTracks(video_track_ids,
-                                video_track_ids_,
-                                MediaStreamTrackMetrics::VIDEO_TRACK);
-  }
-
-  // We always update our sets of tracks.
-  audio_track_ids_ = audio_track_ids;
-  video_track_ids_ = video_track_ids;
-}
-
-void MediaStreamTrackMetricsObserver::ReportAddedAndRemovedTracks(
-    const IdSet& new_ids,
-    const IdSet& old_ids,
-    MediaStreamTrackMetrics::TrackType track_type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(has_reported_start_ && !has_reported_end_);
-
-  IdSet added_tracks = base::STLSetDifference<IdSet>(new_ids, old_ids);
-  IdSet removed_tracks = base::STLSetDifference<IdSet>(old_ids, new_ids);
-
-  ReportTracks(added_tracks, track_type, MediaStreamTrackMetrics::CONNECTED);
-  ReportTracks(
-      removed_tracks, track_type, MediaStreamTrackMetrics::DISCONNECTED);
-}
-
-void MediaStreamTrackMetricsObserver::ReportTracks(
-    const IdSet& ids,
-    MediaStreamTrackMetrics::TrackType track_type,
-    MediaStreamTrackMetrics::LifetimeEvent event) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  for (IdSet::const_iterator it = ids.begin(); it != ids.end(); ++it) {
-    owner_->SendLifetimeMessage(*it, track_type, event, stream_type_);
-  }
-}
-
 MediaStreamTrackMetrics::MediaStreamTrackMetrics()
     : ice_state_(webrtc::PeerConnectionInterface::kIceConnectionNew) {}
 
 MediaStreamTrackMetrics::~MediaStreamTrackMetrics() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   for (const auto& observer : observers_) {
-    observer->SendLifetimeMessages(DISCONNECTED);
+    observer->SendLifetimeMessageForTrack(LifetimeEvent::kDisconnected);
   }
 }
 
-void MediaStreamTrackMetrics::AddStream(StreamType type,
-                                        MediaStreamInterface* stream) {
+void MediaStreamTrackMetrics::AddTrack(Direction direction,
+                                       Kind kind,
+                                       const std::string& track_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  observers_.push_back(
-      std::make_unique<MediaStreamTrackMetricsObserver>(type, stream, this));
+  observers_.push_back(std::make_unique<MediaStreamTrackMetricsObserver>(
+      direction, kind, std::move(track_id), this));
   SendLifeTimeMessageDependingOnIceState(observers_.back().get());
 }
 
-void MediaStreamTrackMetrics::RemoveStream(StreamType type,
-                                           MediaStreamInterface* stream) {
+void MediaStreamTrackMetrics::RemoveTrack(Direction direction,
+                                          Kind kind,
+                                          const std::string& track_id) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   auto it = std::find_if(observers_.begin(), observers_.end(),
-                         ObserverFinder(type, stream));
+                         ObserverFinder(direction, kind, track_id));
   if (it == observers_.end()) {
-    // Since external apps could call removeStream with a stream they
+    // Since external apps could call removeTrack() with a stream they
     // never added, this can happen without it being an error.
     return;
   }
@@ -300,40 +165,41 @@
 }
 
 void MediaStreamTrackMetrics::IceConnectionChange(
-    PeerConnectionInterface::IceConnectionState new_state) {
+    webrtc::PeerConnectionInterface::IceConnectionState new_state) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   ice_state_ = new_state;
   for (const auto& observer : observers_) {
     SendLifeTimeMessageDependingOnIceState(observer.get());
   }
 }
+
 void MediaStreamTrackMetrics::SendLifeTimeMessageDependingOnIceState(
     MediaStreamTrackMetricsObserver* observer) {
   // There is a state transition diagram for these states at
   // http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCIceConnectionState
   switch (ice_state_) {
-    case PeerConnectionInterface::kIceConnectionConnected:
-    case PeerConnectionInterface::kIceConnectionCompleted:
-      observer->SendLifetimeMessages(CONNECTED);
+    case webrtc::PeerConnectionInterface::kIceConnectionConnected:
+    case webrtc::PeerConnectionInterface::kIceConnectionCompleted:
+      observer->SendLifetimeMessageForTrack(LifetimeEvent::kConnected);
       break;
 
-    case PeerConnectionInterface::kIceConnectionFailed:
-      // We don't really need to handle FAILED (it is only supposed
-      // to be preceded by CHECKING so we wouldn't yet have sent a
-      // lifetime message) but we might as well use belt and
-      // suspenders and handle it the same as the other "end call"
-      // states. It will be ignored anyway if the call is not
-      // already connected.
-    case PeerConnectionInterface::kIceConnectionNew:
-      // It's a bit weird to count NEW as an end-lifetime event, but
-      // it's possible to transition directly from a connected state
-      // (CONNECTED or COMPLETED) to NEW, which can then be followed
-      // by a new connection. The observer will ignore the end
-      // lifetime event if it was not preceded by a begin-lifetime
-      // event.
-    case PeerConnectionInterface::kIceConnectionDisconnected:
-    case PeerConnectionInterface::kIceConnectionClosed:
-      observer->SendLifetimeMessages(DISCONNECTED);
+    case webrtc::PeerConnectionInterface::kIceConnectionFailed:
+    // We don't really need to handle FAILED (it is only supposed
+    // to be preceded by CHECKING so we wouldn't yet have sent a
+    // lifetime message) but we might as well use belt and
+    // suspenders and handle it the same as the other "end call"
+    // states. It will be ignored anyway if the call is not
+    // already connected.
+    case webrtc::PeerConnectionInterface::kIceConnectionNew:
+    // It's a bit weird to count NEW as an end-lifetime event, but
+    // it's possible to transition directly from a connected state
+    // (CONNECTED or COMPLETED) to NEW, which can then be followed
+    // by a new connection. The observer will ignore the end
+    // lifetime event if it was not preceded by a begin-lifetime
+    // event.
+    case webrtc::PeerConnectionInterface::kIceConnectionDisconnected:
+    case webrtc::PeerConnectionInterface::kIceConnectionClosed:
+      observer->SendLifetimeMessageForTrack(LifetimeEvent::kDisconnected);
       break;
 
     default:
@@ -345,28 +211,28 @@
 }
 
 void MediaStreamTrackMetrics::SendLifetimeMessage(const std::string& track_id,
-                                                  TrackType track_type,
+                                                  Kind kind,
                                                   LifetimeEvent event,
-                                                  StreamType stream_type) {
+                                                  Direction direction) {
   RenderThreadImpl* render_thread = RenderThreadImpl::current();
   // |render_thread| can be NULL in certain cases when running as part
   // |of a unit test.
   if (render_thread) {
-    if (event == CONNECTED) {
+    if (event == LifetimeEvent::kConnected) {
       GetMediaStreamTrackMetricsHost()->AddTrack(
-          MakeUniqueId(track_id, stream_type), track_type == AUDIO_TRACK,
-          stream_type == RECEIVED_STREAM);
+          MakeUniqueId(track_id, direction), kind == Kind::kAudio,
+          direction == Direction::kReceive);
     } else {
-      DCHECK_EQ(DISCONNECTED, event);
+      DCHECK_EQ(LifetimeEvent::kDisconnected, event);
       GetMediaStreamTrackMetricsHost()->RemoveTrack(
-          MakeUniqueId(track_id, stream_type));
+          MakeUniqueId(track_id, direction));
     }
   }
 }
 
 uint64_t MediaStreamTrackMetrics::MakeUniqueIdImpl(uint64_t pc_id,
                                                    const std::string& track_id,
-                                                   StreamType stream_type) {
+                                                   Direction direction) {
   // We use a hash over the |track| pointer and the PeerConnection ID,
   // plus a boolean flag indicating whether the track is remote (since
   // you might conceivably have a remote track added back as a sent
@@ -376,10 +242,8 @@
   // no longer be considered), just one with virtually zero chance of
   // collisions when faced with non-malicious data.
   std::string unique_id_string =
-      base::StringPrintf("%" PRIu64 " %s %d",
-                         pc_id,
-                         track_id.c_str(),
-                         stream_type == RECEIVED_STREAM ? 1 : 0);
+      base::StringPrintf("%" PRIu64 " %s %d", pc_id, track_id.c_str(),
+                         direction == Direction::kReceive ? 1 : 0);
 
   base::MD5Context ctx;
   base::MD5Init(&ctx);
@@ -392,10 +256,10 @@
 }
 
 uint64_t MediaStreamTrackMetrics::MakeUniqueId(const std::string& track_id,
-                                               StreamType stream_type) {
+                                               Direction direction) {
   return MakeUniqueIdImpl(
       reinterpret_cast<uint64_t>(reinterpret_cast<void*>(this)), track_id,
-      stream_type);
+      direction);
 }
 
 mojom::MediaStreamTrackMetricsHostPtr&
diff --git a/content/renderer/media/webrtc/media_stream_track_metrics.h b/content/renderer/media/webrtc/media_stream_track_metrics.h
index 7793186..addd76a 100644
--- a/content/renderer/media/webrtc/media_stream_track_metrics.h
+++ b/content/renderer/media/webrtc/media_stream_track_metrics.h
@@ -15,10 +15,6 @@
 #include "content/common/media/media_stream.mojom.h"
 #include "third_party/webrtc/api/peerconnectioninterface.h"
 
-namespace webrtc {
-class MediaStreamInterface;
-}
-
 namespace content {
 
 class MediaStreamTrackMetricsObserver;
@@ -36,19 +32,16 @@
   explicit MediaStreamTrackMetrics();
   ~MediaStreamTrackMetrics();
 
-  enum StreamType { SENT_STREAM, RECEIVED_STREAM };
+  enum class Direction { kSend, kReceive };
+  enum class Kind { kAudio, kVideo };
+  enum class LifetimeEvent { kConnected, kDisconnected };
 
-  enum TrackType { AUDIO_TRACK, VIDEO_TRACK };
+  // Starts tracking the lifetime of the track until |RemoveTrack| is called
+  // or this object's lifetime ends.
+  void AddTrack(Direction direction, Kind kind, const std::string& track_id);
 
-  enum LifetimeEvent { CONNECTED, DISCONNECTED };
-
-  // Starts tracking lifetimes of all the tracks in |stream| and any
-  // tracks added or removed to/from the stream until |RemoveStream|
-  // is called or this object's lifetime ends.
-  void AddStream(StreamType type, webrtc::MediaStreamInterface* stream);
-
-  // Stops tracking lifetimes of tracks in |stream|.
-  void RemoveStream(StreamType type, webrtc::MediaStreamInterface* stream);
+  // Stops tracking the lifetime of the track.
+  void RemoveTrack(Direction direction, Kind kind, const std::string& track_id);
 
   // Called to indicate changes in the ICE connection state for the
   // PeerConnection this object is associated with. Used to generate
@@ -71,9 +64,9 @@
   // PeerConnection), false for local streams (sent over a
   // PeerConnection).
   virtual void SendLifetimeMessage(const std::string& track_id,
-                                   TrackType track_type,
+                                   Kind kind,
                                    LifetimeEvent lifetime_event,
-                                   StreamType stream_type);
+                                   Direction direction);
 
  protected:
   // Calls SendLifetimeMessage for |observer| depending on |ice_state_|.
@@ -86,12 +79,12 @@
   // is a one-to-one relationship).
   uint64_t MakeUniqueIdImpl(uint64_t pc_id,
                             const std::string& track,
-                            StreamType stream_type);
+                            Direction direction);
 
  private:
   // Make a unique ID for the given track, that is valid while the
   // track object and the PeerConnection it is attached to both exist.
-  uint64_t MakeUniqueId(const std::string& track, StreamType stream_type);
+  uint64_t MakeUniqueId(const std::string& track_id, Direction direction);
 
   mojom::MediaStreamTrackMetricsHostPtr& GetMediaStreamTrackMetricsHost();
 
diff --git a/content/renderer/media/webrtc/media_stream_track_metrics_unittest.cc b/content/renderer/media/webrtc/media_stream_track_metrics_unittest.cc
index d8819aa..4fb4ff3 100644
--- a/content/renderer/media/webrtc/media_stream_track_metrics_unittest.cc
+++ b/content/renderer/media/webrtc/media_stream_track_metrics_unittest.cc
@@ -78,8 +78,7 @@
   virtual ~MockMediaStreamTrackMetrics() {}
 
   MOCK_METHOD4(SendLifetimeMessage,
-               void(const std::string&, TrackType, LifetimeEvent, StreamType));
-
+               void(const std::string&, Kind, LifetimeEvent, Direction));
   using MediaStreamTrackMetrics::MakeUniqueIdImpl;
 };
 
@@ -170,88 +169,82 @@
 
   // Lower 32 bits the same, upper 32 differ.
   EXPECT_NE(
-      metrics_->MakeUniqueIdImpl(
-          0x1000000000000001, "x", MediaStreamTrackMetrics::RECEIVED_STREAM),
-      metrics_->MakeUniqueIdImpl(
-          0x2000000000000001, "x", MediaStreamTrackMetrics::RECEIVED_STREAM));
+      metrics_->MakeUniqueIdImpl(0x1000000000000001, "x",
+                                 MediaStreamTrackMetrics::Direction::kReceive),
+      metrics_->MakeUniqueIdImpl(0x2000000000000001, "x",
+                                 MediaStreamTrackMetrics::Direction::kReceive));
 
   // Track ID differs.
   EXPECT_NE(metrics_->MakeUniqueIdImpl(
-                42, "x", MediaStreamTrackMetrics::RECEIVED_STREAM),
+                42, "x", MediaStreamTrackMetrics::Direction::kReceive),
             metrics_->MakeUniqueIdImpl(
-                42, "y", MediaStreamTrackMetrics::RECEIVED_STREAM));
+                42, "y", MediaStreamTrackMetrics::Direction::kReceive));
 
   // Remove vs. local track differs.
   EXPECT_NE(metrics_->MakeUniqueIdImpl(
-                42, "x", MediaStreamTrackMetrics::RECEIVED_STREAM),
+                42, "x", MediaStreamTrackMetrics::Direction::kReceive),
             metrics_->MakeUniqueIdImpl(
-                42, "x", MediaStreamTrackMetrics::SENT_STREAM));
+                42, "x", MediaStreamTrackMetrics::Direction::kSend));
 }
 
 TEST_F(MediaStreamTrackMetricsTest, BasicRemoteStreams) {
-  scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio"));
-  scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video"));
-  stream_->AddTrack(audio.get());
-  stream_->AddTrack(video.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                     MediaStreamTrackMetrics::Kind::kVideo, "video");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kReceive));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "video", MediaStreamTrackMetrics::Kind::kVideo,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kReceive));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kReceive));
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("video", MediaStreamTrackMetrics::Kind::kVideo,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kReceive));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionDisconnected);
 }
 
 TEST_F(MediaStreamTrackMetricsTest, BasicLocalStreams) {
-  scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio"));
-  scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video"));
-  stream_->AddTrack(audio.get());
-  stream_->AddTrack(video.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kVideo, "video");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "video", MediaStreamTrackMetrics::Kind::kVideo,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("video", MediaStreamTrackMetrics::Kind::kVideo,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
   metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
 }
 
@@ -259,341 +252,226 @@
   metrics_->IceConnectionChange(
         PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "video", MediaStreamTrackMetrics::Kind::kVideo,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
 
-  scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio"));
-  scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video"));
-  stream_->AddTrack(audio.get());
-  stream_->AddTrack(video.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kVideo, "video");
 }
 
 TEST_F(MediaStreamTrackMetricsTest, RemoteStreamAddedAferIceConnect) {
   metrics_->IceConnectionChange(
         PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kReceive));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "video", MediaStreamTrackMetrics::Kind::kVideo,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kReceive));
 
-  scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio"));
-  scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video"));
-  stream_->AddTrack(audio.get());
-  stream_->AddTrack(video.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
-}
-
-TEST_F(MediaStreamTrackMetricsTest, RemoteStreamTrackAdded) {
-  scoped_refptr<MockAudioTrackInterface> initial(MakeAudioTrack("initial"));
-  scoped_refptr<MockAudioTrackInterface> added(MakeAudioTrack("added"));
-  stream_->AddTrack(initial.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
-
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("initial",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
-  metrics_->IceConnectionChange(
-      PeerConnectionInterface::kIceConnectionConnected);
-
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("added",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
-  AddAudioTrack(added.get());
-
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("initial",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("added",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
-  metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                     MediaStreamTrackMetrics::Kind::kVideo, "video");
 }
 
 TEST_F(MediaStreamTrackMetricsTest, LocalStreamTrackRemoved) {
-  scoped_refptr<MockAudioTrackInterface> first(MakeAudioTrack("first"));
-  scoped_refptr<MockAudioTrackInterface> second(MakeAudioTrack("second"));
-  stream_->AddTrack(first.get());
-  stream_->AddTrack(second.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kAudio, "first");
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kAudio, "second");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("first",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("second",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "first", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "second", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("first",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  stream_->RemoveTrack(first.get());
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("first", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
+                        MediaStreamTrackMetrics::Kind::kAudio, "first");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("second",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("second", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
   metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
 }
 
-TEST_F(MediaStreamTrackMetricsTest, LocalStreamModificationsBeforeAndAfter) {
-  scoped_refptr<MockAudioTrackInterface> first(MakeAudioTrack("first"));
-  scoped_refptr<MockAudioTrackInterface> second(MakeAudioTrack("second"));
-  stream_->AddTrack(first.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
+TEST_F(MediaStreamTrackMetricsTest, RemoveAfterDisconnect) {
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
 
-  // This gets added after we start observing, but no lifetime message
-  // should be sent at this point since the call is not connected. It
-  // should get sent only once it gets connected.
-  AddAudioTrack(second.get());
-
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("first",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("second",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("first",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("second",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
   metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
 
   // This happens after the call is disconnected so no lifetime
   // message should be sent.
-  RemoveAudioTrack(first.get());
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
+                        MediaStreamTrackMetrics::Kind::kAudio, "audio");
 }
 
 TEST_F(MediaStreamTrackMetricsTest, RemoteStreamMultipleDisconnects) {
-  scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio"));
-  stream_->AddTrack(audio.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kReceive));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::RECEIVED_STREAM));
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kReceive));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionDisconnected);
   metrics_->IceConnectionChange(PeerConnectionInterface::kIceConnectionFailed);
-  RemoveAudioTrack(audio.get());
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                        MediaStreamTrackMetrics::Kind::kAudio, "audio");
 }
 
 TEST_F(MediaStreamTrackMetricsTest, RemoteStreamConnectDisconnectTwice) {
-  scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio"));
-  stream_->AddTrack(audio.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, stream_.get());
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
 
   for (size_t i = 0; i < 2; ++i) {
-    EXPECT_CALL(*metrics_,
-                SendLifetimeMessage("audio",
-                                    MediaStreamTrackMetrics::AUDIO_TRACK,
-                                    MediaStreamTrackMetrics::CONNECTED,
-                                    MediaStreamTrackMetrics::RECEIVED_STREAM));
+    EXPECT_CALL(
+        *metrics_,
+        SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
+                            MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                            MediaStreamTrackMetrics::Direction::kReceive));
     metrics_->IceConnectionChange(
         PeerConnectionInterface::kIceConnectionConnected);
 
     EXPECT_CALL(*metrics_,
-                SendLifetimeMessage("audio",
-                                    MediaStreamTrackMetrics::AUDIO_TRACK,
-                                    MediaStreamTrackMetrics::DISCONNECTED,
-                                    MediaStreamTrackMetrics::RECEIVED_STREAM));
+                SendLifetimeMessage(
+                    "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                    MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                    MediaStreamTrackMetrics::Direction::kReceive));
     metrics_->IceConnectionChange(
         PeerConnectionInterface::kIceConnectionDisconnected);
   }
 
-  RemoveAudioTrack(audio.get());
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                        MediaStreamTrackMetrics::Kind::kAudio, "audio");
 }
 
 TEST_F(MediaStreamTrackMetricsTest, LocalStreamRemovedNoDisconnect) {
-  scoped_refptr<MockAudioTrackInterface> audio(MakeAudioTrack("audio"));
-  scoped_refptr<MockVideoTrackInterface> video(MakeVideoTrack("video"));
-  stream_->AddTrack(audio.get());
-  stream_->AddTrack(video.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kVideo, "video");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "video", MediaStreamTrackMetrics::Kind::kVideo,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  metrics_->RemoveStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("video", MediaStreamTrackMetrics::Kind::kVideo,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
+                        MediaStreamTrackMetrics::Kind::kAudio, "audio");
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
+                        MediaStreamTrackMetrics::Kind::kVideo, "video");
 }
 
 TEST_F(MediaStreamTrackMetricsTest, LocalStreamLargerTest) {
-  scoped_refptr<MockAudioTrackInterface> audio1(MakeAudioTrack("audio1"));
-  scoped_refptr<MockAudioTrackInterface> audio2(MakeAudioTrack("audio2"));
-  scoped_refptr<MockAudioTrackInterface> audio3(MakeAudioTrack("audio3"));
-  scoped_refptr<MockVideoTrackInterface> video1(MakeVideoTrack("video1"));
-  scoped_refptr<MockVideoTrackInterface> video2(MakeVideoTrack("video2"));
-  scoped_refptr<MockVideoTrackInterface> video3(MakeVideoTrack("video3"));
-  stream_->AddTrack(audio1.get());
-  stream_->AddTrack(video1.get());
-  metrics_->AddStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kVideo, "video");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio1",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video1",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "video", MediaStreamTrackMetrics::Kind::kVideo,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
   metrics_->IceConnectionChange(
       PeerConnectionInterface::kIceConnectionConnected);
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio2",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  AddAudioTrack(audio2.get());
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video2",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  AddVideoTrack(video2.get());
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
+                        MediaStreamTrackMetrics::Kind::kAudio, "audio");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio1",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  RemoveAudioTrack(audio1.get());
+  // Add back audio
+  EXPECT_CALL(*metrics_, SendLifetimeMessage(
+                             "audio", MediaStreamTrackMetrics::Kind::kAudio,
+                             MediaStreamTrackMetrics::LifetimeEvent::kConnected,
+                             MediaStreamTrackMetrics::Direction::kSend));
+  metrics_->AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                     MediaStreamTrackMetrics::Kind::kAudio, "audio");
 
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio3",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  AddAudioTrack(audio3.get());
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video3",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  AddVideoTrack(video3.get());
-
-  // Add back audio1
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio1",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::CONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  AddAudioTrack(audio1.get());
-
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio2",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  RemoveAudioTrack(audio2.get());
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video2",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  RemoveVideoTrack(video2.get());
-
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio1",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  RemoveAudioTrack(audio1.get());
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video1",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  RemoveVideoTrack(video1.get());
-
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("audio3",
-                                  MediaStreamTrackMetrics::AUDIO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  EXPECT_CALL(*metrics_,
-              SendLifetimeMessage("video3",
-                                  MediaStreamTrackMetrics::VIDEO_TRACK,
-                                  MediaStreamTrackMetrics::DISCONNECTED,
-                                  MediaStreamTrackMetrics::SENT_STREAM));
-  metrics_->RemoveStream(MediaStreamTrackMetrics::SENT_STREAM, stream_.get());
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("audio", MediaStreamTrackMetrics::Kind::kAudio,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
+                        MediaStreamTrackMetrics::Kind::kAudio, "audio");
+  EXPECT_CALL(
+      *metrics_,
+      SendLifetimeMessage("video", MediaStreamTrackMetrics::Kind::kVideo,
+                          MediaStreamTrackMetrics::LifetimeEvent::kDisconnected,
+                          MediaStreamTrackMetrics::Direction::kSend));
+  metrics_->RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
+                        MediaStreamTrackMetrics::Kind::kVideo, "video");
 }
 
 }  // namespace content
diff --git a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
index fcf13d5..bd092e8 100644
--- a/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/webrtc/rtc_peer_connection_handler.cc
@@ -893,6 +893,13 @@
   return kSdpSemanticRequestedDefault;
 }
 
+MediaStreamTrackMetrics::Kind MediaStreamTrackMetricsKind(
+    const blink::WebMediaStreamTrack& track) {
+  return track.Source().GetType() == blink::WebMediaStreamSource::kTypeAudio
+             ? MediaStreamTrackMetrics::Kind::kAudio
+             : MediaStreamTrackMetrics::Kind::kVideo;
+}
+
 }  // namespace
 
 // Implementation of LocalRTCStatsRequest.
@@ -1826,6 +1833,9 @@
                                         webrtc_streams);
   if (!webrtc_sender)
     return nullptr;
+  track_metrics_.AddTrack(MediaStreamTrackMetrics::Direction::kSend,
+                          MediaStreamTrackMetricsKind(track),
+                          track.Id().Utf8());
   DCHECK(FindSender(RTCRtpSender::getId(webrtc_sender)) == rtp_senders_.end());
   rtp_senders_.push_back(std::make_unique<RTCRtpSender>(
       native_peer_connection_, task_runner_, signaling_thread(),
@@ -1840,8 +1850,6 @@
     if (GetLocalStreamUsageCount(rtp_senders_,
                                  stream_ref->adapter().web_stream()) == 1u) {
       PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
-      track_metrics_.AddStream(MediaStreamTrackMetrics::SENT_STREAM,
-                               stream_ref->adapter().webrtc_stream().get());
     }
   }
   return rtp_senders_.back()->ShallowCopy();
@@ -1850,11 +1858,15 @@
 bool RTCPeerConnectionHandler::RemoveTrack(blink::WebRTCRtpSender* web_sender) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::RemoveTrack");
+  auto web_track = web_sender->Track();
   auto it = FindSender(web_sender->Id());
   if (it == rtp_senders_.end())
     return false;
   if (!(*it)->RemoveFromPeerConnection(native_peer_connection_.get()))
     return false;
+  track_metrics_.RemoveTrack(MediaStreamTrackMetrics::Direction::kSend,
+                             MediaStreamTrackMetricsKind(web_track),
+                             web_track.Id().Utf8());
   auto stream_refs = (*it)->stream_refs();
   if (peer_connection_tracker_) {
     peer_connection_tracker_->TrackRemoveTransceiver(
@@ -1869,8 +1881,6 @@
     if (GetLocalStreamUsageCount(rtp_senders_,
                                  stream_ref->adapter().web_stream()) == 0u) {
       PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
-      track_metrics_.RemoveStream(MediaStreamTrackMetrics::SENT_STREAM,
-                                  stream_ref->adapter().webrtc_stream().get());
     }
   }
   return true;
@@ -2062,7 +2072,10 @@
         remote_stream_adapter_refs) {
   DCHECK(task_runner_->RunsTasksInCurrentSequence());
   TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnAddRemoteTrack");
-
+  auto web_track = remote_track_adapter_ref->web_track();
+  track_metrics_.AddTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                          MediaStreamTrackMetricsKind(web_track),
+                          web_track.Id().Utf8());
   for (const auto& remote_stream_adapter_ref : remote_stream_adapter_refs) {
     // New remote stream?
     if (GetRemoteStreamUsageCount(
@@ -2070,9 +2083,6 @@
             remote_stream_adapter_ref->adapter().webrtc_stream().get()) == 0) {
       // Update metrics.
       PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter();
-      track_metrics_.AddStream(
-          MediaStreamTrackMetrics::RECEIVED_STREAM,
-          remote_stream_adapter_ref->adapter().webrtc_stream().get());
     }
   }
 
@@ -2116,8 +2126,12 @@
           nullptr /* sender */, it->second->ShallowCopy() /* receiver */);
     }
     remote_stream_adapter_refs = it->second->StreamAdapterRefs();
+    auto receiver = it->second->ShallowCopy();
+    track_metrics_.RemoveTrack(MediaStreamTrackMetrics::Direction::kReceive,
+                               MediaStreamTrackMetricsKind(receiver->Track()),
+                               receiver->Track().Id().Utf8());
     if (!is_closed_)
-      client_->DidRemoveRemoteTrack(it->second->ShallowCopy());
+      client_->DidRemoveRemoteTrack(std::move(receiver));
     rtp_receivers_.erase(it);
   }
 
@@ -2127,9 +2141,6 @@
             rtp_receivers_,
             remote_stream_adapter_ref->adapter().webrtc_stream().get()) == 0) {
       // Update metrics.
-      track_metrics_.RemoveStream(
-          MediaStreamTrackMetrics::RECEIVED_STREAM,
-          remote_stream_adapter_ref->adapter().webrtc_stream().get());
       PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter();
     }
   }
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.cc
index e03d171..a20adaaa 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.cc
@@ -63,22 +63,24 @@
       remote_track_can_complete_initialization_(
           base::WaitableEvent::ResetPolicy::MANUAL,
           base::WaitableEvent::InitialState::NOT_SIGNALED),
-      is_initialized_(false) {
+      is_initialized_(false),
+      is_disposed_(false) {
   DCHECK(factory_);
   DCHECK(main_thread_);
 }
 
 WebRtcMediaStreamTrackAdapter::~WebRtcMediaStreamTrackAdapter() {
   DCHECK(!remote_track_can_complete_initialization_.IsSignaled());
-  DCHECK(!is_initialized_);
+  DCHECK(is_disposed_);
 }
 
 void WebRtcMediaStreamTrackAdapter::Dispose() {
   DCHECK(main_thread_->BelongsToCurrentThread());
-  if (!is_initialized_)
+  DCHECK(is_initialized_);
+  if (is_disposed_)
     return;
   remote_track_can_complete_initialization_.Reset();
-  is_initialized_ = false;
+  is_disposed_ = true;
   if (web_track_.Source().GetType() ==
       blink::WebMediaStreamSource::kTypeAudio) {
     if (local_track_audio_sink_)
@@ -99,10 +101,19 @@
   return is_initialized_;
 }
 
+void WebRtcMediaStreamTrackAdapter::InitializeOnMainThread() {
+  DCHECK(main_thread_->BelongsToCurrentThread());
+  if (is_initialized_)
+    return;
+  // TODO(hbos): Only ever initialize explicitly,
+  // remove EnsureTrackIsInitialized(). https://crbug.com/857458
+  EnsureTrackIsInitialized();
+}
+
 const blink::WebMediaStreamTrack& WebRtcMediaStreamTrackAdapter::web_track() {
   DCHECK(main_thread_->BelongsToCurrentThread());
-  DCHECK(!web_track_.IsNull());
   EnsureTrackIsInitialized();
+  DCHECK(!web_track_.IsNull());
   return web_track_;
 }
 
@@ -231,6 +242,7 @@
 }
 
 void WebRtcMediaStreamTrackAdapter::EnsureTrackIsInitialized() {
+  DCHECK(main_thread_->BelongsToCurrentThread());
   if (is_initialized_)
     return;
 
@@ -242,7 +254,6 @@
 
 void WebRtcMediaStreamTrackAdapter::DisposeLocalAudioTrack() {
   DCHECK(main_thread_->BelongsToCurrentThread());
-  DCHECK(!is_initialized_);
   DCHECK(local_track_audio_sink_);
   DCHECK_EQ(web_track_.Source().GetType(),
             blink::WebMediaStreamSource::kTypeAudio);
@@ -256,7 +267,6 @@
 
 void WebRtcMediaStreamTrackAdapter::DisposeLocalVideoTrack() {
   DCHECK(main_thread_->BelongsToCurrentThread());
-  DCHECK(!is_initialized_);
   DCHECK(local_track_video_sink_);
   DCHECK_EQ(web_track_.Source().GetType(),
             blink::WebMediaStreamSource::kTypeVideo);
@@ -267,7 +277,6 @@
 
 void WebRtcMediaStreamTrackAdapter::DisposeRemoteAudioTrack() {
   DCHECK(main_thread_->BelongsToCurrentThread());
-  DCHECK(!is_initialized_);
   DCHECK(remote_audio_track_adapter_);
   DCHECK_EQ(web_track_.Source().GetType(),
             blink::WebMediaStreamSource::kTypeAudio);
@@ -280,7 +289,6 @@
 
 void WebRtcMediaStreamTrackAdapter::DisposeRemoteVideoTrack() {
   DCHECK(main_thread_->BelongsToCurrentThread());
-  DCHECK(!is_initialized_);
   DCHECK(remote_video_track_adapter_);
   DCHECK_EQ(web_track_.Source().GetType(),
             blink::WebMediaStreamSource::kTypeVideo);
@@ -300,7 +308,7 @@
 
 void WebRtcMediaStreamTrackAdapter::FinalizeRemoteTrackDisposingOnMainThread() {
   DCHECK(main_thread_->BelongsToCurrentThread());
-  DCHECK(!is_initialized_);
+  DCHECK(is_disposed_);
   remote_audio_track_adapter_ = nullptr;
   remote_video_track_adapter_ = nullptr;
   webrtc_track_ = nullptr;
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.h b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.h
index 722738c3..8be75b5 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.h
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter.h
@@ -53,6 +53,7 @@
   void Dispose();
 
   bool is_initialized() const;
+  void InitializeOnMainThread();
   // These methods must be called on the main thread.
   // TODO(hbos): Allow these methods to be called on any thread and make them
   // const. https://crbug.com/756436
@@ -116,6 +117,7 @@
   // completed on the main thread.
   base::WaitableEvent remote_track_can_complete_initialization_;
   bool is_initialized_;
+  bool is_disposed_;
   blink::WebMediaStreamTrack web_track_;
   scoped_refptr<webrtc::MediaStreamTrackInterface> webrtc_track_;
   // If the track is local, a sink is added to the local webrtc track that is
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
index 28d6c17..de3f036b 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.cc
@@ -59,6 +59,17 @@
   return base::WrapUnique(new AdapterRef(map_, type_, adapter_));
 }
 
+void WebRtcMediaStreamTrackAdapterMap::AdapterRef::InitializeOnMainThread() {
+  adapter_->InitializeOnMainThread();
+  if (type_ == WebRtcMediaStreamTrackAdapterMap::AdapterRef::Type::kRemote) {
+    base::AutoLock scoped_lock(map_->lock_);
+    if (!map_->remote_track_adapters_.FindBySecondary(web_track().UniqueId())) {
+      map_->remote_track_adapters_.SetSecondaryKey(webrtc_track(),
+                                                   web_track().UniqueId());
+    }
+  }
+}
+
 WebRtcMediaStreamTrackAdapterMap::WebRtcMediaStreamTrackAdapterMap(
     PeerConnectionDependencyFactory* const factory,
     scoped_refptr<base::SingleThreadTaskRunner> main_thread)
@@ -182,13 +193,13 @@
   // entry as its secondary key. This ensures that there is at least one
   // |AdapterRef| alive until after the adapter is initialized and its secondary
   // key is set.
+  auto adapter_ref = base::WrapUnique(
+      new AdapterRef(this, AdapterRef::Type::kRemote, new_adapter));
   main_thread_->PostTask(
       FROM_HERE,
       base::BindOnce(
-          &WebRtcMediaStreamTrackAdapterMap::OnRemoteTrackAdapterInitialized,
-          this,
-          base::WrapUnique(
-              new AdapterRef(this, AdapterRef::Type::kRemote, new_adapter))));
+          &WebRtcMediaStreamTrackAdapterMap::AdapterRef::InitializeOnMainThread,
+          std::move(adapter_ref)));
   return base::WrapUnique(
       new AdapterRef(this, AdapterRef::Type::kRemote, new_adapter));
 }
@@ -198,14 +209,4 @@
   return remote_track_adapters_.PrimarySize();
 }
 
-void WebRtcMediaStreamTrackAdapterMap::OnRemoteTrackAdapterInitialized(
-    std::unique_ptr<AdapterRef> adapter_ref) {
-  DCHECK(adapter_ref->is_initialized());
-  {
-    base::AutoLock scoped_lock(lock_);
-    remote_track_adapters_.SetSecondaryKey(adapter_ref->webrtc_track(),
-                                           adapter_ref->web_track().UniqueId());
-  }
-}
-
 }  // namespace content
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h
index c7ef9ed..8c9cbf1 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map.h
@@ -38,6 +38,7 @@
 
     std::unique_ptr<AdapterRef> Copy() const;
     bool is_initialized() const { return adapter_->is_initialized(); }
+    void InitializeOnMainThread();
     const blink::WebMediaStreamTrack& web_track() const {
       return adapter_->web_track();
     }
@@ -137,8 +138,6 @@
   // Invoke on the main thread.
   virtual ~WebRtcMediaStreamTrackAdapterMap();
 
-  void OnRemoteTrackAdapterInitialized(std::unique_ptr<AdapterRef> adapter_ref);
-
   // Pointer to a |PeerConnectionDependencyFactory| owned by the |RenderThread|.
   // It's valid for the lifetime of |RenderThread|.
   PeerConnectionDependencyFactory* const factory_;
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
index 8c5fd3e..a141ce50 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_map_unittest.cc
@@ -53,8 +53,8 @@
   }
 
   std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef>
-  GetOrCreateRemoteTrackAdapter(
-      webrtc::MediaStreamTrackInterface* webrtc_track) {
+  GetOrCreateRemoteTrackAdapter(webrtc::MediaStreamTrackInterface* webrtc_track,
+                                bool wait_for_initialization = true) {
     DCHECK(main_thread_->BelongsToCurrentThread());
     std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> adapter;
     signaling_thread()->PostTask(
@@ -63,7 +63,13 @@
                            GetOrCreateRemoteTrackAdapterOnSignalingThread,
                        base::Unretained(this), base::Unretained(webrtc_track),
                        &adapter));
-    RunMessageLoopsUntilIdle();
+    RunMessageLoopsUntilIdle(wait_for_initialization);
+    DCHECK(adapter);
+    if (wait_for_initialization) {
+      DCHECK(adapter->is_initialized());
+    } else {
+      DCHECK(!adapter->is_initialized());
+    }
     return adapter;
   }
 
@@ -76,7 +82,7 @@
 
   // Runs message loops on the webrtc signaling thread and the main thread until
   // idle.
-  void RunMessageLoopsUntilIdle() {
+  void RunMessageLoopsUntilIdle(bool run_loop_on_main_thread = true) {
     DCHECK(main_thread_->BelongsToCurrentThread());
     base::WaitableEvent waitable_event(
         base::WaitableEvent::ResetPolicy::MANUAL,
@@ -86,7 +92,8 @@
                                       RunMessageLoopUntilIdleOnSignalingThread,
                                   base::Unretained(this), &waitable_event));
     waitable_event.Wait();
-    base::RunLoop().RunUntilIdle();
+    if (run_loop_on_main_thread)
+      base::RunLoop().RunUntilIdle();
   }
 
   void RunMessageLoopUntilIdleOnSignalingThread(
@@ -168,6 +175,29 @@
 }
 
 TEST_F(WebRtcMediaStreamTrackAdapterMapTest,
+       InitializeRemoteTrackAdapterExplicitly) {
+  scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
+      MockWebRtcAudioTrack::Create("remote_track");
+  std::unique_ptr<WebRtcMediaStreamTrackAdapterMap::AdapterRef> adapter_ref =
+      GetOrCreateRemoteTrackAdapter(webrtc_track.get(), false);
+  EXPECT_FALSE(adapter_ref->is_initialized());
+  adapter_ref->InitializeOnMainThread();
+  EXPECT_TRUE(adapter_ref->is_initialized());
+
+  EXPECT_EQ(1u, map_->GetRemoteTrackCount());
+  // Ensure the implicit initialization's posted task is run after it is already
+  // initialized.
+  RunMessageLoopsUntilIdle();
+  // Destroying all references to the adapter should remove it from the map and
+  // dispose it.
+  adapter_ref.reset();
+  EXPECT_EQ(0u, map_->GetRemoteTrackCount());
+  EXPECT_EQ(nullptr, map_->GetRemoteTrackAdapter(webrtc_track.get()));
+  // Allow the disposing of track to occur.
+  RunMessageLoopsUntilIdle();
+}
+
+TEST_F(WebRtcMediaStreamTrackAdapterMapTest,
        LocalAndRemoteTrackAdaptersWithSameID) {
   // Local and remote tracks should be able to use the same id without conflict.
   const char* id = "id";
diff --git a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc
index 7ca513b..74f586d4 100644
--- a/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc
+++ b/content/renderer/media/webrtc/webrtc_media_stream_track_adapter_unittest.cc
@@ -37,7 +37,6 @@
     if (track_adapter_) {
       EXPECT_TRUE(track_adapter_->is_initialized());
       track_adapter_->Dispose();
-      EXPECT_FALSE(track_adapter_->is_initialized());
       track_adapter_ = nullptr;
       RunMessageLoopsUntilIdle();
     }
@@ -80,9 +79,9 @@
         dependency_factory_.get(), main_thread_, webrtc_track);
   }
 
-  // Runs message loops on the webrtc signaling thread and the main thread until
-  // idle.
-  void RunMessageLoopsUntilIdle() {
+  // Runs message loops on the webrtc signaling thread and optionally the main
+  // thread until idle.
+  void RunMessageLoopsUntilIdle(bool run_loop_on_main_thread = true) {
     base::WaitableEvent waitable_event(
         base::WaitableEvent::ResetPolicy::MANUAL,
         base::WaitableEvent::InitialState::NOT_SIGNALED);
@@ -91,7 +90,8 @@
                                       RunMessageLoopUntilIdleOnSignalingThread,
                                   base::Unretained(this), &waitable_event));
     waitable_event.Wait();
-    base::RunLoop().RunUntilIdle();
+    if (run_loop_on_main_thread)
+      base::RunLoop().RunUntilIdle();
   }
 
   void RunMessageLoopUntilIdleOnSignalingThread(
@@ -157,6 +157,7 @@
       base::BindOnce(
           &WebRtcMediaStreamTrackAdapterTest::CreateRemoteTrackAdapter,
           base::Unretained(this), base::Unretained(webrtc_track.get())));
+  // The adapter is initialized implicitly in a PostTask, allow it to run.
   RunMessageLoopsUntilIdle();
   DCHECK(track_adapter_);
   EXPECT_TRUE(track_adapter_->is_initialized());
@@ -181,6 +182,7 @@
       base::BindOnce(
           &WebRtcMediaStreamTrackAdapterTest::CreateRemoteTrackAdapter,
           base::Unretained(this), base::Unretained(webrtc_track.get())));
+  // The adapter is initialized implicitly in a PostTask, allow it to run.
   RunMessageLoopsUntilIdle();
   DCHECK(track_adapter_);
   EXPECT_TRUE(track_adapter_->is_initialized());
@@ -197,4 +199,33 @@
       track_adapter_->GetRemoteVideoTrackAdapterForTesting()->initialized());
 }
 
+TEST_F(WebRtcMediaStreamTrackAdapterTest, RemoteTrackExplicitlyInitialized) {
+  scoped_refptr<MockWebRtcAudioTrack> webrtc_track =
+      MockWebRtcAudioTrack::Create("remote_audio_track");
+  dependency_factory_->GetWebRtcSignalingThread()->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &WebRtcMediaStreamTrackAdapterTest::CreateRemoteTrackAdapter,
+          base::Unretained(this), base::Unretained(webrtc_track.get())));
+  // Wait for the CreateRemoteTrackAdapter() call, but don't run the main thread
+  // loop that would have implicitly initialized the adapter.
+  RunMessageLoopsUntilIdle(false);
+  DCHECK(track_adapter_);
+  EXPECT_FALSE(track_adapter_->is_initialized());
+  // Explicitly initialize before the main thread loop has a chance to run.
+  track_adapter_->InitializeOnMainThread();
+  EXPECT_TRUE(track_adapter_->is_initialized());
+  EXPECT_TRUE(!track_adapter_->web_track().IsNull());
+  EXPECT_EQ(track_adapter_->web_track().Source().GetType(),
+            blink::WebMediaStreamSource::kTypeAudio);
+  EXPECT_TRUE(track_adapter_->webrtc_track());
+  EXPECT_EQ(track_adapter_->webrtc_track()->kind(),
+            webrtc::MediaStreamTrackInterface::kAudioKind);
+  EXPECT_EQ(track_adapter_->webrtc_track()->id().c_str(),
+            track_adapter_->web_track().Id());
+  EXPECT_TRUE(track_adapter_->GetRemoteAudioTrackAdapterForTesting());
+  EXPECT_TRUE(
+      track_adapter_->GetRemoteAudioTrackAdapterForTesting()->initialized());
+}
+
 }  // namespace content
diff --git a/content/renderer/mus/BUILD.gn b/content/renderer/mus/BUILD.gn
index 297195a..3fbd631 100644
--- a/content/renderer/mus/BUILD.gn
+++ b/content/renderer/mus/BUILD.gn
@@ -18,6 +18,10 @@
 
   configs += [ "//content:content_implementation" ]
 
+  public_deps = [
+    "//content/public/common:common_sources",
+  ]
+
   deps = [
     "//base",
     "//cc",
@@ -25,7 +29,6 @@
     "//components/viz/client",
     "//content/common",
     "//content/public/child:child_sources",
-    "//content/public/common:common_sources",
     "//media/mojo/interfaces:remoting",
     "//services/service_manager/public/cpp",
     "//services/ui/public/cpp",
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 0bc1692..59cafc6 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -205,13 +205,17 @@
 class RendererBlinkPlatformImpl::SandboxSupport
     : public blink::WebSandboxSupport {
  public:
+#if defined(OS_LINUX)
+  explicit SandboxSupport(sk_sp<font_service::FontLoader> font_loader)
+      : font_loader_(std::move(font_loader)) {}
+#endif
   ~SandboxSupport() override {}
 
 #if defined(OS_MACOSX)
   bool LoadFont(CTFontRef src_font,
                 CGFontRef* container,
                 uint32_t* font_id) override;
-#elif defined(OS_POSIX)
+#elif defined(OS_LINUX)
   void GetFallbackFontForCharacter(
       blink::WebUChar32 character,
       const char* preferred_locale,
@@ -229,6 +233,7 @@
   // here.
   base::Lock unicode_font_families_mutex_;
   std::map<int32_t, blink::WebFallbackFont> unicode_font_families_;
+  sk_sp<font_service::FontLoader> font_loader_;
 #endif
 };
 #endif  // !defined(OS_ANDROID) && !defined(OS_WIN)
@@ -247,13 +252,6 @@
       is_locked_to_site_(false),
       default_task_runner_(main_thread_scheduler->DefaultTaskRunner()),
       main_thread_scheduler_(main_thread_scheduler) {
-#if !defined(OS_ANDROID) && !defined(OS_WIN) && !defined(OS_FUCHSIA)
-  if (g_sandbox_enabled && sandboxEnabled()) {
-    sandbox_support_.reset(new RendererBlinkPlatformImpl::SandboxSupport);
-  } else {
-    DVLOG(1) << "Disabling sandbox support for testing.";
-  }
-#endif
 
   // RenderThread may not exist in some tests.
   if (RenderThreadImpl::current()) {
@@ -267,11 +265,28 @@
     web_idb_factory_.reset(new WebIDBFactoryImpl(
         sync_message_filter_,
         RenderThreadImpl::current()->GetIOTaskRunner().get()));
+#if defined(OS_LINUX)
+    font_loader_ = sk_make_sp<font_service::FontLoader>(connector_.get());
+    SkFontConfigInterface::SetGlobal(font_loader_);
+#endif
   } else {
     service_manager::mojom::ConnectorRequest request;
     connector_ = service_manager::Connector::Create(&request);
   }
 
+#if !defined(OS_ANDROID) && !defined(OS_WIN) && !defined(OS_FUCHSIA)
+  if (g_sandbox_enabled && sandboxEnabled()) {
+#if defined(OS_MACOSX)
+    sandbox_support_.reset(new RendererBlinkPlatformImpl::SandboxSupport());
+#else
+    sandbox_support_.reset(
+        new RendererBlinkPlatformImpl::SandboxSupport(font_loader_));
+#endif
+  } else {
+    DVLOG(1) << "Disabling sandbox support for testing.";
+  }
+#endif
+
   blink_interface_provider_.reset(
       new BlinkInterfaceProviderImpl(connector_.get()));
   top_level_blame_context_.Initialize();
@@ -592,8 +607,8 @@
     return;
   }
 
-  content::GetFallbackFontForCharacter(character, preferred_locale,
-                                       fallbackFont);
+  content::GetFallbackFontForCharacter(font_loader_, character,
+                                       preferred_locale, fallbackFont);
   unicode_font_families_.insert(std::make_pair(character, *fallbackFont));
 }
 
@@ -604,8 +619,8 @@
     bool is_italic,
     float device_scale_factor,
     blink::WebFontRenderStyle* out) {
-  GetRenderStyleForStrike(family, size, is_bold, is_italic, device_scale_factor,
-                          out);
+  GetRenderStyleForStrike(font_loader_, family, size, is_bold, is_italic,
+                          device_scale_factor, out);
 }
 
 #endif
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 94d5e7b2..a068ebb9 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -29,6 +29,11 @@
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h"
 #include "third_party/blink/public/platform/modules/webdatabase/web_database.mojom.h"
 
+#if defined(OS_LINUX)
+#include "components/services/font/public/cpp/font_loader.h"  // nogncheck
+#include "third_party/skia/include/core/SkRefCnt.h"           // nogncheck
+#endif
+
 namespace IPC {
 class SyncMessageFilter;
 }
@@ -319,6 +324,10 @@
   blink::mojom::WebDatabaseHostPtrInfo web_database_host_info_;
   scoped_refptr<blink::mojom::ThreadSafeWebDatabaseHostPtr> web_database_host_;
 
+#if defined(OS_LINUX)
+  sk_sp<font_service::FontLoader> font_loader_;
+#endif
+
   THREAD_CHECKER(main_thread_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(RendererBlinkPlatformImpl);
diff --git a/content/renderer/renderer_main.cc b/content/renderer/renderer_main.cc
index 30e9f57..0b722923 100644
--- a/content/renderer/renderer_main.cc
+++ b/content/renderer/renderer_main.cc
@@ -43,14 +43,6 @@
 #include "base/android/library_loader/library_loader_hooks.h"
 #endif  // OS_ANDROID
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
-    !defined(OS_FUCHSIA)
-#include "content/common/font_config_ipc_linux.h"
-#include "services/service_manager/sandbox/linux/sandbox_linux.h"
-#include "services/service_manager/zygote/common/common_sandbox_support_linux.h"
-#include "third_party/skia/include/ports/SkFontConfigInterface.h"
-#endif
-
 #if defined(OS_MACOSX)
 #include <Carbon/Carbon.h>
 #include <signal.h>
@@ -121,16 +113,6 @@
   }
 #endif
 
-#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
-    !defined(OS_FUCHSIA)
-  // This call could already have been made from zygote_main_linux.cc. However
-  // we need to do it here if Zygote is disabled.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoZygote)) {
-    SkFontConfigInterface::SetGlobal(
-        sk_make_sp<FontConfigIPC>(service_manager::GetSandboxFD()));
-  }
-#endif
-
   InitializeSkia();
 
   // This function allows pausing execution using the --renderer-startup-dialog
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index b10fed5..5ff5de0 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -55,8 +55,10 @@
                "EmbeddedWorkerInstanceClientImpl::StartWorker");
   auto start_timing = mojom::EmbeddedWorkerStartTiming::New();
   start_timing->start_worker_received_time = base::TimeTicks::Now();
-  service_manager::mojom::InterfaceProviderPtr interface_provider(
-      std::move(params->provider_info->interface_provider));
+  blink::mojom::CacheStoragePtrInfo cache_storage =
+      std::move(params->provider_info->cache_storage);
+  service_manager::mojom::InterfaceProviderPtrInfo interface_provider =
+      std::move(params->provider_info->interface_provider);
 
   auto client = std::make_unique<ServiceWorkerContextClient>(
       params->embedded_worker_id, params->service_worker_version_id,
@@ -77,6 +79,7 @@
       "ServiceWorker.EmbeddedWorkerInstanceClient.StartWorker", metric,
       StartWorkerHistogramEnum::NUM_TYPES);
   wrapper_ = StartWorkerContext(std::move(params), std::move(client),
+                                std::move(cache_storage),
                                 std::move(interface_provider));
 }
 
@@ -133,7 +136,8 @@
 EmbeddedWorkerInstanceClientImpl::StartWorkerContext(
     mojom::EmbeddedWorkerStartParamsPtr params,
     std::unique_ptr<ServiceWorkerContextClient> context_client,
-    service_manager::mojom::InterfaceProviderPtr interface_provider) {
+    blink::mojom::CacheStoragePtrInfo cache_storage,
+    service_manager::mojom::InterfaceProviderPtrInfo interface_provider) {
   std::unique_ptr<blink::WebServiceWorkerInstalledScriptsManager> manager;
   // |installed_scripts_info| is null if scripts should be served by net layer,
   // when the worker is not installed, or the worker is launched for checking
@@ -147,7 +151,7 @@
       std::make_unique<WorkerWrapper>(blink::WebEmbeddedWorker::Create(
           std::move(context_client), std::move(manager),
           params->content_settings_proxy.PassHandle(),
-          interface_provider.PassInterface().PassHandle()));
+          cache_storage.PassHandle(), interface_provider.PassHandle()));
 
   blink::WebEmbeddedWorkerStartData start_data;
   start_data.script_url = params->script_url;
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.h b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
index 8d24349..6c942b7 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.h
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.h
@@ -101,7 +101,8 @@
   std::unique_ptr<WorkerWrapper> StartWorkerContext(
       mojom::EmbeddedWorkerStartParamsPtr params,
       std::unique_ptr<ServiceWorkerContextClient> context_client,
-      service_manager::mojom::InterfaceProviderPtr interface_provider);
+      blink::mojom::CacheStoragePtrInfo cache_storage,
+      service_manager::mojom::InterfaceProviderPtrInfo interface_provider);
 
   mojo::Binding<mojom::EmbeddedWorkerInstanceClient> binding_;
 
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 4ca446be..ab42e81 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -352,6 +352,10 @@
     ]
   }
 
+  if (is_linux && !is_android) {
+    deps += [ "//components/services/font:lib" ]
+  }
+
   if (use_x11) {
     # Some tests rely on this tool at runtime. Note: it might be better if
     # the tests that needed it had this as a dep instead of adding it here.
@@ -892,6 +896,10 @@
 service_manifest("content_shell_packaged_services_manifest_overlay") {
   source = "//content/shell/browser/content_shell_packaged_services_manifest_overlay.json"
   packaged_services = [ "//services/test/echo:manifest" ]
+
+  if (is_linux && !is_android) {
+    packaged_services += [ "//components/services/font:manifest" ]
+  }
 }
 
 group("content_shell_crash_test") {
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 2a7e3b5..904da49b 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -65,6 +65,11 @@
 #include "content/public/common/content_descriptors.h"
 #endif
 
+#if defined(OS_LINUX)
+#include "components/services/font/font_service_app.h"  // nogncheck
+#include "components/services/font/public/interfaces/constants.mojom.h"  // nogncheck
+#endif
+
 #if defined(OS_WIN)
 #include "sandbox/win/src/sandbox.h"
 #include "services/service_manager/sandbox/win/sandbox_win.h"
@@ -227,6 +232,10 @@
       base::BindRepeating(&base::ASCIIToUTF16, "Test Service");
   (*services)[echo::mojom::kServiceName] =
       base::BindRepeating(&base::ASCIIToUTF16, "Echo Service");
+#if defined(OS_LINUX)
+  (*services)[font_service::mojom::kServiceName] =
+      base::BindRepeating(&base::ASCIIToUTF16, "Font Service");
+#endif
 }
 
 bool ShellContentBrowserClient::ShouldTerminateOnServiceQuit(
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 5648249a..10e7cf3 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1058,10 +1058,7 @@
   }
 
   if (is_linux) {
-    sources += [
-      "../browser/linux_ipc_browsertest.cc",
-      "../zygote/zygote_browsertest.cc",
-    ]
+    sources += [ "../zygote/zygote_browsertest.cc" ]
     deps += [ "//ui/gfx:test_support" ]
   }
 
diff --git a/content/utility/BUILD.gn b/content/utility/BUILD.gn
index 610106e..117ae90 100644
--- a/content/utility/BUILD.gn
+++ b/content/utility/BUILD.gn
@@ -68,6 +68,10 @@
       "//media/mojo/services",
     ]
   }
+
+  if (is_linux && !is_android) {
+    deps += [ "//components/services/font:lib" ]
+  }
 }
 
 # See comment at the top of //content/BUILD.gn for how this works.
diff --git a/content/utility/utility_blink_platform_with_sandbox_support_impl.cc b/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
index a3987953..13ab692 100644
--- a/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
+++ b/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
@@ -13,6 +13,8 @@
 #elif defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
 #include "base/synchronization/lock.h"
 #include "content/child/child_process_sandbox_support_impl_linux.h"
+#include "content/child/child_thread_impl.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "third_party/blink/public/platform/linux/web_fallback_font.h"
 #include "third_party/blink/public/platform/linux/web_sandbox_support.h"
 #endif
@@ -30,6 +32,10 @@
 class UtilityBlinkPlatformWithSandboxSupportImpl::SandboxSupport
     : public blink::WebSandboxSupport {
  public:
+#if defined(OS_LINUX)
+  explicit SandboxSupport(sk_sp<font_service::FontLoader> font_loader)
+      : font_loader_(std::move(font_loader)) {}
+#endif
   ~SandboxSupport() override {}
 
 #if defined(OS_MACOSX)
@@ -53,14 +59,20 @@
   base::Lock unicode_font_families_mutex_;
   // Maps unicode chars to their fallback fonts.
   std::map<int32_t, blink::WebFallbackFont> unicode_font_families_;
+  sk_sp<font_service::FontLoader> font_loader_;
 #endif  // defined(OS_MACOSX)
 };
 
 #endif  // defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
 
 UtilityBlinkPlatformWithSandboxSupportImpl::
-    UtilityBlinkPlatformWithSandboxSupportImpl() {
-#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+    UtilityBlinkPlatformWithSandboxSupportImpl(
+        service_manager::Connector* connector) {
+#if defined(OS_LINUX)
+  font_loader_ = sk_make_sp<font_service::FontLoader>(connector);
+  SkFontConfigInterface::SetGlobal(font_loader_);
+  sandbox_support_ = std::make_unique<SandboxSupport>(font_loader_);
+#elif defined(OS_MACOSX)
   sandbox_support_ = std::make_unique<SandboxSupport>();
 #endif
 }
@@ -105,9 +117,8 @@
     fallback_font->is_italic = iter->second.is_italic;
     return;
   }
-
-  content::GetFallbackFontForCharacter(character, preferred_locale,
-                                       fallback_font);
+  content::GetFallbackFontForCharacter(font_loader_, character,
+                                       preferred_locale, fallback_font);
   unicode_font_families_.emplace(character, *fallback_font);
 }
 
@@ -118,8 +129,8 @@
                                    bool is_italic,
                                    float device_scale_factor,
                                    blink::WebFontRenderStyle* out) {
-  GetRenderStyleForStrike(family, size, is_bold, is_italic, device_scale_factor,
-                          out);
+  GetRenderStyleForStrike(font_loader_, family, size, is_bold, is_italic,
+                          device_scale_factor, out);
 }
 
 #endif
diff --git a/content/utility/utility_blink_platform_with_sandbox_support_impl.h b/content/utility/utility_blink_platform_with_sandbox_support_impl.h
index db4236a..bdb6e9e 100644
--- a/content/utility/utility_blink_platform_with_sandbox_support_impl.h
+++ b/content/utility/utility_blink_platform_with_sandbox_support_impl.h
@@ -11,10 +11,19 @@
 #include "build/build_config.h"
 #include "content/utility/utility_blink_platform_impl.h"
 
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+#include "components/services/font/public/cpp/font_loader.h"  // nogncheck
+#include "third_party/skia/include/core/SkRefCnt.h"           // nogncheck
+#endif
+
 namespace blink {
 class WebSandboxSupport;
 }
 
+namespace service_manager {
+class Connector;
+}
+
 namespace content {
 
 // This class extends from UtilityBlinkPlatformImpl with added blink web
@@ -22,7 +31,9 @@
 class UtilityBlinkPlatformWithSandboxSupportImpl
     : public UtilityBlinkPlatformImpl {
  public:
-  UtilityBlinkPlatformWithSandboxSupportImpl();
+  UtilityBlinkPlatformWithSandboxSupportImpl() = delete;
+  explicit UtilityBlinkPlatformWithSandboxSupportImpl(
+      service_manager::Connector*);
   ~UtilityBlinkPlatformWithSandboxSupportImpl() override;
 
   // BlinkPlatformImpl
@@ -33,6 +44,9 @@
   class SandboxSupport;
   std::unique_ptr<SandboxSupport> sandbox_support_;
 #endif
+#if defined(OS_LINUX)
+  sk_sp<font_service::FontLoader> font_loader_;
+#endif
 
   DISALLOW_COPY_AND_ASSIGN(UtilityBlinkPlatformWithSandboxSupportImpl);
 };
diff --git a/content/utility/utility_service_factory.cc b/content/utility/utility_service_factory.cc
index 4d2eb95..2d0a82de 100644
--- a/content/utility/utility_service_factory.cc
+++ b/content/utility/utility_service_factory.cc
@@ -45,6 +45,11 @@
 #endif  // BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
 #endif
 
+#if defined(OS_LINUX)
+#include "components/services/font/font_service_app.h"  // nogncheck
+#include "components/services/font/public/interfaces/constants.mojom.h"  // nogncheck
+#endif
+
 #if defined(OS_WIN)
 #include "sandbox/win/src/sandbox.h"
 
@@ -170,6 +175,14 @@
     services->insert(
         std::make_pair(content::mojom::kNetworkServiceName, network_info));
   }
+
+#if defined(OS_LINUX)
+  service_manager::EmbeddedServiceInfo font_service_info;
+  font_service_info.factory =
+      base::BindRepeating(&font_service::FontServiceApp::CreateService);
+  services->insert(
+      std::make_pair(font_service::mojom::kServiceName, font_service_info));
+#endif
 }
 
 void UtilityServiceFactory::OnServiceQuit() {
diff --git a/content/utility/utility_thread_impl.cc b/content/utility/utility_thread_impl.cc
index 767ee872..65b164f 100644
--- a/content/utility/utility_thread_impl.cc
+++ b/content/utility/utility_thread_impl.cc
@@ -118,7 +118,8 @@
 
   blink_platform_impl_ =
       sandbox_support
-          ? std::make_unique<UtilityBlinkPlatformWithSandboxSupportImpl>()
+          ? std::make_unique<UtilityBlinkPlatformWithSandboxSupportImpl>(
+                GetConnector())
           : std::make_unique<UtilityBlinkPlatformImpl>();
   blink::Platform::Initialize(blink_platform_impl_.get());
 }
diff --git a/docs/linux_sandbox_ipc.md b/docs/linux_sandbox_ipc.md
index 5ff70906..f0555b8 100644
--- a/docs/linux_sandbox_ipc.md
+++ b/docs/linux_sandbox_ipc.md
@@ -4,11 +4,13 @@
 is a lower level system which deals with cases where we need to route requests
 from the bottom of the call stack up into the browser.
 
-The motivating example is Skia, which uses fontconfig to load fonts. In a
-chrooted renderer we cannot access the user's fontcache, nor the font files
-themselves. However, font loading happens when we have called through WebKit,
-through Skia and into the SkFontHost. At this point, we cannot loop back around
-to use the main IPC system.
+The motivating example used to be Skia, which uses fontconfig to load
+fonts. Howvever, the OOP IPC for FontConfig was moved to using Font Service and
+the `components/services/font/public/cpp/font_loader.h` interface.
+
+These days, only the out-of-process localtime implementation as well as
+an OOP call for making a shared memory segment are using the Sandbox IPC
+file-descriptor based system. See `sandbox/linux/services/libc_interceptor.cc`.
 
 Thus we define a small IPC system which doesn't depend on anything but `base`
 and which can make synchronous requests to the browser process.
@@ -36,22 +38,12 @@
 
 Here is a (possibly incomplete) list of endpoints in the renderer:
 
-### fontconfig
+### localtime
 
-As mentioned above, the motivating example of this is dealing with fontconfig
-from a chrooted renderer. We implement our own Skia FontHost, outside of the
-Skia tree, in `skia/ext/SkFontHost_fontconfig**`.
+`content/browser/sandbox_ipc_linux.h` defines HandleLocalTime which is
+implemented in `sandbox/linux/services/libc_interceptor.cc`.
 
-There are two methods used. One for performing a match against the fontconfig
-data and one to return a file descriptor to a font file resulting from one of
-those matches. The only wrinkle is that fontconfig is a single-threaded library
-and it's already used in the browser by GTK itself.
+### Creating a shared memory segment
 
-Thus, we have a couple of options:
-
-1.  Handle the requests on the UI thread in the browser.
-1.  Handle the requests in a separate address space.
-
-The original implementation did the former (handle on UI thread). This turned
-out to be a terrible idea, performance wise, so we now handle the requests on a
-dedicated process.
+`content/browser/sandbox_ipc_linux.h` defines HandleMakeSharedMemorySegment
+which is implemented in `content/browser/sandbox_ipc_linux.cc`.
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index b46aaa83..8debf0c 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -222,6 +222,10 @@
     ]
   }
 
+  if (is_linux) {
+    deps += [ "//components/services/font/public/cpp" ]
+  }
+
   if (is_chromeos) {
     sources += [
       "browser/api/vpn_provider/vpn_service_factory.cc",
diff --git a/extensions/shell/browser/DEPS b/extensions/shell/browser/DEPS
index ac34117..2f55513 100644
--- a/extensions/shell/browser/DEPS
+++ b/extensions/shell/browser/DEPS
@@ -8,6 +8,7 @@
   "+components/network_session_configurator/common",
   "+components/pref_registry",
   "+components/sessions",
+  "+components/services/font",
   "+components/update_client",
   "+components/user_prefs",
   "+components/web_modal",
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc
index c018d0c..fd77420 100644
--- a/extensions/shell/browser/shell_content_browser_client.cc
+++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -8,8 +8,10 @@
 
 #include <utility>
 
+#include "base/bind.h"
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "build/build_config.h"
 #include "components/guest_view/browser/guest_view_message_filter.h"
 #include "components/nacl/common/buildflags.h"
 #include "content/public/browser/browser_main_runner.h"
@@ -56,6 +58,12 @@
 #include "content/public/browser/child_process_data.h"
 #endif
 
+#if defined(OS_LINUX)
+#include "base/strings/utf_string_conversions.h"
+#include "components/services/font/font_service_app.h"  // nogncheck
+#include "components/services/font/public/interfaces/constants.mojom.h"  // nogncheck
+#endif
+
 using base::CommandLine;
 using content::BrowserContext;
 using content::BrowserThread;
@@ -257,6 +265,14 @@
   return throttles;
 }
 
+void ShellContentBrowserClient::RegisterOutOfProcessServices(
+    OutOfProcessServiceMap* services) {
+#if defined(OS_LINUX)
+  (*services)[font_service::mojom::kServiceName] =
+      base::BindRepeating(&base::ASCIIToUTF16, "Font Service");
+#endif
+}
+
 std::unique_ptr<content::NavigationUIData>
 ShellContentBrowserClient::GetNavigationUIData(
     content::NavigationHandle* navigation_handle) {
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h
index 3be19c9..3bb45208 100644
--- a/extensions/shell/browser/shell_content_browser_client.h
+++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -64,6 +64,7 @@
   std::vector<std::unique_ptr<content::NavigationThrottle>>
   CreateThrottlesForNavigation(
       content::NavigationHandle* navigation_handle) override;
+  void RegisterOutOfProcessServices(OutOfProcessServiceMap* services) override;
   std::unique_ptr<content::NavigationUIData> GetNavigationUIData(
       content::NavigationHandle* navigation_handle) override;
   void RegisterNonNetworkNavigationURLLoaderFactories(
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index e926a3e..204456cc 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -663,4 +663,50 @@
 
     libfuzzer_options = [ "max_len=16384" ]
   }
+
+  fuzzer_test("gpu_raster_swiftshader_fuzzer") {
+    sources = [
+      "command_buffer/tests/fuzzer_main.cc",
+    ]
+
+    defines = [
+      "GPU_FUZZER_USE_RASTER_DECODER",
+      "GPU_FUZZER_USE_SWIFTSHADER",
+    ]
+
+    deps = [
+      ":gles2",
+      ":gpu",
+      "//base",
+      "//base/third_party/dynamic_annotations",
+      "//ui/gfx/geometry",
+      "//ui/gl",
+      "//ui/gl:test_support",
+    ]
+
+    libfuzzer_options = [ "max_len=16384" ]
+  }
+
+  fuzzer_test("gpu_raster_angle_fuzzer") {
+    sources = [
+      "command_buffer/tests/fuzzer_main.cc",
+    ]
+
+    defines = [
+      "GPU_FUZZER_USE_RASTER_DECODER",
+      "GPU_FUZZER_USE_ANGLE",
+    ]
+
+    deps = [
+      ":gles2",
+      ":gpu",
+      "//base",
+      "//base/third_party/dynamic_annotations",
+      "//ui/gfx/geometry",
+      "//ui/gl",
+      "//ui/gl:test_support",
+    ]
+
+    libfuzzer_options = [ "max_len=16384" ]
+  }
 }
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index a339e25f..7e22f62 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -449,6 +449,10 @@
     deps += [ "//components/os_crypt" ]
   }
 
+  if (is_linux) {
+    deps += [ "//components/services/font/public/cpp" ]
+  }
+
   if (is_component_build) {
     sources += [
       "lib/browser/headless_content_browser_client.cc",
@@ -744,6 +748,7 @@
     "public/util/testing/test_in_memory_protocol_handler.h",
     "test/headless_browser_test.cc",
     "test/headless_browser_test.h",
+    "test/headless_client_browsertest.cc",
     "test/headless_protocol_browsertest.cc",
     "test/headless_test_launcher.cc",
     "test/test_protocol_handler.cc",
diff --git a/headless/lib/browser/DEPS b/headless/lib/browser/DEPS
index f20dffe..6552fb8 100644
--- a/headless/lib/browser/DEPS
+++ b/headless/lib/browser/DEPS
@@ -3,6 +3,7 @@
   "+components/printing/browser",
   "+components/printing/common",
   "+components/security_state",
+  "+components/services/font",
   "+components/viz",
   "+printing",
   "+storage/browser/quota",
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index b764fc0..715270a 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -13,6 +13,7 @@
 #include "base/json/json_reader.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/client_certificate_delegate.h"
@@ -50,6 +51,11 @@
 #include "components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom.h"
 #endif
 
+#if defined(OS_LINUX)
+#include "components/services/font/font_service_app.h"  // nogncheck
+#include "components/services/font/public/interfaces/constants.mojom.h"  // nogncheck
+#endif
+
 namespace headless {
 
 namespace {
@@ -165,6 +171,10 @@
   (*services)[printing::mojom::kServiceName] =
       base::BindRepeating(&base::ASCIIToUTF16, "PDF Compositor Service");
 #endif
+#if defined(OS_LINUX)
+  (*services)[font_service::mojom::kServiceName] =
+      base::BindRepeating(&base::ASCIIToUTF16, "Font Service");
+#endif
 }
 
 std::unique_ptr<base::Value>
diff --git a/headless/lib/browser/headless_devtools_client_impl.cc b/headless/lib/browser/headless_devtools_client_impl.cc
index 05da6bf7..313c464b 100644
--- a/headless/lib/browser/headless_devtools_client_impl.cc
+++ b/headless/lib/browser/headless_devtools_client_impl.cc
@@ -16,6 +16,11 @@
 
 namespace headless {
 
+namespace {
+int g_next_message_id = 0;
+int g_next_raw_message_id = 1;
+}  // namespace
+
 // static
 std::unique_ptr<HeadlessDevToolsClient> HeadlessDevToolsClient::Create() {
   auto result = std::make_unique<HeadlessDevToolsClientImpl>();
@@ -67,7 +72,10 @@
       tracing_domain_(this),
       weak_ptr_factory_(this) {}
 
-HeadlessDevToolsClientImpl::~HeadlessDevToolsClientImpl() = default;
+HeadlessDevToolsClientImpl::~HeadlessDevToolsClientImpl() {
+  if (parent_client_)
+    parent_client_->sessions_.erase(session_id_);
+};
 
 void HeadlessDevToolsClientImpl::AttachToExternalHost(
     ExternalHost* external_host) {
@@ -102,35 +110,34 @@
   raw_protocol_listener_ = raw_protocol_listener;
 }
 
+std::unique_ptr<HeadlessDevToolsClient>
+HeadlessDevToolsClientImpl::CreateSession(const std::string& session_id) {
+  std::unique_ptr<HeadlessDevToolsClientImpl> client =
+      std::make_unique<HeadlessDevToolsClientImpl>();
+  client->parent_client_ = this;
+  client->session_id_ = session_id;
+  sessions_[session_id] = client.get();
+  return client;
+}
+
 int HeadlessDevToolsClientImpl::GetNextRawDevToolsMessageId() {
-  int id = next_raw_message_id_;
-  next_raw_message_id_ += 2;
+  int id = g_next_raw_message_id;
+  g_next_raw_message_id += 2;
   return id;
 }
 
 void HeadlessDevToolsClientImpl::SendRawDevToolsMessage(
     const std::string& json_message) {
-#ifndef NDEBUG
-  std::unique_ptr<base::Value> message =
-      base::JSONReader::Read(json_message, base::JSON_PARSE_RFC);
-  const base::Value* id_value = message->FindKey("id");
-  if (!id_value) {
-    NOTREACHED() << "Badly formed message " << json_message;
+  std::unique_ptr<base::Value> message = base::JSONReader::Read(json_message);
+  if (!message->is_dict()) {
+    LOG(ERROR) << "Malformed raw message";
     return;
   }
-#endif
-  DCHECK(channel_ || external_host_);
-  if (channel_)
-    channel_->SendProtocolMessage(json_message);
-  else
-    external_host_->SendProtocolMessage(json_message);
-}
-
-void HeadlessDevToolsClientImpl::SendRawDevToolsMessage(
-    const base::DictionaryValue& message) {
-  std::string json_message;
-  base::JSONWriter::Write(message, &json_message);
-  SendRawDevToolsMessage(json_message);
+  std::unique_ptr<base::DictionaryValue> dict =
+      base::DictionaryValue::From(std::move(message));
+  if (!session_id_.empty())
+    dict->SetString("sessionId", session_id_);
+  SendProtocolMessage(dict.get());
 }
 
 void HeadlessDevToolsClientImpl::DispatchMessageFromExternalHost(
@@ -141,8 +148,30 @@
 
 void HeadlessDevToolsClientImpl::ReceiveProtocolMessage(
     const std::string& json_message) {
+  // LOG(ERROR) << "[RECV] " << json_message;
   std::unique_ptr<base::Value> message =
       base::JSONReader::Read(json_message, base::JSON_PARSE_RFC);
+  if (!message || !message->is_dict()) {
+    NOTREACHED() << "Badly formed reply " << json_message;
+    return;
+  }
+  std::unique_ptr<base::DictionaryValue> message_dict =
+      base::DictionaryValue::From(std::move(message));
+
+  std::string session_id;
+  if (message_dict->GetString("sessionId", &session_id)) {
+    auto it = sessions_.find(session_id);
+    if (it != sessions_.end()) {
+      it->second->ReceiveProtocolMessage(json_message, std::move(message_dict));
+      return;
+    }
+  }
+  ReceiveProtocolMessage(json_message, std::move(message_dict));
+}
+
+void HeadlessDevToolsClientImpl::ReceiveProtocolMessage(
+    const std::string& json_message,
+    std::unique_ptr<base::DictionaryValue> message) {
   const base::DictionaryValue* message_dict;
   if (!message || !message->GetAsDictionary(&message_dict)) {
     NOTREACHED() << "Badly formed reply " << json_message;
@@ -415,13 +444,25 @@
     CallbackType callback) {
   if (renderer_crashed_)
     return;
-  DCHECK(channel_ || external_host_);
-  int id = next_message_id_;
-  next_message_id_ += 2;  // We only send even numbered messages.
+  int id = g_next_message_id;
+  g_next_message_id += 2;  // We only send even numbered messages.
   message->SetInteger("id", id);
+  if (!session_id_.empty())
+    message->SetString("sessionId", session_id_);
+  pending_messages_[id] = Callback(std::move(callback));
+  SendProtocolMessage(message);
+}
+
+void HeadlessDevToolsClientImpl::SendProtocolMessage(
+    const base::DictionaryValue* message) {
+  if (parent_client_) {
+    parent_client_->SendProtocolMessage(message);
+    return;
+  }
+
   std::string json_message;
   base::JSONWriter::Write(*message, &json_message);
-  pending_messages_[id] = Callback(std::move(callback));
+  // LOG(ERROR) << "[SEND] " << json_message;
   if (channel_)
     channel_->SendProtocolMessage(json_message);
   else
diff --git a/headless/lib/headless_devtools_client_browsertest.cc b/headless/lib/headless_devtools_client_browsertest.cc
index fa62bbce..02cc620 100644
--- a/headless/lib/headless_devtools_client_browsertest.cc
+++ b/headless/lib/headless_devtools_client_browsertest.cc
@@ -1170,7 +1170,9 @@
     std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
     params->SetString("expression", "1+1");
     message.Set("params", std::move(params));
-    devtools_client_->SendRawDevToolsMessage(message);
+    std::string json_message;
+    base::JSONWriter::Write(message, &json_message);
+    devtools_client_->SendRawDevToolsMessage(json_message);
   }
 
   bool OnProtocolMessage(const std::string& json_message,
diff --git a/headless/public/headless_devtools_client.h b/headless/public/headless_devtools_client.h
index 055f8d51..350ffd5 100644
--- a/headless/public/headless_devtools_client.h
+++ b/headless/public/headless_devtools_client.h
@@ -198,12 +198,14 @@
   virtual void SetRawProtocolListener(
       RawProtocolListener* raw_protocol_listener) = 0;
 
+  virtual std::unique_ptr<HeadlessDevToolsClient> CreateSession(
+      const std::string& session_id) = 0;
+
   // Generates an odd numbered ID.
   virtual int GetNextRawDevToolsMessageId() = 0;
 
   // The id within the message must be odd to prevent collisions.
   virtual void SendRawDevToolsMessage(const std::string& json_message) = 0;
-  virtual void SendRawDevToolsMessage(const base::DictionaryValue& message) = 0;
 
   // TODO(dgozman): remove this method together with ExternalHost.
   virtual void DispatchMessageFromExternalHost(
diff --git a/headless/public/internal/headless_devtools_client_impl.h b/headless/public/internal/headless_devtools_client_impl.h
index 3708182b..cba1a53 100644
--- a/headless/public/internal/headless_devtools_client_impl.h
+++ b/headless/public/internal/headless_devtools_client_impl.h
@@ -7,6 +7,7 @@
 
 #include <unordered_map>
 
+#include "base/containers/flat_map.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
 #include "headless/public/devtools/domains/accessibility.h"
@@ -96,9 +97,10 @@
   tracing::Domain* GetTracing() override;
   void SetRawProtocolListener(
       RawProtocolListener* raw_protocol_listener) override;
+  std::unique_ptr<HeadlessDevToolsClient> CreateSession(
+      const std::string& session_id) override;
   int GetNextRawDevToolsMessageId() override;
   void SendRawDevToolsMessage(const std::string& json_message) override;
-  void SendRawDevToolsMessage(const base::DictionaryValue& message) override;
   void DispatchMessageFromExternalHost(
       const std::string& json_message) override;
   void AttachToChannel(
@@ -170,15 +172,19 @@
                          const EventHandler* event_handler,
                          const base::DictionaryValue* result_dict);
 
+  void ReceiveProtocolMessage(const std::string& json_message,
+                              std::unique_ptr<base::DictionaryValue> message);
+  void SendProtocolMessage(const base::DictionaryValue* message);
+
   std::unique_ptr<HeadlessDevToolsChannel> channel_;
   ExternalHost* external_host_ = nullptr;
   RawProtocolListener* raw_protocol_listener_ = nullptr;
 
-  int next_message_id_ = 0;
-  int next_raw_message_id_ = 1;
   std::unordered_map<int, Callback> pending_messages_;
   EventHandlerMap event_handlers_;
-
+  std::string session_id_;
+  HeadlessDevToolsClientImpl* parent_client_ = nullptr;
+  base::flat_map<std::string, HeadlessDevToolsClientImpl*> sessions_;
   bool renderer_crashed_ = false;
 
   accessibility::ExperimentalDomain accessibility_domain_;
diff --git a/headless/test/headless_client_browsertest.cc b/headless/test/headless_client_browsertest.cc
new file mode 100644
index 0000000..4f8fd0b
--- /dev/null
+++ b/headless/test/headless_client_browsertest.cc
@@ -0,0 +1,68 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <memory>
+
+#include "build/build_config.h"
+#include "content/public/test/browser_test.h"
+#include "headless/public/devtools/domains/runtime.h"
+#include "headless/public/devtools/domains/target.h"
+#include "headless/public/headless_devtools_client.h"
+#include "headless/test/headless_browser_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace headless {
+
+class HeadlessClientBrowserTest : public HeadlessAsyncDevTooledBrowserTest,
+                                  public target::ExperimentalObserver {
+ public:
+  HeadlessClientBrowserTest() = default;
+
+ private:
+  // HeadlessWebContentsObserver implementation.
+  void RunDevTooledTest() override {
+    browser_devtools_client_->GetTarget()->GetExperimental()->AddObserver(this);
+    browser_devtools_client_->GetTarget()->CreateTarget(
+        target::CreateTargetParams::Builder().SetUrl("about:blank").Build(),
+        base::BindOnce(&HeadlessClientBrowserTest::AttachToTarget,
+                       base::Unretained(this)));
+  }
+
+  void AttachToTarget(std::unique_ptr<target::CreateTargetResult> result) {
+    browser_devtools_client_->GetTarget()->AttachToTarget(
+        target::AttachToTargetParams::Builder()
+            .SetTargetId(result->GetTargetId())
+            .SetFlatten(true)
+            .Build(),
+        base::BindOnce(&HeadlessClientBrowserTest::CreateSession,
+                       base::Unretained(this)));
+  }
+
+  void CreateSession(std::unique_ptr<target::AttachToTargetResult> result) {
+    session_client_ =
+        browser_devtools_client_->CreateSession(result->GetSessionId());
+    session_client_->GetRuntime()->Evaluate(
+        "window.location.href",
+        base::BindOnce(&HeadlessClientBrowserTest::FinishTest,
+                       base::Unretained(this)));
+  }
+
+  void FinishTest(std::unique_ptr<runtime::EvaluateResult> result) {
+    const base::Value* value = result->GetResult()->GetValue();
+    std::string str;
+    EXPECT_TRUE(value->GetAsString(&str));
+    EXPECT_EQ("about:blank", str);
+    session_client_.reset();
+    FinishAsynchronousTest();
+  }
+
+ private:
+  std::unique_ptr<HeadlessDevToolsClient> session_client_;
+};
+
+IN_PROC_BROWSER_TEST_F(HeadlessClientBrowserTest, FlatProtocolAccess) {
+  RunTest();
+}
+
+}  // namespace headless
diff --git a/ios/chrome/browser/consent_auditor/consent_auditor_factory.cc b/ios/chrome/browser/consent_auditor/consent_auditor_factory.cc
index e9dc3ea..3a5cdcf 100644
--- a/ios/chrome/browser/consent_auditor/consent_auditor_factory.cc
+++ b/ios/chrome/browser/consent_auditor/consent_auditor_factory.cc
@@ -57,12 +57,9 @@
     web::BrowserState* browser_state) const {
   ios::ChromeBrowserState* ios_browser_state =
       ios::ChromeBrowserState::FromBrowserState(browser_state);
-  // TODO(crbug.com/851438): Don't create user event service at all if it is not
-  // needed.
-  syncer::UserEventService* const user_event_service =
-      IOSUserEventServiceFactory::GetForBrowserState(ios_browser_state);
 
-  std::unique_ptr<syncer::ConsentSyncBridge> bridge;
+  std::unique_ptr<syncer::ConsentSyncBridge> consent_sync_bridge;
+  syncer::UserEventService* user_event_service = nullptr;
   if (base::FeatureList::IsEnabled(switches::kSyncUserConsentSeparateType)) {
     syncer::OnceModelTypeStoreFactory store_factory =
         browser_sync::ProfileSyncService::GetModelTypeStoreFactory(
@@ -72,12 +69,16 @@
             syncer::USER_CONSENTS,
             base::BindRepeating(&syncer::ReportUnrecoverableError,
                                 ::GetChannel()));
-    bridge = std::make_unique<syncer::ConsentSyncBridgeImpl>(
+    consent_sync_bridge = std::make_unique<syncer::ConsentSyncBridgeImpl>(
         std::move(store_factory), std::move(change_processor));
+  } else {
+    user_event_service =
+        IOSUserEventServiceFactory::GetForBrowserState(ios_browser_state);
   }
 
   return std::make_unique<consent_auditor::ConsentAuditor>(
-      ios_browser_state->GetPrefs(), std::move(bridge), user_event_service,
+      ios_browser_state->GetPrefs(), std::move(consent_sync_bridge),
+      user_event_service,
       // The browser version and locale do not change runtime, so we can pass
       // them directly.
       version_info::GetVersionNumber(),
diff --git a/ios/chrome/browser/ui/autofill/BUILD.gn b/ios/chrome/browser/ui/autofill/BUILD.gn
index e39f6bc..1213a1c 100644
--- a/ios/chrome/browser/ui/autofill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/BUILD.gn
@@ -11,8 +11,6 @@
     "card_unmask_prompt_view_bridge.mm",
     "chrome_autofill_client_ios.h",
     "chrome_autofill_client_ios.mm",
-    "storage_switch_tooltip.h",
-    "storage_switch_tooltip.mm",
   ]
   deps = [
     ":autofill_ui",
diff --git a/ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm b/ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm
index 5a0420e..180ab8e 100644
--- a/ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm
+++ b/ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm
@@ -14,16 +14,16 @@
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/autofill/cells/cvc_item.h"
 #import "ios/chrome/browser/ui/autofill/cells/status_item.h"
-#import "ios/chrome/browser/ui/autofill/cells/storage_switch_item.h"
-#import "ios/chrome/browser/ui/autofill/storage_switch_tooltip.h"
 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.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)
@@ -126,12 +126,7 @@
   UIBarButtonItem* _verifyButton;
   CVCItem* _CVCItem;
   StatusItem* _statusItem;
-  StorageSwitchItem* _storageSwitchItem;
-
-  // The tooltip is added as a child of the collection view rather than the
-  // StorageSwitchContentView to allow it to overflow the bounds of the switch
-  // view.
-  StorageSwitchTooltip* _storageSwitchTooltip;
+  CollectionViewSwitchItem* _storageSwitchItem;
 
   // Owns |self|.
   autofill::CardUnmaskPromptViewBridge* _bridge;  // weak
@@ -222,14 +217,12 @@
 
   if (controller->CanStoreLocally()) {
     _storageSwitchItem =
-        [[StorageSwitchItem alloc] initWithType:ItemTypeStorageSwitch];
+        [[CollectionViewSwitchItem alloc] initWithType:ItemTypeStorageSwitch];
+    _storageSwitchItem.text = l10n_util::GetNSString(
+        IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_CHECKBOX);
     _storageSwitchItem.on = controller->GetStoreLocallyStartState();
     [model addItem:_storageSwitchItem
         toSectionWithIdentifier:SectionIdentifierMain];
-
-    _storageSwitchTooltip = [[StorageSwitchTooltip alloc] init];
-    [_storageSwitchTooltip setHidden:YES];
-    [self.collectionView addSubview:_storageSwitchTooltip];
   } else {
     _storageSwitchItem = nil;
   }
@@ -268,7 +261,6 @@
 
 - (void)showSpinner {
   [_verifyButton setEnabled:NO];
-  [_storageSwitchTooltip setHidden:YES];
 
   [self
       updateWithStatus:StatusItemState::VERIFYING
@@ -335,31 +327,6 @@
              preferredHeightForStatus);
 }
 
-- (void)layoutTooltipFromButton:(UIButton*)button {
-  const CGRect buttonFrameInCollectionView =
-      [self.collectionView convertRect:button.bounds fromView:button];
-  CGRect tooltipFrame = _storageSwitchTooltip.frame;
-
-  // First, set the width and use sizeToFit to have the label flow the text and
-  // set the height appropriately.
-  const CGFloat kTooltipMargin = 8;
-  CGFloat availableWidth =
-      CGRectGetMinX(buttonFrameInCollectionView) - 2 * kTooltipMargin;
-  const CGFloat kMaxTooltipWidth = 210;
-  tooltipFrame.size.width = MIN(availableWidth, kMaxTooltipWidth);
-  _storageSwitchTooltip.frame = tooltipFrame;
-  [_storageSwitchTooltip sizeToFit];
-
-  // Then use the size to position the tooltip appropriately, based on the
-  // button position.
-  tooltipFrame = _storageSwitchTooltip.frame;
-  tooltipFrame.origin.x = CGRectGetMinX(buttonFrameInCollectionView) -
-                          kTooltipMargin - CGRectGetWidth(tooltipFrame);
-  tooltipFrame.origin.y = CGRectGetMaxY(buttonFrameInCollectionView) -
-                          CGRectGetHeight(tooltipFrame);
-  _storageSwitchTooltip.frame = tooltipFrame;
-}
-
 - (BOOL)inputCVCIsValid:(CVCItem*)item {
   return _bridge->GetController()->InputCvcIsValid(
       base::SysNSStringToUTF16(item.CVCText));
@@ -453,19 +420,6 @@
   _bridge->PerformClose();
 }
 
-- (void)onTooltipButtonTapped:(UIButton*)button {
-  BOOL shouldShowTooltip = !button.selected;
-  button.highlighted = shouldShowTooltip;
-  if (shouldShowTooltip) {
-    button.selected = YES;
-    [self layoutTooltipFromButton:button];
-    [_storageSwitchTooltip setHidden:NO];
-  } else {
-    button.selected = NO;
-    [_storageSwitchTooltip setHidden:YES];
-  }
-}
-
 - (void)onStorageSwitchChanged:(UISwitch*)switchView {
   // Update the item.
   _storageSwitchItem.on = switchView.on;
@@ -565,12 +519,11 @@
       break;
     }
     case ItemTypeStorageSwitch: {
-      StorageSwitchCell* storageSwitchCell =
-          base::mac::ObjCCastStrict<StorageSwitchCell>(cell);
-      [storageSwitchCell.tooltipButton
-                 addTarget:self
-                    action:@selector(onTooltipButtonTapped:)
-          forControlEvents:UIControlEventTouchUpInside];
+      CollectionViewSwitchCell* storageSwitchCell =
+          base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell);
+      storageSwitchCell.textLabel.font = [MDCTypography body2Font];
+      storageSwitchCell.textLabel.textColor =
+          [[MDCPalette greyPalette] tint500];
       [storageSwitchCell.switchView addTarget:self
                                        action:@selector(onStorageSwitchChanged:)
                              forControlEvents:UIControlEventValueChanged];
diff --git a/ios/chrome/browser/ui/autofill/cells/BUILD.gn b/ios/chrome/browser/ui/autofill/cells/BUILD.gn
index 3a01976..5f725dc9d 100644
--- a/ios/chrome/browser/ui/autofill/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/cells/BUILD.gn
@@ -10,8 +10,6 @@
     "cvc_item.mm",
     "status_item.h",
     "status_item.mm",
-    "storage_switch_item.h",
-    "storage_switch_item.mm",
   ]
 
   deps = [
@@ -39,7 +37,6 @@
     "autofill_edit_item_unittest.mm",
     "cvc_item_unittest.mm",
     "status_item_unittest.mm",
-    "storage_switch_item_unittest.mm",
   ]
 
   deps = [
diff --git a/ios/chrome/browser/ui/autofill/cells/storage_switch_item.h b/ios/chrome/browser/ui/autofill/cells/storage_switch_item.h
deleted file mode 100644
index d7a488f..0000000
--- a/ios/chrome/browser/ui/autofill/cells/storage_switch_item.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_AUTOFILL_CELLS_STORAGE_SWITCH_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_AUTOFILL_CELLS_STORAGE_SWITCH_ITEM_H_
-
-#import <UIKit/UIKit.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"
-
-// StorageSwitchItem is the model class corresponding to StorageSwitchCell.
-@interface StorageSwitchItem : CollectionViewItem
-
-// The current state of the switch.
-@property(nonatomic, assign, getter=isOn) BOOL on;
-
-@end
-
-// StorageSwitchCell implements a UICollectionViewCell subclass containing a
-// text label, a switch and a tooltip button.
-@interface StorageSwitchCell : MDCCollectionViewCell
-
-// Label displaying a standard text.
-@property(nonatomic, readonly, strong) UILabel* textLabel;
-
-// The tooltip button. Clients own and manage the tooltip they present and can
-// use the button frame as the anchor point. Otherwise, this button is a no-op.
-@property(nonatomic, readonly, strong) UIButton* tooltipButton;
-
-// The switch view.
-@property(nonatomic, readonly, strong) UISwitch* switchView;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_AUTOFILL_CELLS_STORAGE_SWITCH_ITEM_H_
diff --git a/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm b/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm
deleted file mode 100644
index eb34c2e..0000000
--- a/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm
+++ /dev/null
@@ -1,145 +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/autofill/cells/storage_switch_item.h"
-
-#include "components/grit/components_scaled_resources.h"
-#include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/uikit_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"
-
-#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;
-// Space at the leading side of the tooltip button.
-const CGFloat kTooltipButtonLeadingSpacing = 8;
-// Space at the trailing side of the tooltip button.
-const CGFloat kTooltipButtonTrailingSpacing = 30;
-}
-
-@implementation StorageSwitchItem
-
-@synthesize on = _on;
-
-- (instancetype)initWithType:(NSInteger)type {
-  self = [super initWithType:type];
-  if (self) {
-    self.cellClass = [StorageSwitchCell class];
-  }
-  return self;
-}
-
-#pragma mark CollectionViewItem
-
-- (void)configureCell:(StorageSwitchCell*)cell {
-  [super configureCell:cell];
-  cell.switchView.on = self.on;
-}
-
-@end
-
-@implementation StorageSwitchCell
-
-@synthesize textLabel = _textLabel;
-@synthesize tooltipButton = _tooltipButton;
-@synthesize switchView = _switchView;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    UIView* contentView = self.contentView;
-
-    _textLabel = [[UILabel alloc] init];
-    _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
-    [contentView addSubview:_textLabel];
-
-    _switchView = [[UISwitch alloc] init];
-    _switchView.translatesAutoresizingMaskIntoConstraints = NO;
-    [contentView addSubview:_switchView];
-
-    _tooltipButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    _tooltipButton.translatesAutoresizingMaskIntoConstraints = NO;
-    [contentView addSubview:_tooltipButton];
-
-    _textLabel.text = l10n_util::GetNSString(
-        IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_CHECKBOX);
-    _textLabel.font = [[MDCTypography fontLoader] mediumFontOfSize:14];
-    _textLabel.textColor = [[MDCPalette greyPalette] tint500];
-    _textLabel.numberOfLines = 0;
-    [_textLabel
-        setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
-                                        forAxis:
-                                            UILayoutConstraintAxisHorizontal];
-
-    _switchView.onTintColor = [[MDCPalette cr_bluePalette] tint500];
-
-    [_tooltipButton setImage:NativeImage(IDR_AUTOFILL_TOOLTIP_ICON_H)
-                    forState:UIControlStateSelected];
-    [_tooltipButton setImage:NativeImage(IDR_AUTOFILL_TOOLTIP_ICON)
-                    forState:UIControlStateNormal];
-
-    // Set up the constraints.
-    [NSLayoutConstraint activateConstraints:@[
-      [_textLabel.topAnchor constraintEqualToAnchor:contentView.topAnchor
-                                           constant:kVerticalPadding],
-      [_textLabel.bottomAnchor constraintEqualToAnchor:contentView.bottomAnchor
-                                              constant:-kVerticalPadding],
-      [_textLabel.leadingAnchor
-          constraintEqualToAnchor:contentView.leadingAnchor
-                         constant:kHorizontalPadding],
-      [_textLabel.trailingAnchor
-          constraintLessThanOrEqualToAnchor:_tooltipButton.leadingAnchor
-                                   constant:-kTooltipButtonLeadingSpacing],
-      [_tooltipButton.centerYAnchor
-          constraintEqualToAnchor:contentView.centerYAnchor],
-      [_tooltipButton.trailingAnchor
-          constraintEqualToAnchor:_switchView.leadingAnchor
-                         constant:-kTooltipButtonTrailingSpacing],
-      [_switchView.centerYAnchor
-          constraintEqualToAnchor:contentView.centerYAnchor],
-      [_switchView.trailingAnchor
-          constraintEqualToAnchor:contentView.trailingAnchor
-                         constant:-kHorizontalPadding],
-    ]];
-  }
-  return self;
-}
-
-// Implement -layoutSubviews as per instructions in documentation for
-// +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:].
-- (void)layoutSubviews {
-  [super layoutSubviews];
-
-  // Adjust the text label preferredMaxLayoutWidth when the parent's width
-  // changes, for instance on screen rotation.
-  self.textLabel.preferredMaxLayoutWidth =
-      CGRectGetWidth(self.contentView.frame) - 2 * kHorizontalPadding -
-      kTooltipButtonLeadingSpacing - CGRectGetWidth(self.tooltipButton.frame) -
-      kTooltipButtonTrailingSpacing - CGRectGetWidth(self.switchView.frame);
-
-  // Re-layout with the new preferred width to allow the label to adjust its
-  // height.
-  [super layoutSubviews];
-}
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  [self.tooltipButton removeTarget:nil
-                            action:nil
-                  forControlEvents:self.tooltipButton.allControlEvents];
-  [self.switchView removeTarget:nil
-                         action:nil
-               forControlEvents:self.switchView.allControlEvents];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/autofill/cells/storage_switch_item_unittest.mm b/ios/chrome/browser/ui/autofill/cells/storage_switch_item_unittest.mm
deleted file mode 100644
index d311112..0000000
--- a/ios/chrome/browser/ui/autofill/cells/storage_switch_item_unittest.mm
+++ /dev/null
@@ -1,59 +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/autofill/cells/storage_switch_item.h"
-
-#include "base/mac/foundation_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-using StorageSwitchItemTest = PlatformTest;
-
-// Tests that the label and switch values are set properly after a call to
-// |configureCell:|.
-TEST_F(StorageSwitchItemTest, ConfigureCell) {
-  StorageSwitchItem* item = [[StorageSwitchItem alloc] initWithType:0];
-  item.on = YES;
-
-  id cell = [[[item cellClass] alloc] init];
-  ASSERT_TRUE([cell isMemberOfClass:[StorageSwitchCell class]]);
-
-  StorageSwitchCell* switchCell =
-      base::mac::ObjCCastStrict<StorageSwitchCell>(cell);
-  EXPECT_TRUE(switchCell.textLabel.text);
-  EXPECT_FALSE(switchCell.switchView.on);
-
-  [item configureCell:cell];
-  EXPECT_TRUE(switchCell.switchView.on);
-}
-
-TEST_F(StorageSwitchItemTest, PrepareForReuseClearsActions) {
-  StorageSwitchCell* cell = [[StorageSwitchCell alloc] init];
-  UIButton* tooltipButton = cell.tooltipButton;
-  UISwitch* switchView = cell.switchView;
-  NSArray* target = [NSArray array];
-
-  EXPECT_EQ(0U, [[tooltipButton allTargets] count]);
-  EXPECT_EQ(0U, [[switchView allTargets] count]);
-  [tooltipButton addTarget:target
-                    action:@selector(count)
-          forControlEvents:UIControlEventTouchUpInside];
-  [switchView addTarget:target
-                 action:@selector(count)
-       forControlEvents:UIControlEventValueChanged];
-  EXPECT_EQ(1U, [[tooltipButton allTargets] count]);
-  EXPECT_EQ(1U, [[switchView allTargets] count]);
-
-  [cell prepareForReuse];
-  EXPECT_EQ(0U, [[tooltipButton allTargets] count]);
-  EXPECT_EQ(0U, [[switchView allTargets] count]);
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/autofill/storage_switch_tooltip.h b/ios/chrome/browser/ui/autofill/storage_switch_tooltip.h
deleted file mode 100644
index 652cf35c..0000000
--- a/ios/chrome/browser/ui/autofill/storage_switch_tooltip.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_AUTOFILL_STORAGE_SWITCH_TOOLTIP_H_
-#define IOS_CHROME_BROWSER_UI_AUTOFILL_STORAGE_SWITCH_TOOLTIP_H_
-
-#import <UIKit/UIKit.h>
-
-// A label that displays the storage setting tooltip text with appropriate
-// layout and styling.
-@interface StorageSwitchTooltip : UILabel
-
-- (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
-
-- (instancetype)init;
-
-- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_AUTOFILL_STORAGE_SWITCH_TOOLTIP_H_
diff --git a/ios/chrome/browser/ui/autofill/storage_switch_tooltip.mm b/ios/chrome/browser/ui/autofill/storage_switch_tooltip.mm
deleted file mode 100644
index 216034f4..0000000
--- a/ios/chrome/browser/ui/autofill/storage_switch_tooltip.mm
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/autofill/storage_switch_tooltip.h"
-
-#include "base/logging.h"
-#include "components/strings/grit/components_strings.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 {
-
-const CGFloat kCornerRadius = 2.0f;
-const CGFloat kFontSize = 12.0f;
-const CGFloat kInset = 8.0f;
-
-}  // namespace
-
-@implementation StorageSwitchTooltip
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    NSString* tooltipText =
-        l10n_util::GetNSString(IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_TOOLTIP);
-    [self setText:tooltipText];
-    [self setTextColor:[UIColor whiteColor]];
-    [self setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.9]];
-    [[self layer] setCornerRadius:kCornerRadius];
-    [[self layer] setMasksToBounds:YES];
-    [self setFont:[[MDCTypography fontLoader] regularFontOfSize:kFontSize]];
-    [self setNumberOfLines:0];  // Allows multi-line layout.
-  }
-  return self;
-}
-
-- (instancetype)init {
-  return [self initWithFrame:CGRectZero];
-}
-
-- (instancetype)initWithCoder:(NSCoder*)aDecoder {
-  NOTREACHED();
-  return nil;
-}
-
-// The logic in textRectForBounds:limitedToNumberOfLines: and drawTextInRect:
-// adds an inset. Based on
-// http://stackoverflow.com/questions/21167226/resizing-a-uilabel-to-accomodate-insets/21267507#21267507
-- (CGRect)textRectForBounds:(CGRect)bounds
-     limitedToNumberOfLines:(NSInteger)numberOfLines {
-  UIEdgeInsets insets = {kInset, kInset, kInset, kInset};
-  CGRect rect = [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, insets)
-                  limitedToNumberOfLines:numberOfLines];
-
-  rect.origin.x -= insets.left;
-  rect.origin.y -= insets.top;
-  rect.size.width += (insets.left + insets.right);
-  rect.size.height += (insets.top + insets.bottom);
-
-  return rect;
-}
-
-- (void)drawTextInRect:(CGRect)rect {
-  UIEdgeInsets insets = {kInset, kInset, kInset, kInset};
-  [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm
index 61594f9f..e55887a 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/location_bar/location_bar_legacy_coordinator.h"
+#import "ios/chrome/browser/ui/location_bar/location_bar_coordinator.h"
 
 #include <memory>
 #include <string>
@@ -60,10 +60,9 @@
 
 namespace {
 
-class LocationBarLegacyCoordinatorTest : public PlatformTest {
+class LocationBarCoordinatorTest : public PlatformTest {
  protected:
-  LocationBarLegacyCoordinatorTest()
-      : web_state_list_(&web_state_list_delegate_) {}
+  LocationBarCoordinatorTest() : web_state_list_(&web_state_list_delegate_) {}
 
   void SetUp() override {
     PlatformTest::SetUp();
@@ -87,7 +86,7 @@
     delegate_ = [[TestToolbarCoordinatorDelegate alloc] init];
     url_loader_ = [[FakeURLLoader alloc] init];
 
-    coordinator_ = [[LocationBarLegacyCoordinator alloc] init];
+    coordinator_ = [[LocationBarCoordinator alloc] init];
     coordinator_.browserState = browser_state_.get();
     coordinator_.webStateList = &web_state_list_;
     coordinator_.delegate = delegate_;
@@ -105,7 +104,7 @@
   }
 
   web::TestWebThreadBundle web_thread_bundle_;
-  LocationBarLegacyCoordinator* coordinator_;
+  LocationBarCoordinator* coordinator_;
   std::unique_ptr<TestChromeBrowserState> browser_state_;
   FakeWebStateListDelegate web_state_list_delegate_;
   WebStateList web_state_list_;
@@ -113,7 +112,7 @@
   FakeURLLoader* url_loader_;
 };
 
-TEST_F(LocationBarLegacyCoordinatorTest, Stops) {
+TEST_F(LocationBarCoordinatorTest, Stops) {
   EXPECT_TRUE(coordinator_.view == nil);
   [coordinator_ start];
   EXPECT_TRUE(coordinator_.view != nil);
@@ -124,7 +123,7 @@
 // Calls -loadGURLFromLocationBar:transition: with https://www.google.com/ URL.
 // Verifies that URLLoader receives correct load request, which also includes
 // variations header.
-TEST_F(LocationBarLegacyCoordinatorTest, LoadGoogleUrl) {
+TEST_F(LocationBarCoordinatorTest, LoadGoogleUrl) {
   ASSERT_EQ(VariationsHttpHeaderProvider::ForceIdsResult::SUCCESS,
             VariationsHttpHeaderProvider::GetInstance()->ForceVariationIds(
                 /*variation_ids=*/{"100"}, /*command_line_variation_ids=*/""));
@@ -146,7 +145,7 @@
 // Calls -loadGURLFromLocationBar:transition: with https://www.nongoogle.com/
 // URL. Verifies that URLLoader receives correct load request without variations
 // header.
-TEST_F(LocationBarLegacyCoordinatorTest, LoadNonGoogleUrl) {
+TEST_F(LocationBarCoordinatorTest, LoadNonGoogleUrl) {
   ASSERT_EQ(VariationsHttpHeaderProvider::ForceIdsResult::SUCCESS,
             VariationsHttpHeaderProvider::GetInstance()->ForceVariationIds(
                 /*variation_ids=*/{"100"}, /*command_line_variation_ids=*/""));
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm b/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
index 2b6b53e..c5880686 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_steady_view.mm
@@ -286,7 +286,7 @@
   [self updateAccessibility];
 }
 
-#pragma mark - UIAccessibilityContainer]
+#pragma mark - UIAccessibilityContainer
 
 - (NSArray*)accessibilityElements {
   return self.accessibleElements;
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
index 1e9baf5..e7fdcae 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
@@ -209,8 +209,10 @@
     // Display a fake "placeholder".
     NSString* placeholderString =
         l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT);
-    UIColor* placeholderColor =
-        [LocationBarSteadyViewColorScheme incognitoScheme].placeholderColor;
+    LocationBarSteadyViewColorScheme* scheme =
+        self.incognito ? [LocationBarSteadyViewColorScheme incognitoScheme]
+                       : [LocationBarSteadyViewColorScheme standardScheme];
+    UIColor* placeholderColor = scheme.placeholderColor;
     self.locationBarSteadyView.locationLabel.attributedText = [
         [NSAttributedString alloc]
         initWithString:placeholderString
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.cc b/ios/chrome/browser/ui/omnibox/omnibox_util.cc
index e46b140..42ca1d9 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_util.cc
+++ b/ios/chrome/browser/ui/omnibox/omnibox_util.cc
@@ -122,9 +122,7 @@
       return base::ASCIIToUTF16("location_bar_insecure");
     case security_state::EV_SECURE:
     case security_state::SECURE:
-      return base::ASCIIToUTF16("location_bar_secure");
     case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
-      // TODO(crbug.com/848732): update this icon.
       return base::ASCIIToUTF16("location_bar_secure");
     case security_state::DANGEROUS:
       return base::ASCIIToUTF16("location_bar_dangerous");
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
index 6ee8b069..5f78eab 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -983,6 +983,9 @@
 }
 
 void OmniboxViewIOS::OnSelectedMatchForAppending(const base::string16& str) {
+  // Exit preedit state and append the match. Refocus if necessary.
+  if ([field_ isPreEditing])
+    [field_ exitPreEditState];
   this->SetUserText(str);
   this->FocusOmnibox();
 }
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 c9aeb3d..58be286 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
@@ -18,7 +18,6 @@
 #import "ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h"
 #import "ios/chrome/browser/ui/autofill/cells/cvc_item.h"
 #import "ios/chrome/browser/ui/autofill/cells/status_item.h"
-#import "ios/chrome/browser/ui/autofill/cells/storage_switch_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_account_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_detail_item.h"
@@ -90,7 +89,6 @@
   ItemTypeAutofillDynamicHeight,
   ItemTypeAutofillCVC,
   ItemTypeAutofillStatus,
-  ItemTypeAutofillStorageSwitch,
   ItemTypeAccountControlDynamicHeight,
   ItemTypeFooter,
   ItemTypeContentSuggestions,
@@ -245,8 +243,6 @@
       toSectionWithIdentifier:SectionIdentifierAutofill];
   [model addItem:[self statusItemError]
       toSectionWithIdentifier:SectionIdentifierAutofill];
-  [model addItem:[self storageSwitchItem]
-      toSectionWithIdentifier:SectionIdentifierAutofill];
 
   // Payments cells.
   [model addSectionWithIdentifier:SectionIdentifierPayments];
@@ -367,7 +363,6 @@
     case ItemTypeTextError:
     case ItemTypeAutofillCVC:
     case ItemTypeAutofillStatus:
-    case ItemTypeAutofillStorageSwitch:
     case ItemTypePaymentsDynamicHeight:
     case ItemTypeAutofillDynamicHeight:
     case ItemTypeColdStateSigninPromo:
@@ -427,7 +422,6 @@
       [self.collectionViewModel itemAtIndexPath:indexPath];
   switch (item.type) {
     case ItemTypeApp:
-    case ItemTypeAutofillStorageSwitch:
     case ItemTypeColdStateSigninPromo:
     case ItemTypeSwitchBasic:
     case ItemTypeSwitchDynamicHeight:
@@ -695,13 +689,6 @@
   return item;
 }
 
-- (CollectionViewItem*)storageSwitchItem {
-  StorageSwitchItem* item =
-      [[StorageSwitchItem alloc] initWithType:ItemTypeAutofillStorageSwitch];
-  item.on = YES;
-  return item;
-}
-
 - (CollectionViewFooterItem*)shortFooterItem {
   CollectionViewFooterItem* footerItem =
       [[CollectionViewFooterItem alloc] initWithType:ItemTypeFooter];
diff --git a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
index 3edb1063..b2967cb 100644
--- a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
+++ b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
@@ -99,8 +99,7 @@
 
 // Tests signing in with one account, switching sync account to a second and
 // choosing to keep the browsing data separate during the switch.
-// TODO(crbug.com/854446): Enable after fixing.
-- (void)DISABLED_testSignInSwitchAccountsAndKeepDataSeparate {
+- (void)testSignInSwitchAccountsAndKeepDataSeparate {
   // Set up the fake identities.
   ios::FakeChromeIdentityService* identity_service =
       ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
@@ -137,8 +136,7 @@
 
 // Tests signing in with one account, switching sync account to a second and
 // choosing to import the browsing data during the switch.
-// TODO(crbug.com/854446): Enable after fixing.
-- (void)DISABLED_testSignInSwitchAccountsAndImportData {
+- (void)testSignInSwitchAccountsAndImportData {
   // Set up the fake identities.
   ios::FakeChromeIdentityService* identity_service =
       ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
@@ -176,8 +174,7 @@
 
 // Tests that switching from a managed account to a non-managed account works
 // correctly and displays the expected warnings.
-// TODO(crbug.com/854446): Enable after fixing.
-- (void)DISABLED_testSignInSwitchManagedAccount {
+- (void)testSignInSwitchManagedAccount {
   // Set up the fake identities.
   ios::FakeChromeIdentityService* identity_service =
       ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.h b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.h
index 02208e72..ba89ecb4 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.h
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.h
@@ -30,6 +30,8 @@
 @property(nonatomic, weak) UIImage* icon;
 @property(nonatomic, weak) UIImage* snapshot;
 @property(nonatomic, copy) NSString* title;
+// Fixed (immutable) UI elements that may be referenced in animations.
+@property(nonatomic, readonly, weak) UIView* topBar;
 
 // Returns a cell with the same theme, icon, snapshot, and title as the reciever
 // (but no delegate or identifier) for use in animated transitions.
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm
index 9f734cd..791be92 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_cell.mm
@@ -16,8 +16,9 @@
 #endif
 
 @interface GridCell ()
+// Redeclare TopBar readwrite internally.
+@property(nonatomic, readwrite, weak) UIView* topBar;
 // Visual components of the cell.
-@property(nonatomic, weak) UIView* topBar;
 @property(nonatomic, weak) UIImageView* iconView;
 @property(nonatomic, weak) TopAlignedImageView* snapshotView;
 @property(nonatomic, weak) UILabel* titleLabel;
@@ -36,8 +37,8 @@
 @synthesize icon = _icon;
 @synthesize snapshot = _snapshot;
 @synthesize title = _title;
-// Private properties.
 @synthesize topBar = _topBar;
+// Private properties.
 @synthesize iconView = _iconView;
 @synthesize snapshotView = _snapshotView;
 @synthesize titleLabel = _titleLabel;
@@ -145,6 +146,8 @@
       UIColorFromRGB(kGridCellSnapshotBackgroundColor);
   switch (theme) {
     case GridThemeLight:
+      self.contentView.backgroundColor =
+          UIColorFromRGB(kGridLightThemeCellHeaderColor);
       self.topBar.backgroundColor =
           UIColorFromRGB(kGridLightThemeCellHeaderColor);
       self.titleLabel.textColor = UIColorFromRGB(kGridLightThemeCellTitleColor);
@@ -154,6 +157,8 @@
           UIColorFromRGB(kGridLightThemeCellSelectionColor).CGColor;
       break;
     case GridThemeDark:
+      self.contentView.backgroundColor =
+          UIColorFromRGB(kGridDarkThemeCellHeaderColor);
       self.topBar.backgroundColor =
           UIColorFromRGB(kGridDarkThemeCellHeaderColor);
       self.titleLabel.textColor = UIColorFromRGB(kGridDarkThemeCellTitleColor);
diff --git a/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm
index 0e59d2f..76b1656c 100644
--- a/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/grid/grid_view_controller.mm
@@ -190,7 +190,8 @@
   [self.collectionView layoutIfNeeded];
   NSMutableArray<GridTransitionLayoutItem*>* items =
       [[NSMutableArray alloc] init];
-  GridTransitionLayoutItem* selectedItem;
+  GridTransitionLayoutItem* activeItem;
+  GridTransitionLayoutItem* selectionItem;
   for (NSIndexPath* path in self.collectionView.indexPathsForVisibleItems) {
     GridCell* cell = base::mac::ObjCCastStrict<GridCell>(
         [self.collectionView cellForItemAtIndexPath:path]);
@@ -200,15 +201,24 @@
     // change to the other properties such as center, bounds, etc.
     attributes.frame =
         [self.collectionView convertRect:attributes.frame toView:nil];
+    GridCell* proxyCell = [cell proxyForTransitions];
     GridTransitionLayoutItem* item =
-        [GridTransitionLayoutItem itemWithCell:[cell proxyForTransitions]
+        [GridTransitionLayoutItem itemWithCell:proxyCell
+                                 auxillaryView:proxyCell.topBar
                                     attributes:attributes];
     [items addObject:item];
     if ([cell.itemIdentifier isEqualToString:self.selectedItemID]) {
-      selectedItem = item;
+      activeItem = item;
+
+      selectionItem =
+          [GridTransitionLayoutItem itemWithCell:[cell proxyForTransitions]
+                                   auxillaryView:nil
+                                      attributes:attributes];
     }
   }
-  return [GridTransitionLayout layoutWithItems:items selectedItem:selectedItem];
+  return [GridTransitionLayout layoutWithItems:items
+                                    activeItem:activeItem
+                                 selectionItem:selectionItem];
 }
 
 #pragma mark - UICollectionViewDataSource
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index 12c46b2a7..1fdc2ff5 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -681,36 +681,39 @@
 // interact with the layout system at all.
 - (void)animateToolbarsForAppearance {
   DCHECK(self.transitionCoordinator);
-  // TODO(crbug.com/820410): Tune the timing of these animations.
+  // Set toolbar alphas to 0 prior to animation.
+  self.topToolbar.alpha = 0;
+  self.bottomToolbar.alpha = 0;
 
-  // Capture the current toolbar transforms.
-  CGAffineTransform topToolbarBaseTransform = self.topToolbar.transform;
-  CGAffineTransform bottomToolbarBaseTransform = self.bottomToolbar.transform;
-  // Translate the top toolbar up offscreen by shifting it up by its height.
-  self.topToolbar.transform = CGAffineTransformTranslate(
-      self.topToolbar.transform, /*tx=*/0,
-      /*ty=*/-(self.topToolbar.bounds.size.height * 0.5));
-  // Translate the bottom toolbar down offscreen by shifting it down by its
-  // height.
-  self.bottomToolbar.transform = CGAffineTransformTranslate(
-      self.bottomToolbar.transform, /*tx=*/0,
-      /*ty=*/(self.topToolbar.bounds.size.height * 0.5));
-
-  // Block that restores the toolbar transforms, suitable for using with the
-  // transition coordinator.
+  // Fade the toolbars in for the last 60% of the transition.
+  auto keyframe = ^{
+    [UIView addKeyframeWithRelativeStartTime:0.4
+                            relativeDuration:0.6
+                                  animations:^{
+                                    self.topToolbar.alpha = 1.0;
+                                    self.bottomToolbar.alpha = 1.0;
+                                  }];
+  };
+  // Animation block that does the keyframe animation.
   auto animation = ^(id<UIViewControllerTransitionCoordinatorContext> context) {
-    self.topToolbar.transform = topToolbarBaseTransform;
-    self.bottomToolbar.transform = bottomToolbarBaseTransform;
+    [UIView animateKeyframesWithDuration:context.transitionDuration
+                                   delay:0
+                                 options:UIViewAnimationOptionLayoutSubviews
+                              animations:keyframe
+                              completion:nil];
   };
 
   // Also hide the scroll view (and thus the tab grids) until the transition
-  // completes.
+  // completes. Set the toolbar alpha to 1.0 as part of the completion handler
+  // as well, in case the animation didn't complete.
   self.scrollView.hidden = YES;
   auto cleanup = ^(id<UIViewControllerTransitionCoordinatorContext> context) {
     self.scrollView.hidden = NO;
+    self.topToolbar.alpha = 1.0;
+    self.bottomToolbar.alpha = 1.0;
   };
 
-  // Animate the toolbars into place alongside the current transition.
+  // Animate the toolbar alphas alongside the current transition.
   [self.transitionCoordinator animateAlongsideTransition:animation
                                               completion:cleanup];
 }
@@ -718,38 +721,36 @@
 // Translates the toolbar views offscreen using the transition coordinator.
 - (void)animateToolbarsForDisappearance {
   DCHECK(self.transitionCoordinator);
-  // TODO(crbug.com/820410): Tune the timing of these animations.
 
-  // Capture the current toolbar transforms.
-  CGAffineTransform topToolbarBaseTransform = self.topToolbar.transform;
-  CGAffineTransform bottomToolbarBaseTransform = self.bottomToolbar.transform;
-  // Translate the top toolbar up offscreen by shifting it up by its height.
-  CGAffineTransform topToolbarOffsetTransform = CGAffineTransformTranslate(
-      self.topToolbar.transform, /*tx=*/0,
-      /*ty=*/-(self.topToolbar.bounds.size.height * 0.5));
-  // Translate the bottom toolbar down offscreen by shifting it down by its
-  // height.
-  CGAffineTransform bottomToolbarOffsetTransform = CGAffineTransformTranslate(
-      self.bottomToolbar.transform, /*tx=*/0,
-      /*ty=*/(self.topToolbar.bounds.size.height * 0.5));
+  // Fade the toolbars out in the first 66% of the transition.
+  auto keyframe = ^{
+    [UIView addKeyframeWithRelativeStartTime:0
+                            relativeDuration:0.66
+                                  animations:^{
+                                    self.topToolbar.alpha = 0.0;
+                                    self.bottomToolbar.alpha = 0.0;
+                                  }];
+  };
 
-  // Block that animates the toolbar transforms, suitable for using with the
-  // transition coordinator.
+  // Animation block that does the keyframe animation.
   auto animation = ^(id<UIViewControllerTransitionCoordinatorContext> context) {
-    self.topToolbar.transform = topToolbarOffsetTransform;
-    self.bottomToolbar.transform = bottomToolbarOffsetTransform;
+    [UIView animateKeyframesWithDuration:context.transitionDuration
+                                   delay:0
+                                 options:UIViewAnimationOptionLayoutSubviews
+                              animations:keyframe
+                              completion:nil];
   };
 
   // Hide the scroll view (and thus the tab grids) until the transition
-  // completes.
+  // completes. Restore the toolbar opacity when the transition completes.
   self.scrollView.hidden = YES;
   auto cleanup = ^(id<UIViewControllerTransitionCoordinatorContext> context) {
     self.scrollView.hidden = NO;
-    self.topToolbar.transform = topToolbarBaseTransform;
-    self.bottomToolbar.transform = bottomToolbarBaseTransform;
+    self.topToolbar.alpha = 1.0;
+    self.bottomToolbar.alpha = 1.0;
   };
 
-  // Animate the toolbars into place alongside the current transition.
+  // Animate the toolbar alphas alongside the current transition.
   [self.transitionCoordinator animateAlongsideTransition:animation
                                               completion:cleanup];
 }
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/BUILD.gn b/ios/chrome/browser/ui/tab_grid/transitions/BUILD.gn
index 7337c0f..cdbf4eb 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_grid/transitions/BUILD.gn
@@ -23,5 +23,6 @@
 
   deps = [
     "//base",
+    "//ios/chrome/browser/ui/util",
   ]
 }
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_to_visible_tab_animator.mm b/ios/chrome/browser/ui/tab_grid/transitions/grid_to_visible_tab_animator.mm
index e566b8f..630e6460 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_to_visible_tab_animator.mm
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_to_visible_tab_animator.mm
@@ -5,13 +5,17 @@
 #import "ios/chrome/browser/ui/tab_grid/transitions/grid_to_visible_tab_animator.h"
 
 #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.h"
+#import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h"
 #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_state_providing.h"
+#import "ios/chrome/browser/ui/util/layout_guide_names.h"
+#import "ios/chrome/browser/ui/util/named_guide.h"
+#import "ios/chrome/browser/ui/util/property_animator_group.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@interface GridToVisibleTabAnimator ()<GridTransitionAnimationDelegate>
+@interface GridToVisibleTabAnimator ()
 @property(nonatomic, weak) id<GridTransitionStateProviding> stateProvider;
 // Animation object for this transition.
 @property(nonatomic, strong) GridTransitionAnimation* animation;
@@ -35,7 +39,7 @@
 
 - (NSTimeInterval)transitionDuration:
     (id<UIViewControllerContextTransitioning>)transitionContext {
-  return 0.4;
+  return 0.3;
 }
 
 - (void)animateTransition:
@@ -63,33 +67,45 @@
   GridTransitionLayout* layout =
       [self.stateProvider layoutForTransitionContext:transitionContext];
 
+  // Ask the state provider for the views to use when inserting the animation.
+  UIView* proxyContainer =
+      [self.stateProvider proxyContainerForTransitionContext:transitionContext];
+
+  // Find the rect for the animating tab by getting the content area layout
+  // guide.
+  // Conceptually this transition is presenting a tab (a BVC). However,
+  // currently the BVC instances are themselves contanted within a BVCContainer
+  // view controller. This means that the |presentedView| is not the BVC's
+  // view; rather it's the view of the view controller that contains the BVC.
+  // Unfortunatley, the layout guide needed here is attached to the BVC's view,
+  // which is the first (and only) subview of the BVCContainerViewController's
+  // view.
+  // TODO(crbug.com/860234) Clean up this arrangement.
+  UIView* viewWithNamedGuides = presentedView.subviews[0];
+  CGRect finalRect =
+      [NamedGuide guideWithName:kContentAreaGuide view:viewWithNamedGuides]
+          .layoutFrame;
+  layout.expandedRect =
+      [proxyContainer convertRect:finalRect fromView:viewWithNamedGuides];
+
+  NSTimeInterval duration = [self transitionDuration:transitionContext];
   // Create the animation view and insert it.
   self.animation = [[GridTransitionAnimation alloc]
       initWithLayout:layout
-            delegate:self
+            duration:duration
            direction:GridAnimationDirectionExpanding];
 
-  //   Ask the state provider for the views to use when inserting the animation.
-  UIView* proxyContainer =
-      [self.stateProvider proxyContainerForTransitionContext:transitionContext];
   UIView* viewBehindProxies =
       [self.stateProvider proxyPositionForTransitionContext:transitionContext];
-
   [proxyContainer insertSubview:self.animation aboveSubview:viewBehindProxies];
 
-  NSTimeInterval duration = [self transitionDuration:transitionContext];
-
-  // Fade in the presented view.
-  [UIView animateWithDuration:duration * 0.3
-                        delay:duration * 0.7
-                      options:UIViewAnimationOptionCurveEaseOut
-                   animations:^{
-                     presentedView.alpha = 1.0;
-                   }
-                   completion:nil];
+  [self.animation.animator addCompletion:^(UIViewAnimatingPosition position) {
+    BOOL finished = (position == UIViewAnimatingPositionEnd);
+    [self gridTransitionAnimationDidFinish:finished];
+  }];
 
   // Run the main animation.
-  [self.animation animateWithDuration:duration];
+  [self.animation.animator startAnimation];
 }
 
 - (void)gridTransitionAnimationDidFinish:(BOOL)finished {
@@ -104,6 +120,9 @@
   if (self.transitionContext.transitionWasCancelled) {
     [presentedView removeFromSuperview];
   } else {
+    // TODO(crbug.com/850507): Have the tab view animate itself in alongside
+    // this transition instead of just setting the alpha here.
+    presentedView.alpha = 1;
     [gridView removeFromSuperview];
   }
   // Mark the transition as completed.
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.h b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.h
index 501f683..043b1d6 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.h
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.h
@@ -11,44 +11,36 @@
 
 // The directions the animation can take.
 typedef NS_ENUM(NSUInteger, GridAnimationDirection) {
-  // Moving from the expanded grid down into the regular grid.
+  // Moving from an expanded single tab down into the grid.
   GridAnimationDirectionContracting = 0,
-  // Moving from the regular grid out to the expanded grid.
+  // Moving from the grid out to an expanded single tab.
   GridAnimationDirectionExpanding = 1,
 };
 
-// Delegate for this animation, to be informed about animation events.
-@protocol GridTransitionAnimationDelegate
-// Tell the delegate thet the animation completed. If |finished| is YES, then
-// the animation was able to run its full duration.
-- (void)gridTransitionAnimationDidFinish:(BOOL)finished;
-@end
-
 // A view that encapsulates an animation used to transition into a grid.
 // A transition animator should place this view at the appropriate place in the
-// view hierarchy and then call -animateWithDuration: to trigger the animations.
-// TODO(crbug.com/804539): Update this class to be an  Orchestrator object
-// that the present and dismiss animations can both use.
+// view hierarchy and then call |-beginAnimations| on its |animator| property.
 @interface GridTransitionAnimation : UIView
 
+// The animator object this animation uses; it will have the same duration
+// that this object is initialized with.
+// This property is |nil| until this object is added to a view hierarchy. Any
+// animations or callbacks added to |animator| must be added *after* this object
+// is added as a subview of another view.
+@property(nonatomic, readonly) id<UIViewImplicitlyAnimating> animator;
+
 // Designated initializer. |layout| is a GridTransitionLayout object defining
 // the layout the animation should animate to. |delegate| is an object that will
-// be informed about events in this object's animation.
-// If |startsExpanded| is YES, the animation will start with the grid cells in
-// the expanded position and zoom down to the regular grid position. Otherwise
-// they will start in the grid position and zoom out to the expanded positions.
+// be informed about events in this object's animation. |direction| is the
+// direction that the transition will animate.
 - (instancetype)initWithLayout:(GridTransitionLayout*)layout
-                      delegate:(id<GridTransitionAnimationDelegate>)delegate
+                      duration:(NSTimeInterval)duration
                      direction:(GridAnimationDirection)direction
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
 
-// Runs the animation for this object with the passed duration.
-// It's an error to call this more than once on any instance of this object.
-- (void)animateWithDuration:(NSTimeInterval)duration;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_GRID_TRANSITIONS_GRID_TRANSITION_ANIMATION_H_
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm
index 1cd2332..ee535bf2 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.mm
@@ -4,53 +4,63 @@
 
 #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.h"
 
+#import "base/logging.h"
 #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h"
+#import "ios/chrome/browser/ui/util/property_animator_group.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+// Scale factor for inactive items when a tab is expanded.
+const CGFloat kInactiveItemScale = 0.95;
+}
+
 @interface GridTransitionAnimation ()
+// The property animator group backing the public |animator| property.
+@property(nonatomic, readonly) PropertyAnimatorGroup* animations;
 // The layout of the grid for this animation.
 @property(nonatomic, strong) GridTransitionLayout* layout;
-// The delegate for this animation.
-@property(nonatomic, weak) id<GridTransitionAnimationDelegate> delegate;
+// The duration of the animation.
+@property(nonatomic, readonly, assign) NSTimeInterval duration;
 // The direction this animation is in.
 @property(nonatomic, readonly, assign) GridAnimationDirection direction;
-// The x and y scales of the enlarged grid relative to the selected cell in the
-// regular grid.
-@property(nonatomic, assign) CGFloat xScale;
-@property(nonatomic, assign) CGFloat yScale;
-// Convenience properties for getting the size and center of the selected cell
+// Convenience properties for getting the size and center of the active cell
 // in the grid.
-@property(nonatomic, readonly) CGSize selectedSize;
-@property(nonatomic, readonly) CGPoint selectedCenter;
-// Corner radius that the selected cell will have when it is animated into the
+@property(nonatomic, readonly) CGSize activeSize;
+@property(nonatomic, readonly) CGPoint activeCenter;
+// Corner radius that the active cell will have when it is animated into the
 // regulat grid.
-@property(nonatomic, assign) CGFloat finalSelectedCellCornerRadius;
+@property(nonatomic, assign) CGFloat finalActiveCellCornerRadius;
 @end
 
 @implementation GridTransitionAnimation
+@synthesize animations = _animations;
 @synthesize layout = _layout;
-@synthesize delegate = _delegate;
+@synthesize duration = _duration;
 @synthesize direction = _direction;
-@synthesize xScale = _xScale;
-@synthesize yScale = _yScale;
-@synthesize finalSelectedCellCornerRadius = _finalSelectedCellCornerRadius;
+@synthesize finalActiveCellCornerRadius = _finalActiveCellCornerRadius;
 
 - (instancetype)initWithLayout:(GridTransitionLayout*)layout
-                      delegate:(id<GridTransitionAnimationDelegate>)delegate
+                      duration:(NSTimeInterval)duration
                      direction:(GridAnimationDirection)direction {
   if (self = [super initWithFrame:CGRectZero]) {
+    _animations = [[PropertyAnimatorGroup alloc] init];
     _layout = layout;
-    _delegate = delegate;
+    _duration = duration;
     _direction = direction;
-    _finalSelectedCellCornerRadius =
-        _layout.selectedItem.cell.contentView.layer.cornerRadius;
+    _finalActiveCellCornerRadius =
+        _layout.activeItem.cell.contentView.layer.cornerRadius;
   }
   return self;
 }
 
+- (id<UIViewImplicitlyAnimating>)animator {
+  return self.animations;
+}
+
 #pragma mark - UIView
 
 - (void)willMoveToSuperview:(UIView*)newSuperview {
@@ -61,293 +71,362 @@
 }
 
 - (void)didMoveToSuperview {
+  if (!self.superview)
+    return;
   // Positioning the animating items depends on converting points to this
   // view's coordinate system, so wait until it's in a view hierarchy.
   switch (self.direction) {
     case GridAnimationDirectionContracting:
-      [self positionSelectedItemInExpandedGrid];
-      [self positionUnselectedItemsInExpandedGrid];
+      [self positionExpandedActiveItem];
+      [self prepareInactiveItemsForAppearance];
+      [self buildContractingAnimations];
       break;
     case GridAnimationDirectionExpanding:
-      [self positionSelectedItemInRegularGrid];
-      [self positionUnselectedItemsInRegularGrid];
+      [self prepareAllItemsForExpansion];
+      [self buildExpandingAnimations];
       break;
   }
+  // Make sure all of the layout after the view setup is complete before any
+  // animations are run.
+  [self layoutIfNeeded];
 }
 
 #pragma mark - Private Properties
 
-- (CGSize)selectedSize {
-  return self.layout.selectedItem.attributes.size;
+- (CGSize)activeSize {
+  return self.layout.activeItem.attributes.size;
 }
 
-- (CGPoint)selectedCenter {
-  return self.layout.selectedItem.attributes.center;
-}
-
-#pragma mark - Public methods
-
-- (void)animateWithDuration:(NSTimeInterval)duration {
-  switch (self.direction) {
-    case GridAnimationDirectionContracting:
-      [self animateToRegularGridWithDuration:duration];
-      break;
-    case GridAnimationDirectionExpanding:
-      [self animateToExpandedGridWithDuration:duration];
-      break;
-  }
+- (CGPoint)activeCenter {
+  return self.layout.activeItem.attributes.center;
 }
 
 #pragma mark - Private methods
 
-- (void)animateToRegularGridWithDuration:(NSTimeInterval)duration {
-  // The transition is structured as two or three separate animations. They are
-  // timed based on |staggeredDuration|, which is a configurable fraction
-  // of the overall animation duration.
-  CGFloat staggeredDuration = duration * 0.7;
+- (void)buildContractingAnimations {
+  // The transition is structured as two or four separate animations. They are
+  // timed based on various sub-durations and delays which are expressed as
+  // fractions of the overall animation duration.
+  CGFloat partialDuration = 0.6;
+  CGFloat briefDuration = partialDuration * 0.5;
+  CGFloat shortDelay = 0.12;
+  CGFloat longDelay = 0.4;
 
-  // If there's only one cell, the animation has two parts:
-  //   (A) Fading in the selected cell highlight indicator.
-  //   (B) Zooming the selected cell into position.
-  // These parts are timed over |duration| like this:
+  // If there's only one cell, the animation has two parts.
+  //   (A) Zooming the active cell into position.
+  //   (B) Fading in the active cell's auxilliary view.
+  //   (C) Rounding the corners of the active cell.
   //
-  //           |#|----------[A]--------------------{100%}
-  //  {0%}------------------[B]--------------------{100%}
+  //  {0%}------------------[A]----------{60%}
+  //                 {40%}--[B]---------------{70%}
+  //  {0%}---[C]---{30%}
+
+  // If there's more than once cell, the animation adds two more parts:
+  //   (D) Scaling up the inactive cells.
+  //   (E) Fading the inactive cells to 100% opacity.
+  // The overall timing is as follows:
   //
-  //  (|#| is |duration| - |staggeredDuration|).
-  // Animation B will call the completion handler in this case.
-
-  // If there's more than once cell, the animation has three parts:
-  //   (A) Fading in the selected cell highlight indicator.
-  //   (B) Zooming the selected cell into position.
-  //   (C) Zooming the unselected cells into position.
-  // The timing is as follows:
+  //  {0%}------------------[A]----------{60%}
+  //                 {40%}--[B]---------------{70%}
+  //  {0%}---[C]---{30%}
+  //  {0%}------------------[D]--------------------{100%}
+  //     {12%}--------------[E]-------------- {72%}
   //
-  //           |#|----------[A]--------------------{100%}
-  //  {0%}------------------[B]------|*|
-  //           |#|----------[C]--------------------{100%}
-  //  (|*| is |staggeredDuration|).
-  //  (|#| is |duration| - |staggeredDuration|).
-  // Animation C will call the completion handler in this case.
+  // All animations are timed ease-in (so more motion happens later), except
+  // for C which is relatively small in space and short in duration; it has
+  // linear timing so it doesn't seem instantaneous.
+  // (Changing the timing constants above will change the timing % values)
 
-  // TODO(crbug.com/820410): Tune the timing, relative pacing, and curves of
-  // these animations.
-
-  UICollectionViewCell* selectedCell = self.layout.selectedItem.cell;
-
-  // Run animation (A) starting at |1 - staggeredDuration|.
-  [UIView animateWithDuration:staggeredDuration
-                        delay:duration - staggeredDuration
-                      options:UIViewAnimationOptionCurveEaseOut
-                   animations:^{
-                     selectedCell.selected = YES;
-                   }
-                   completion:nil];
-
-  // Completion block to be run when the transition completes.
-  auto completion = ^(BOOL finished) {
-    // Tell the delegate the animation has completed.
-    [self.delegate gridTransitionAnimationDidFinish:finished];
+  // A: Zoom the active cell into position.
+  auto zoomActiveCellAnimation = ^{
+    [self positionAndScaleActiveItemInGrid];
   };
+  auto zoomActiveCellKeyframeAnimation =
+      [self keyframeAnimationWithRelativeStart:0
+                              relativeDuration:partialDuration
+                                    animations:zoomActiveCellAnimation];
+  UIViewPropertyAnimator* zoomActiveCell = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveEaseIn
+            animations:zoomActiveCellKeyframeAnimation];
+  [self.animations addAnimator:zoomActiveCell];
+
+  // B: Fade in the active cell's auxillary view
+  UIView* auxillaryView = self.layout.activeItem.auxillaryView;
+  auto fadeInAuxillaryKeyframeAnimation =
+      [self keyframeAnimationWithRelativeStart:longDelay
+                              relativeDuration:briefDuration
+                                    animations:^{
+                                      auxillaryView.alpha = 1.0;
+                                    }];
+  UIViewPropertyAnimator* fadeInAuxillary = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveEaseIn
+            animations:fadeInAuxillaryKeyframeAnimation];
+  [self.animations addAnimator:fadeInAuxillary];
+
+  // C: Round the corners of the active cell.
+  UICollectionViewCell* cell = self.layout.activeItem.cell;
+  cell.contentView.layer.cornerRadius = 0.0;
+  auto roundCornersAnimation = ^{
+    cell.contentView.layer.cornerRadius = self.finalActiveCellCornerRadius;
+  };
+  auto roundCornersKeyframeAnimation =
+      [self keyframeAnimationWithRelativeStart:0
+                              relativeDuration:briefDuration
+                                    animations:roundCornersAnimation];
+  UIViewPropertyAnimator* roundCorners = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveLinear
+            animations:roundCornersKeyframeAnimation];
+  [self.animations addAnimator:roundCorners];
 
   if (self.layout.items.count == 1) {
     // Single cell case.
-    // Run animation (B) for the whole duration without delay.
-    [UIView animateWithDuration:duration
-                          delay:0
-                        options:UIViewAnimationOptionCurveEaseOut
-                     animations:^{
-                       [self positionSelectedItemInRegularGrid];
-                     }
-                     completion:completion];
-  } else {
-    // Multiple cell case.
-    // Run animation (B) up to |staggeredDuration|.
-    [UIView animateWithDuration:staggeredDuration
-                          delay:0.0
-                        options:UIViewAnimationOptionCurveEaseOut
-                     animations:^{
-                       [self positionSelectedItemInRegularGrid];
-                     }
-                     completion:nil];
-
-    // Run animation (C) for |staggeredDuration| up to the end of the
-    // transition.
-    [UIView animateWithDuration:staggeredDuration
-                          delay:duration - staggeredDuration
-                        options:UIViewAnimationOptionCurveEaseOut
-                     animations:^{
-                       [self positionUnselectedItemsInRegularGrid];
-                     }
-                     completion:completion];
+    return;
   }
+
+  // Additional animations for multiple cells.
+  // D: Scale up inactive cells.
+  auto scaleUpCellsAnimation = ^{
+    for (GridTransitionLayoutItem* item in self.layout.items) {
+      if (item == self.layout.activeItem)
+        continue;
+      item.cell.transform = CGAffineTransformIdentity;
+    }
+  };
+  UIViewPropertyAnimator* scaleUpCells = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveEaseOut
+            animations:scaleUpCellsAnimation];
+  [self.animations addAnimator:scaleUpCells];
+
+  // E: Fade in inactive cells.
+  auto fadeInCellsAnimation = ^{
+    for (GridTransitionLayoutItem* item in self.layout.items) {
+      if (item == self.layout.activeItem)
+        continue;
+      item.cell.alpha = 1.0;
+    }
+  };
+  auto fadeInCellsKeyframeAnimation =
+      [self keyframeAnimationWithRelativeStart:shortDelay
+                              relativeDuration:partialDuration
+                                    animations:fadeInCellsAnimation];
+  UIViewPropertyAnimator* fadeInCells = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveEaseOut
+            animations:fadeInCellsKeyframeAnimation];
+  [self.animations addAnimator:fadeInCells];
 }
 
-- (void)animateToExpandedGridWithDuration:(NSTimeInterval)duration {
-  // The transition is structured as two or three separate animations. They are
-  // timed based on |staggeredDuration|, which is a configurable fraction
-  // of the overall animation duration.
-  CGFloat staggeredDuration = duration * 0.9;
+- (void)buildExpandingAnimations {
+  // The transition is structured as two or four separate animations. They are
+  // timed based on two sub-durations which are expressed as fractions of the
+  // overall animation duration.
+  CGFloat partialDuration = 0.66;
+  CGFloat briefDuration = 0.23;
 
-  // If there's only one cell, the animation has two parts:
-  //   (A) Fading out the selected cell highlight indicator.
-  //   (B) Zooming the selected cell out into position.
+  // If there's only one cell, the animation has three parts:
+  //   (A) Zooming the active cell out into the expanded position.
+  //   (B) Fading out the active cell's auxilliary view.
+  //   (C) Squaring the corners of the active cell.
   // These parts are timed over |duration| like this:
   //
-  //  {0%}-----------[A]-------------|*|
-  //  {0%}------------------[B]--------------------{100%}
+  //  {0%}--[A]-----------------------------------{100%}
+  //  {0%}--[B]--{23%}
+  //                                {77%}---[C]---{100%}
+
+  // If there's more than once cell, the animation adds:
+  //   (C) Scaling the inactive cells to 95%
+  //   (D) Fading out the inactive cells.
+  // The overall timing is as follows:
   //
-  //  (|#| is |duration| - |staggeredDuration|).
-  // Animation B will call the completion handler in this case.
-
-  // If there's more than once cell, the animation has three parts:
-  //   (A) Fading out the selected cell highlight indicator.
-  //   (B) Zooming the selected cell into position.
-  //   (C) Zooming the unselected cells into position.
-  // The timing is as follows:
+  //  {0%}--[A]-----------------------------------{100%}
+  //  {0%}--[B]--{23%}
+  //                                {77%}---[C]---{100%}
+  //  {0%}--[D]-----------------------------------{100%}
+  //  {0%}--[E]-----------------{66%}
   //
-  //  {0%}-----------[A]-------------|*|
-  //  {0%}---------- [C]-------------|*|
-  //                 |#|-------------[B]-----------{100%}
-  //  (|*| is |staggeredDuration|)
-  //  (|#| is |duration| - |staggeredDuration|).
-  // Animation C will call the completion handler in this case.
+  // All animations are timed ease-out (so more motion happens sooner), except
+  // for C which is relatively small in space and short in duration; it has
+  // linear timing so it doesn't seem instantaneous.
 
-  // TODO(crbug.com/820410): Tune the timing, relative pacing, and curves of
-  // these animations.
+  // A: Zoom the active cell into position.
+  UIViewPropertyAnimator* zoomActiveCell = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveEaseOut
+            animations:^{
+              [self positionExpandedActiveItem];
+            }];
+  [self.animations addAnimator:zoomActiveCell];
 
-  UICollectionViewCell* selectedCell = self.layout.selectedItem.cell;
+  // B: Fade out the active cell's auxillary view.
+  UIView* auxillaryView = self.layout.activeItem.auxillaryView;
+  auto fadeOutAuxilliaryAnimation =
+      [self keyframeAnimationWithRelativeStart:0
+                              relativeDuration:briefDuration
+                                    animations:^{
+                                      auxillaryView.alpha = 0.0;
+                                    }];
+  UIViewPropertyAnimator* fadeOutAuxilliary = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveEaseOut
+            animations:fadeOutAuxilliaryAnimation];
+  [self.animations addAnimator:fadeOutAuxilliary];
 
-  // Run animation (A) for |staggeredDuration|.
-  [UIView animateWithDuration:staggeredDuration
-                        delay:0
-                      options:UIViewAnimationOptionCurveEaseOut
-                   animations:^{
-                     selectedCell.selected = NO;
-                   }
-                   completion:nil];
-
-  // Completion block to be run when the transition completes.
-  auto completion = ^(BOOL finished) {
-    // Tell the delegate the animation has completed.
-    [self.delegate gridTransitionAnimationDidFinish:finished];
+  // C: Square the active cell's corners.
+  UICollectionViewCell* cell = self.layout.activeItem.cell;
+  auto squareCornersAnimation = ^{
+    cell.contentView.layer.cornerRadius = 0.0;
   };
+  auto squareCornersKeyframeAnimation =
+      [self keyframeAnimationWithRelativeStart:1.0 - briefDuration
+                              relativeDuration:briefDuration
+                                    animations:squareCornersAnimation];
+  UIViewPropertyAnimator* squareCorners = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveLinear
+            animations:squareCornersKeyframeAnimation];
+  [self.animations addAnimator:squareCorners];
 
-  if (self.layout.items.count == 1) {
-    // Single cell case.
-    // Run animation (B) for the whole duration without delay.
-    [UIView animateWithDuration:duration
-                          delay:0
-                        options:UIViewAnimationOptionCurveEaseIn
-                     animations:^{
-                       [self positionSelectedItemInExpandedGrid];
-                     }
-                     completion:completion];
-  } else {
-    // Multiple cell case.
-    // Run animation (C) for |staggeredDuration|.
-    [UIView animateWithDuration:staggeredDuration
-                          delay:0.0
-                        options:UIViewAnimationOptionCurveEaseOut
-                     animations:^{
-                       [self positionUnselectedItemsInExpandedGrid];
-                     }
-                     completion:completion];
+  // If there's only a single cell, that's all.
+  if (self.layout.items.count == 1)
+    return;
 
-    // Run animation (B) for |staggeredDuration| up to the end of the
-    // transition.
-    [UIView animateWithDuration:staggeredDuration
-                          delay:duration - staggeredDuration
-                        options:UIViewAnimationOptionCurveEaseOut
-                     animations:^{
-                       [self positionSelectedItemInExpandedGrid];
-                     }
-                     completion:nil];
-  }
+  // Additional animations for multiple cells.
+  // D: Scale down inactive cells.
+  auto scaleDownCellsAnimation = ^{
+    for (GridTransitionLayoutItem* item in self.layout.items) {
+      if (item == self.layout.activeItem)
+        continue;
+      item.cell.transform = CGAffineTransformScale(
+          item.cell.transform, kInactiveItemScale, kInactiveItemScale);
+    }
+  };
+  UIViewPropertyAnimator* scaleDownCells = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveEaseOut
+            animations:scaleDownCellsAnimation];
+  [self.animations addAnimator:scaleDownCells];
+
+  // E: Fade out inactive cells.
+  auto fadeOutCellsAnimation = ^{
+    for (GridTransitionLayoutItem* item in self.layout.items) {
+      if (item == self.layout.activeItem)
+        continue;
+      item.cell.alpha = 0.0;
+    }
+  };
+  auto fadeOutCellsKeyframeAnimation =
+      [self keyframeAnimationWithRelativeStart:0
+                              relativeDuration:partialDuration
+                                    animations:fadeOutCellsAnimation];
+  UIViewPropertyAnimator* fadeOutCells = [[UIViewPropertyAnimator alloc]
+      initWithDuration:self.duration
+                 curve:UIViewAnimationCurveEaseOut
+            animations:fadeOutCellsKeyframeAnimation];
+  [self.animations addAnimator:fadeOutCells];
 }
 
-// Perfrom the initial setup for the animation, computing scale based on the
+// Perfroms the initial setup for the animation, computing scale based on the
 // superview size and adding the transition cells to the view hierarchy.
 - (void)prepareForAnimationInSuperview:(UIView*)newSuperview {
-  // Extract some useful metrics from the animation superview.
-  CGSize animationSize = newSuperview.bounds.size;
+  // Add the selection item first, so it's under ther other views.
+  [self addSubview:self.layout.selectionItem.cell];
 
-  // Compute the scale of the transition grid (which is at the proportional size
-  // of the superview).
-  self.xScale = animationSize.width / self.selectedSize.width;
-  self.yScale = animationSize.height / self.selectedSize.height;
+  // Only show the selection part.
+  self.layout.selectionItem.cell.contentView.hidden = YES;
+  self.layout.selectionItem.cell.selected = YES;
 
+  // Add the active item last so it's always the top subview.
   for (GridTransitionLayoutItem* item in self.layout.items) {
+    if (item == self.layout.activeItem)
+      continue;
     [self addSubview:item.cell];
   }
+  [self addSubview:self.layout.activeItem.cell];
 }
 
-// Positions the selected item in the expanded grid position with a zero corner
-// radius.
-- (void)positionSelectedItemInExpandedGrid {
-  [self positionAndScaleItemInExpandedGrid:self.layout.selectedItem];
-  UICollectionViewCell* cell = self.layout.selectedItem.cell;
-  cell.contentView.layer.cornerRadius = 0.0;
+// Positions the active item in the expanded grid position with a zero corner
+// radius and a 0% opacity auxilliary view.
+- (void)positionExpandedActiveItem {
+  GridTransitionLayoutItem* activeItem = self.layout.activeItem;
+  UICollectionViewCell* cell = activeItem.cell;
+  // Ensure that the cell's subviews are correctly positioned.
+  [cell layoutIfNeeded];
+  // Position the cell frame so so that the area below the aux view matches the
+  // expanded rect.
+  // Easiest way to do this is to set the frame to the expanded rect and then
+  // add height to it to include the aux view height.
+  CGFloat auxHeight = activeItem.auxillaryView.frame.size.height;
+  CGRect cellFrame = self.layout.expandedRect;
+  cellFrame.size.height += auxHeight;
+  cellFrame.origin.y -= auxHeight;
+  cell.frame = cellFrame;
+  activeItem.auxillaryView.alpha = 0.0;
 }
 
-// Positions all of the non-selected items in their expanded grid positions.
-- (void)positionUnselectedItemsInExpandedGrid {
-  // Lay out the transition grid add it as subviews.
+// Positions all of the inactive items in their grid positions.
+// Fades and scales each of those items.
+- (void)prepareInactiveItemsForAppearance {
   for (GridTransitionLayoutItem* item in self.layout.items) {
-    if (item == self.layout.selectedItem)
+    if (item == self.layout.activeItem)
       continue;
-    [self positionAndScaleItemInExpandedGrid:item];
+    [self positionItemInGrid:item];
+    item.cell.alpha = 0.0;
+    item.cell.transform = CGAffineTransformScale(
+        item.cell.transform, kInactiveItemScale, kInactiveItemScale);
   }
+  [self positionItemInGrid:self.layout.selectionItem];
 }
 
-// Positions the selected item in the regular grid position with its final
+// Positions the active item in the regular grid position with its final
 // corner radius.
-- (void)positionSelectedItemInRegularGrid {
-  [self positionAndScaleItemInRegularGrid:self.layout.selectedItem];
-  UICollectionViewCell* cell = self.layout.selectedItem.cell;
-  cell.contentView.layer.cornerRadius = self.finalSelectedCellCornerRadius;
-}
-
-// Positions all of the non-selected items in their regular grid positions.
-- (void)positionUnselectedItemsInRegularGrid {
-  for (GridTransitionLayoutItem* item in self.layout.items) {
-    if (item == self.layout.selectedItem)
-      continue;
-    [self positionAndScaleItemInRegularGrid:item];
-  }
-}
-
-// Positions |item| in its regular grid position.
-- (void)positionAndScaleItemInRegularGrid:(GridTransitionLayoutItem*)item {
-  UIView* cell = item.cell;
-  cell.center =
-      [self.superview convertPoint:item.attributes.center fromView:nil];
+- (void)positionAndScaleActiveItemInGrid {
+  UICollectionViewCell* cell = self.layout.activeItem.cell;
   cell.transform = CGAffineTransformIdentity;
+  cell.frame = self.layout.activeItem.attributes.frame;
+  [self positionItemInGrid:self.layout.activeItem];
 }
 
-// Positions |item| in its expanded grid position.
-- (void)positionAndScaleItemInExpandedGrid:(GridTransitionLayoutItem*)item {
-  UICollectionViewCell* cell = item.cell;
-  cell.bounds = item.attributes.bounds;
-  // Add a scale transform to the cell so it matches the x-scale of the
-  // open tab. Scaling is only based on the x-scale so that the aspect ratio of
-  // the cell will be preserved.
-  cell.transform =
-      CGAffineTransformScale(cell.transform, self.xScale, self.xScale);
-  cell.center = [self expandedCenterForItem:item];
+// Prepares all of the items for an expansion anumation.
+- (void)prepareAllItemsForExpansion {
+  for (GridTransitionLayoutItem* item in self.layout.items) {
+    [self positionItemInGrid:item];
+  }
+  [self positionItemInGrid:self.layout.selectionItem];
 }
 
-// Returns the center point for an item in the expanded grid position. This is
-// computed by scaling its center point relative to the selected item's center
-// point. The scaling factors are the ratios of the animation view's height and
-// width to the selected cell's height and width.
-- (CGPoint)expandedCenterForItem:(GridTransitionLayoutItem*)item {
-  // Convert item center from window coordinates.
-  CGPoint gridCenter = [self convertPoint:item.attributes.center fromView:nil];
-  // Map that to the scale and position of the transition grid.
-  return CGPointMake(
-      self.center.x + ((gridCenter.x - self.selectedCenter.x) * self.xScale),
-      self.center.y + ((gridCenter.y - self.selectedCenter.y) * self.yScale));
+// Positions |item| in it grid position.
+- (void)positionItemInGrid:(GridTransitionLayoutItem*)item {
+  UIView* cell = item.cell;
+  CGPoint attributeCenter = item.attributes.center;
+  CGPoint newCenter =
+      [self.superview convertPoint:attributeCenter fromView:nil];
+  cell.center = newCenter;
+}
+
+// Helper function to construct keyframe animation blocks.
+// Given |start| and |duration| (in the [0.0-1.0] interval), returns an
+// animation block which runs |animations| starting at |start| (relative to
+// |self.duration|) and running for |duration| (likewise).
+- (void (^)(void))keyframeAnimationWithRelativeStart:(double)start
+                                    relativeDuration:(double)duration
+                                          animations:
+                                              (void (^)(void))animations {
+  auto keyframe = ^{
+    [UIView addKeyframeWithRelativeStartTime:start
+                            relativeDuration:duration
+                                  animations:animations];
+  };
+  return ^{
+    [UIView animateKeyframesWithDuration:self.duration
+                                   delay:0
+                                 options:UIViewAnimationOptionLayoutSubviews
+                              animations:keyframe
+                              completion:nil];
+  };
 }
 
 @end
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h
index c8de9ee3..8944963 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h
@@ -16,16 +16,25 @@
 
 // All of the items in the layout.
 @property(nonatomic, copy, readonly) NSArray<GridTransitionLayoutItem*>* items;
-// The item in the layout (if any) that's selected.
-// Note that |selectedItem.cell.selected| doesn't need to be YES; the transition
+// The item in the layout (if any) that's the 'active' item (the one that will
+// expand and contract).
+// Note that |activeItem.cell.selected| doesn't need to be YES; the transition
 // animation may set or unset that selection state as part of the animation.
-@property(nonatomic, strong, readonly) GridTransitionLayoutItem* selectedItem;
+@property(nonatomic, strong, readonly) GridTransitionLayoutItem* activeItem;
 
-// Creates a new layout object with |items|, and |selectedItem| selected.
+// An item that may be used to *only* show the selection state.
+// |selectionItem| is not one of the items in |items|.
+@property(nonatomic, strong, readonly) GridTransitionLayoutItem* selectionItem;
+
+// The rect, in UIWindow coordinates, that an "expanded" item should occupy.
+@property(nonatomic) CGRect expandedRect;
+
+// Creates a new layout object with |items|, and |activeItem| selected.
 // |items| should be non-nil, but it may be empty.
-// |selectedItem| must either be nil, or one of the members of |items|.
+// |activeItem| must either be nil, or one of the members of |items|.
 + (instancetype)layoutWithItems:(NSArray<GridTransitionLayoutItem*>*)items
-                   selectedItem:(GridTransitionLayoutItem*)selectedItem;
+                     activeItem:(GridTransitionLayoutItem*)activeItem
+                  selectionItem:(GridTransitionLayoutItem*)selectionItem;
 
 @end
 
@@ -38,6 +47,10 @@
 // ition, but the value of thie property should not be in any view hierarchy
 // when the layout item is created.
 @property(nonatomic, strong, readonly) UICollectionViewCell* cell;
+
+// An auxillary view in |cell|'s view hierarchy that may also be animated.
+@property(nonatomic, weak, readonly) UIView* auxillaryView;
+
 // The layout attributes for the cell in the collection view, normalized to
 // UIWindow coordinates. It's the responsibility of the setter to do this
 // normalization.
@@ -47,9 +60,11 @@
 // Creates a new layout item instance will |cell| and |attributes|, neither of
 // which can be nil.
 // It's an error if |cell| has a superview.
+// It's an error if |auxillaryView| is not a subview of |cell|; it may be nil.
 // The properties (size, etc) of |attributes| don't need to match the corres-
 // ponding properties of |cell| when the item is created.
 + (instancetype)itemWithCell:(UICollectionViewCell*)cell
+               auxillaryView:(UIView*)auxillaryView
                   attributes:(UICollectionViewLayoutAttributes*)attributes;
 
 @end
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
index 14e4126..32b27f8f 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
+++ b/ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.mm
@@ -12,47 +12,55 @@
 
 @interface GridTransitionLayout ()
 @property(nonatomic, readwrite) NSArray<GridTransitionLayoutItem*>* items;
-@property(nonatomic, readwrite) GridTransitionLayoutItem* selectedItem;
+@property(nonatomic, readwrite) GridTransitionLayoutItem* activeItem;
+@property(nonatomic, readwrite) GridTransitionLayoutItem* selectionItem;
 @end
 
 @implementation GridTransitionLayout
-@synthesize selectedItem = _selectedItem;
+@synthesize activeItem = _activeItem;
+@synthesize selectionItem = _selectionItem;
 @synthesize items = _items;
+@synthesize expandedRect = _expandedRect;
 
 + (instancetype)layoutWithItems:(NSArray<GridTransitionLayoutItem*>*)items
-                   selectedItem:(GridTransitionLayoutItem*)selectedItem {
+                     activeItem:(GridTransitionLayoutItem*)activeItem
+                  selectionItem:(GridTransitionLayoutItem*)selectionItem {
   DCHECK(items);
   GridTransitionLayout* layout = [[GridTransitionLayout alloc] init];
   layout.items = items;
-  layout.selectedItem = selectedItem;
+  layout.activeItem = activeItem;
+  layout.selectionItem = selectionItem;
   return layout;
 }
 
-- (void)setSelectedItem:(GridTransitionLayoutItem*)selectedItem {
-  DCHECK(!selectedItem || [self.items containsObject:selectedItem]);
-  _selectedItem = selectedItem;
+- (void)setActiveItem:(GridTransitionLayoutItem*)activeItem {
+  DCHECK(!activeItem || [self.items containsObject:activeItem]);
+  _activeItem = activeItem;
 }
 
 @end
 
 @interface GridTransitionLayoutItem ()
 @property(nonatomic, readwrite) UICollectionViewCell* cell;
+@property(nonatomic, readwrite) UIView* auxillaryView;
 @property(nonatomic, readwrite) UICollectionViewLayoutAttributes* attributes;
 @end
 
 @implementation GridTransitionLayoutItem
 @synthesize cell = _cell;
+@synthesize auxillaryView = _auxillaryView;
 @synthesize attributes = _attributes;
 
 + (instancetype)itemWithCell:(UICollectionViewCell*)cell
+               auxillaryView:(UIView*)auxillaryView
                   attributes:(UICollectionViewLayoutAttributes*)attributes {
   DCHECK(cell);
-  DCHECK(attributes);
   DCHECK(!cell.superview);
+  DCHECK(!auxillaryView || [auxillaryView isDescendantOfView:cell]);
   GridTransitionLayoutItem* item = [[GridTransitionLayoutItem alloc] init];
   item.cell = cell;
+  item.auxillaryView = auxillaryView;
   item.attributes = attributes;
   return item;
 }
-
 @end
diff --git a/ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.mm b/ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.mm
index f34e263e..6f440bf 100644
--- a/ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.mm
+++ b/ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.mm
@@ -5,13 +5,17 @@
 #import "ios/chrome/browser/ui/tab_grid/transitions/tab_to_grid_animator.h"
 
 #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_animation.h"
+#import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_layout.h"
 #import "ios/chrome/browser/ui/tab_grid/transitions/grid_transition_state_providing.h"
+#import "ios/chrome/browser/ui/util/layout_guide_names.h"
+#import "ios/chrome/browser/ui/util/named_guide.h"
+#import "ios/chrome/browser/ui/util/property_animator_group.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@interface TabToGridAnimator ()<GridTransitionAnimationDelegate>
+@interface TabToGridAnimator ()
 @property(nonatomic, weak) id<GridTransitionStateProviding> stateProvider;
 // Animation object for this transition.
 @property(nonatomic, strong) GridTransitionAnimation* animation;
@@ -35,7 +39,7 @@
 
 - (NSTimeInterval)transitionDuration:
     (id<UIViewControllerContextTransitioning>)transitionContext {
-  return 0.4;
+  return 0.5;
 }
 
 - (void)animateTransition:
@@ -53,6 +57,8 @@
   UIView* dismissingView =
       [transitionContext viewForKey:UITransitionContextFromViewKey];
 
+  // Find the rect for the animating tab by getting the content area layout
+  // guide.
   // Add the grid view to the container. This isn't just for the transition;
   // this is how the grid view controller's view is added to the view
   // hierarchy.
@@ -60,35 +66,52 @@
   gridView.frame =
       [transitionContext finalFrameForViewController:gridViewController];
 
+  // Ask the state provider for the views to use when inserting the animation.
+  UIView* proxyContainer =
+      [self.stateProvider proxyContainerForTransitionContext:transitionContext];
+
   // Get the layout of the grid for the transition.
   GridTransitionLayout* layout =
       [self.stateProvider layoutForTransitionContext:transitionContext];
 
+  // Get the initial rect for the snapshotted content of the active tab.
+  // Conceptually this transition is dismissing a tab (a BVC). However,
+  // currently the BVC instances are themselves contanted within a BVCContainer
+  // view controller. This means that the |dismissingView| is not the BVC's
+  // view; rather it's the view of the view controller that contains the BVC.
+  // Unfortunatley, the layout guide needed here is attached to the BVC's view,
+  // which is the first (and only) subview of the BVCContainerViewController's
+  // view.
+  // TODO(crbug.com/860234) Clean up this arrangement.
+  UIView* viewWithNamedGuides = dismissingView.subviews[0];
+  CGRect initialRect =
+      [NamedGuide guideWithName:kContentAreaGuide view:viewWithNamedGuides]
+          .layoutFrame;
+  layout.expandedRect =
+      [proxyContainer convertRect:initialRect fromView:viewWithNamedGuides];
+
+  NSTimeInterval duration = [self transitionDuration:transitionContext];
   // Create the animation view and insert it.
   self.animation = [[GridTransitionAnimation alloc]
       initWithLayout:layout
-            delegate:self
+            duration:duration
            direction:GridAnimationDirectionContracting];
 
-  // Ask the state provider for the views to use when inserting the animation.
-  UIView* proxyContainer =
-      [self.stateProvider proxyContainerForTransitionContext:transitionContext];
   UIView* viewBehindProxies =
       [self.stateProvider proxyPositionForTransitionContext:transitionContext];
-
   [proxyContainer insertSubview:self.animation aboveSubview:viewBehindProxies];
 
-  NSTimeInterval duration = [self transitionDuration:transitionContext];
+  [self.animation.animator addCompletion:^(UIViewAnimatingPosition position) {
+    BOOL finished = (position == UIViewAnimatingPositionEnd);
+    [self gridTransitionAnimationDidFinish:finished];
+  }];
 
-  // Fade out active tab view.
-  [UIView animateWithDuration:duration / 5
-                   animations:^{
-                     dismissingView.alpha = 0;
-                   }
-                   completion:nil];
+  // TODO(crbug.com/850507): Have the tab view animate itself out alongside this
+  // transition instead of just zeroing the alpha here.
+  dismissingView.alpha = 0;
 
   // Run the main animation.
-  [self.animation animateWithDuration:duration];
+  [self.animation.animator startAnimation];
 }
 
 - (void)gridTransitionAnimationDidFinish:(BOOL)finished {
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index 902eea9..2a3a435d 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -2813,7 +2813,14 @@
 
 // Tries verifying a certificate chain that is missing an intermediate. The
 // intermediate is available via AIA.
-TEST_P(CertVerifyProcInternalWithNetFetchingTest, IntermediateFromAia200) {
+// TODO(crbug.com/860189): Failing on iOS
+#if defined(OS_IOS)
+#define MAYBE_IntermediateFromAia200 DISABLED_IntermediateFromAia200
+#else
+#define MAYBE_IntermediateFromAia200 IntermediateFromAia200
+#endif
+TEST_P(CertVerifyProcInternalWithNetFetchingTest,
+       MAYBE_IntermediateFromAia200) {
   const char kHostname[] = "www.example.com";
 
   base::FilePath certs_dir =
diff --git a/net/url_request/url_request_job_factory_impl_unittest.cc b/net/url_request/url_request_job_factory_impl_unittest.cc
index 58ee048..efbccd9 100644
--- a/net/url_request/url_request_job_factory_impl_unittest.cc
+++ b/net/url_request/url_request_job_factory_impl_unittest.cc
@@ -74,7 +74,8 @@
 }
 
 TEST(URLRequestJobFactoryTest, BasicProtocolHandler) {
-  base::test::ScopedTaskEnvironment scoped_task_environment;
+  base::test::ScopedTaskEnvironment scoped_task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
   TestDelegate delegate;
   URLRequestJobFactoryImpl job_factory;
   TestURLRequestContext request_context;
diff --git a/remoting/host/backoff_timer_unittest.cc b/remoting/host/backoff_timer_unittest.cc
index fe52bcd..425e010 100644
--- a/remoting/host/backoff_timer_unittest.cc
+++ b/remoting/host/backoff_timer_unittest.cc
@@ -19,7 +19,7 @@
 }  // namespace
 
 TEST(BackoffTimer, Basic) {
-  base::MockTimer* mock_timer = new base::MockTimer(false, false);
+  base::MockOneShotTimer* mock_timer = new base::MockOneShotTimer();
   BackoffTimer backoff_timer;
   backoff_timer.SetTimerForTest(base::WrapUnique(mock_timer));
   ASSERT_FALSE(backoff_timer.IsRunning());
diff --git a/remoting/protocol/capture_scheduler_unittest.cc b/remoting/protocol/capture_scheduler_unittest.cc
index 05ae90f..004a6a0 100644
--- a/remoting/protocol/capture_scheduler_unittest.cc
+++ b/remoting/protocol/capture_scheduler_unittest.cc
@@ -32,7 +32,7 @@
     scheduler_->set_minimum_interval(
         base::TimeDelta::FromMilliseconds(kMinumumFrameIntervalMs));
     scheduler_->SetTickClockForTest(&tick_clock_);
-    capture_timer_ = new base::MockTimer(false, false);
+    capture_timer_ = new base::MockOneShotTimer();
     scheduler_->SetTimerForTest(base::WrapUnique(capture_timer_));
     scheduler_->Start();
   }
@@ -79,7 +79,7 @@
   base::SimpleTestTickClock tick_clock_;
 
   // Owned by |scheduler_|.
-  base::MockTimer* capture_timer_;
+  base::MockOneShotTimer* capture_timer_;
 
   bool capture_called_;
 };
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 8a7efc8..2e45760 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -142,7 +142,6 @@
     "//components/cookie_config",
     "//components/network_session_configurator/browser",
     "//components/network_session_configurator/common",
-    "//components/os_crypt",
     "//components/prefs",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
@@ -187,10 +186,6 @@
   }
 
   defines = [ "IS_NETWORK_SERVICE_IMPL" ]
-
-  if (is_chromecast) {
-    defines += [ "IS_CHROMECAST" ]
-  }
 }
 
 source_set("tests") {
diff --git a/services/network/DEPS b/services/network/DEPS
index 2e5b4b7..b946204 100644
--- a/services/network/DEPS
+++ b/services/network/DEPS
@@ -3,7 +3,6 @@
   "+components/content_settings/core/common",
   "+components/cookie_config",
   "+components/network_session_configurator",
-  "+components/os_crypt",
   # Prefs are used to create an independent file with a persisted key:value
   # store for networking-related data (Like which servers support QUIC), rather
   # than to store user preferences.
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 9e0d6bb..9284ae8 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1093,6 +1093,8 @@
   // have to figure out which of the latter needs to move to the network
   // process). TODO: http://crbug.com/789644
   if (params_->cookie_path) {
+    net::CookieCryptoDelegate* crypto_delegate = nullptr;
+
     scoped_refptr<base::SequencedTaskRunner> client_task_runner =
         base::MessageLoopCurrent::Get()->task_runner();
     scoped_refptr<base::SequencedTaskRunner> background_task_runner =
@@ -1109,15 +1111,6 @@
           new net::DefaultChannelIDStore(channel_id_db.get()));
     }
 
-    net::CookieCryptoDelegate* crypto_delegate = nullptr;
-    if (params_->enable_encrypted_cookies) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(IS_CHROMECAST)
-      DCHECK(network_service_->os_crypt_config_set())
-          << "NetworkService::SetCryptConfig must be called before creating a "
-             "NetworkContext with encrypted cookies.";
-#endif
-      crypto_delegate = cookie_config::GetCookieCryptoDelegate();
-    }
     scoped_refptr<net::SQLitePersistentCookieStore> sqlite_store(
         new net::SQLitePersistentCookieStore(
             params_->cookie_path.value(), client_task_runner,
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index c4df8ec..1aba17c2 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/task_scheduler/post_task.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "components/certificate_transparency/sth_distributor.h"
 #include "components/certificate_transparency/sth_observer.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -38,11 +39,6 @@
 #include "third_party/boringssl/src/include/openssl/cpu.h"
 #endif
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(IS_CHROMECAST)
-#include "components/os_crypt/key_storage_config_linux.h"
-#include "components/os_crypt/os_crypt.h"
-#endif
-
 namespace network {
 
 namespace {
@@ -367,21 +363,6 @@
   sth_distributor_->NewSTHObserved(sth);
 }
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-void NetworkService::SetCryptConfig(mojom::CryptConfigPtr crypt_config) {
-#if !defined(IS_CHROMECAST)
-  auto config = std::make_unique<os_crypt::Config>();
-  config->store = crypt_config->store;
-  config->product_name = crypt_config->product_name;
-  config->main_thread_runner = base::ThreadTaskRunnerHandle::Get();
-  config->should_use_preference = crypt_config->should_use_preference;
-  config->user_data_path = crypt_config->user_data_path;
-  OSCrypt::SetConfig(std::move(config));
-  os_crypt_config_set_ = true;
-#endif
-}
-#endif
-
 net::HttpAuthHandlerFactory* NetworkService::GetHttpAuthHandlerFactory() {
   if (!http_auth_handler_factory_) {
     http_auth_handler_factory_ = net::HttpAuthHandlerFactory::CreateDefault(
diff --git a/services/network/network_service.h b/services/network/network_service.h
index 839a5da9..df84df0 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -14,7 +14,6 @@
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/optional.h"
-#include "build/build_config.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "net/http/http_auth_preferences.h"
 #include "net/log/net_log.h"
@@ -133,9 +132,6 @@
   void GetTotalNetworkUsages(
       mojom::NetworkService::GetTotalNetworkUsagesCallback callback) override;
   void UpdateSignedTreeHead(const net::ct::SignedTreeHead& sth) override;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-  void SetCryptConfig(mojom::CryptConfigPtr crypt_config) override;
-#endif
 
   // Returns the shared HttpAuthHandlerFactory for the NetworkService, creating
   // one if needed.
@@ -159,8 +155,6 @@
 
   certificate_transparency::STHReporter* sth_reporter();
 
-  bool os_crypt_config_set() const { return os_crypt_config_set_; }
-
   static NetworkService* GetNetworkServiceForTesting();
 
  private:
@@ -227,8 +221,6 @@
 
   bool quic_disabled_ = false;
 
-  bool os_crypt_config_set_ = false;
-
   std::unique_ptr<certificate_transparency::STHDistributor> sth_distributor_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkService);
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc
index e0eed6b..abf2d0c 100644
--- a/services/network/network_service_unittest.cc
+++ b/services/network/network_service_unittest.cc
@@ -97,7 +97,6 @@
 TEST_F(NetworkServiceTest, CreateContextWithoutChannelID) {
   mojom::NetworkContextParamsPtr params = CreateContextParams();
   params->cookie_path = base::FilePath();
-  params->enable_encrypted_cookies = false;
   mojom::NetworkContextPtr network_context;
   service()->CreateNetworkContext(mojo::MakeRequest(&network_context),
                                   std::move(params));
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index e9d7bfe..8aab22f 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -121,10 +121,4 @@
     export_define_blink = "BLINK_PLATFORM_IMPLEMENTATION=1"
     export_header_blink = "third_party/blink/public/platform/web_common.h"
   }
-
-  # This is only needed on desktop linux, but the defines make this difficult
-  # because IS_CHROMECAST is not available in build/build_config.h.
-  if (is_linux && !is_chromeos) {
-    enabled_features = [ "needs_crypt_config" ]
-  }
 }
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 89f5818..38bc97a 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -62,9 +62,6 @@
   // Points to the cookie file. An in-memory cookie store is used if it's empty.
   mojo_base.mojom.FilePath? cookie_path;
 
-  // If true, cookies will be stored encrypted.
-  bool enable_encrypted_cookies = true;
-
   // If the cookie file is given, this controls whether previously written
   // session cookies are restored. Otherwise it should be false.
   bool restore_old_session_cookies = false;
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index 2eeab65..2c08cd6e 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -163,22 +163,6 @@
   string android_negotiate_account_type;
 };
 
-// Values for configuring OSCrypt.
-[EnableIf=needs_crypt_config]
-struct CryptConfig {
-  // Force OSCrypt to use a specific linux password store.
-  string store;
-
-  // The product name to use for permission prompts.
-  string product_name;
-
-  // Controls whether preference on using or ignoring backends is used.
-  bool should_use_preference;
-
-  // Preferences are stored in a separate file in the user data directory.
-  mojo_base.mojom.FilePath user_data_path;
-};
-
 // Browser interface to the network service.
 interface NetworkService {
   SetClient(NetworkServiceClient client);
@@ -247,9 +231,4 @@
   // Transparency. Broadcast to each NetworkContext using the NetworkService.
   // NetworkContextes ignore STHs from unrecognized logs.
   UpdateSignedTreeHead(SignedTreeHead signed_tree_head);
-
-  // Sets up OSCrypt for the network service process. Must be called before
-  // encrypted cookies can be read or set.
-  [EnableIf=needs_crypt_config]
-  SetCryptConfig(CryptConfig crypt_config);
 };
diff --git a/services/network/resource_scheduler_unittest.cc b/services/network/resource_scheduler_unittest.cc
index bd42c9f..08e651d 100644
--- a/services/network/resource_scheduler_unittest.cc
+++ b/services/network/resource_scheduler_unittest.cc
@@ -23,7 +23,6 @@
 #include "base/test/mock_entropy_provider.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_mock_time_task_runner.h"
-#include "base/timer/mock_timer.h"
 #include "base/timer/timer.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/request_priority.h"
@@ -171,8 +170,7 @@
   void InitializeScheduler(bool enabled = true) {
     CleanupScheduler();
 
-    // Destroys previous scheduler, also destroys any previously created
-    // mock_timer_.
+    // Destroys previous scheduler.
     scheduler_.reset(new ResourceScheduler(enabled));
 
     scheduler()->SetResourceSchedulerParamsManagerForTests(
@@ -292,11 +290,6 @@
     request->ChangePriority(new_priority, intra_priority);
   }
 
-  void FireCoalescingTimer() {
-    EXPECT_TRUE(mock_timer_->IsRunning());
-    mock_timer_->Fire();
-  }
-
   void RequestLimitOverrideConfigTestHelper(bool experiment_status) {
     InitializeThrottleDelayableExperiment(experiment_status, 0.0);
 
@@ -440,7 +433,6 @@
 
   base::MessageLoop message_loop_;
   std::unique_ptr<ResourceScheduler> scheduler_;
-  base::MockTimer* mock_timer_;
   net::HttpServerPropertiesImpl http_server_properties_;
   net::TestNetworkQualityEstimator network_quality_estimator_;
   net::TestURLRequestContext context_;
diff --git a/services/resource_coordinator/observers/ipc_volume_reporter_unittest.cc b/services/resource_coordinator/observers/ipc_volume_reporter_unittest.cc
index de57a37..8d35567 100644
--- a/services/resource_coordinator/observers/ipc_volume_reporter_unittest.cc
+++ b/services/resource_coordinator/observers/ipc_volume_reporter_unittest.cc
@@ -17,10 +17,10 @@
 class TestIPCVolumeReporter : public IPCVolumeReporter {
  public:
   TestIPCVolumeReporter()
-      : IPCVolumeReporter(std::make_unique<base::MockTimer>(false, false)) {}
+      : IPCVolumeReporter(std::make_unique<base::MockOneShotTimer>()) {}
 
-  base::MockTimer* mock_timer() const {
-    return reinterpret_cast<base::MockTimer*>(timer());
+  base::MockOneShotTimer* mock_timer() const {
+    return static_cast<base::MockOneShotTimer*>(timer());
   }
 };
 
diff --git a/services/service_manager/sandbox/linux/sandbox_linux.h b/services/service_manager/sandbox/linux/sandbox_linux.h
index e4d7a7a..dcf4eeee 100644
--- a/services/service_manager/sandbox/linux/sandbox_linux.h
+++ b/services/service_manager/sandbox/linux/sandbox_linux.h
@@ -56,11 +56,11 @@
   // This isn't the full list, values < 32 are reserved for methods called from
   // Skia, and values < 64 are reserved for libc_interceptor.cc.
   enum LinuxSandboxIPCMethods {
-    METHOD_GET_FALLBACK_FONT_FOR_CHAR = 64,
+    DEPRECATED_METHOD_GET_FALLBACK_FONT_FOR_CHAR = 64,
     DEPRECATED_METHOD_GET_CHILD_WITH_INODE,
-    METHOD_GET_STYLE_FOR_STRIKE,
+    DEPRECATED_METHOD_GET_STYLE_FOR_STRIKE,
     METHOD_MAKE_SHARED_MEMORY_SEGMENT,
-    METHOD_MATCH_WITH_FALLBACK,
+    DEPRECATED_METHOD_MATCH_WITH_FALLBACK,
   };
 
   // These form a bitmask which describes the conditions of the Linux sandbox.
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index f9b11e4..dc80b058 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -49,6 +49,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -763,6 +769,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -12644,6 +12656,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -13354,6 +13372,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -14034,6 +14058,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -14724,6 +14754,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -15417,6 +15453,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -23612,6 +23654,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 4ffa1673..00e5f24 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -3894,6 +3894,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 8a61168..819b201c 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -745,6 +745,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -1589,6 +1595,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -2382,6 +2394,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -3083,6 +3101,17 @@
             }
           ]
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
+          ]
+        },
         "test": "blink_heap_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index f36eea83..6046bf0 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -2641,6 +2641,16 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "args": [
+          "--test-launcher-batch-limit=1",
+          "--test-launcher-print-test-stdio=always"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -3522,6 +3532,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -5459,6 +5475,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_heap_unittests"
       },
       {
@@ -6155,6 +6177,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "blink_fuzzer_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "blink_platform_unittests"
       },
       {
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 234e28f..c3fdcdca 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -179,6 +179,10 @@
     "label": "//third_party/blink/common:blink_common_unittests",
     "type": "console_test_launcher",
   },
+  "blink_fuzzer_unittests": {
+    "label": "//third_party/blink/renderer/platform:blink_fuzzer_unittests",
+    "type": "console_test_launcher",
+  },
   "blink_heap_unittests": {
     "label": "//third_party/blink/renderer/platform/heap:blink_heap_unittests",
     "type": "console_test_launcher",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 7bec85fc..99d8ee5 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -1840,6 +1840,7 @@
   'linux_specific_chromium_gtests': {
     # Linux only.
     # TODO(kbr): unclear why some of these aren't run more broadly.
+    'blink_fuzzer_unittests': {},
     'filesystem_service_unittests': {},
     'leveldb_service_unittests': {},
     'traffic_annotation_auditor_unittests': {},
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json
index 939cb0f..5a37c1d 100644
--- a/testing/buildbot/trybot_analyze_config.json
+++ b/testing/buildbot/trybot_analyze_config.json
@@ -32,7 +32,8 @@
       "testing/scripts/.*",
       "testing/test_env.py",
       "third_party/android_platform/development/scripts/.*",
-      "tools/clang/blink_gc_plugin/CMakeLists.txt"
+      "tools/clang/blink_gc_plugin/CMakeLists.txt",
+      "tools/luci-go/.*"
     ],
     "ignores": [
       "infra/config/recipes.cfg",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 6cf4f88..43a3ee2 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -323,7 +323,6 @@
 crbug.com/591099 fast/block/basic/quirk-percent-height-table-cell.html [ Failure ]
 crbug.com/591099 fast/block/block-width-recalc-with-relative-height.html [ Failure ]
 crbug.com/591099 fast/block/float-avoids-padding-inline-ancestors.html [ Crash ]
-crbug.com/810335 fast/block/float/003.html [ Failure ]
 crbug.com/591099 fast/block/float/floats-offset-image-strict-line-height.html [ Failure ]
 crbug.com/591099 fast/block/float/floats-offset-inline-block-strict-line-height.html [ Failure ]
 crbug.com/591099 fast/block/float/negative-margin-on-element-avoiding-floats-with-margin-on-parent.html [ Failure ]
@@ -382,7 +381,6 @@
 crbug.com/591099 fast/css-intrinsic-dimensions/fixed-height-stf-img-inline-child-percent-height.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Failure ]
 crbug.com/807708 fast/css-intrinsic-dimensions/width-avoid-floats.html [ Failure ]
-crbug.com/591099 fast/css/007.html [ Failure ]
 crbug.com/591099 fast/css/abs-pos-child-inside-rel-pos-inline-001.html [ Failure ]
 crbug.com/591099 fast/css/abs-pos-child-inside-rel-pos-inline-offset-001.html [ Failure ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
@@ -901,7 +899,6 @@
 crbug.com/591099 printing/absolute-position-headers-and-footers.html [ Failure ]
 crbug.com/591099 printing/iframe-svg-in-object-print.html [ Failure ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
-crbug.com/591099 scrollbars/scrollbar-miss-mousemove-disabled.html [ Failure ]
 crbug.com/591099 shapedetection/detection-HTMLVideoElement.html [ Pass ]
 crbug.com/591099 storage/indexeddb/cursor-continue-validity.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/index-cursor.html [ Pass Timeout ]
@@ -932,7 +929,6 @@
 crbug.com/591099 tables/mozilla/bugs/bug2973.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug30692.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug50695-2.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug53690-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug55527.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug57828-2.html [ Failure ]
 crbug.com/591099 tables/mozilla_expected_failures/bugs/bug3166-16.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index d4d977c..ffb838d3 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1998,7 +1998,7 @@
 crbug.com/692560 external/wpt/html/semantics/document-metadata/styling/LinkStyle.html [ Failure Pass ]
 crbug.com/627706 external/wpt/html/semantics/embedded-content/the-img-element/invalid-src.html [ Skip ]
 
-crbug.com/698135 external/wpt/editing/run/delete.html [ Crash Failure Timeout ]
+crbug.com/860211 [ Mac ] external/wpt/editing/run/delete.html [ Failure ]
 
 crbug.com/813098 external/wpt/editing/run/removeformat.html [ Timeout Pass ]
 
@@ -2751,7 +2751,6 @@
 # These need to be updated but appear not to be related to that change.
 crbug.com/626703 http/tests/devtools/indexeddb/database-refresh-view.js [ Pass Failure ]
 crbug.com/626703 http/tests/devtools/extensions/extensions-sidebar.js [ Pass Failure ]
-crbug.com/751952 external/wpt/editing/run/forwarddelete.html [ Failure Pass Timeout ]
 crbug.com/751952 fast/text/international/complex-text-rectangle.html [ Timeout Pass ]
 crbug.com/751952 [ Mac Win ] editing/selection/modify_extend/extend_by_character.html [ Failure Pass ]
 crbug.com/751952 http/tests/devtools/console/console-uncaught-promise.js [ Pass Failure ]
@@ -2795,6 +2794,7 @@
 crbug.com/849859 external/wpt/web-animations/timing-model/animations/pausing-an-animation.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/console/console-timing-logging-manual.html [ Skip ]
 crbug.com/626703 external/wpt/css/css-scoping/host-specificity-002.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-scoping/slotted-specificity.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/break-spaces-001.html [ Failure ]
@@ -4670,6 +4670,8 @@
 
 # Sheriff 2018-06-11
 crbug.com/850202 [ Linux ] http/tests/devtools/network/network-filters.js [ Pass Failure ]
+crbug.com/851746 [ Linux ] fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html [ Pass Timeout ]
+crbug.com/851746 [ Linux ] virtual/gpu/fast/canvas/color-space/canvas-colorManaged-convertToBlob-roundtrip.html [ Pass Timeout ]
 
 crbug.com/853360 [ Mac ] fast/css/input-search-padding.html [ Failure ]
 crbug.com/853360 [ Mac ] fast/forms/calendar-picker/calendar-picker-appearance-ar.html [ Failure ]
@@ -4730,7 +4732,7 @@
 crbug.com/857520 [ Mac Win ] external/wpt/accelerometer/Accelerometer-iframe-access.https.html [ Failure ]
 
 # Sheriff 2018-06-29
-crbug.com/859064 [ Linux Win10 Mac10.13 ] http/tests/devtools/console-resource-errors.js [ Failure ]
+crbug.com/859064 http/tests/devtools/console-resource-errors.js [ Pass Failure ]
 crbug.com/859169 [ Win7 ] http/tests/devtools/layers/layer-scroll-rects-get.js [ Failure Pass ]
 crbug.com/859270 [ Mac10.12 ] external/wpt/gyroscope/Gyroscope-iframe-access.https.html [ Timeout ]
 
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 1bbad14..b2796c2 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -187,6 +187,12 @@
      {}
     ]
    ],
+   "console/console-timing-logging-manual.html": [
+    [
+     "/console/console-timing-logging-manual.html",
+     {}
+    ]
+   ],
    "css/CSS2/cascade/at-import-008.xht": [
     [
      "/css/CSS2/cascade/at-import-008.xht",
@@ -104882,6 +104888,11 @@
      {}
     ]
    ],
+   "cookie-store/serviceworker_cookieStore_subscriptions_eventhandler_attribute.js": [
+    [
+     {}
+    ]
+   ],
    "cookie-store/serviceworker_cookieStore_subscriptions_mismatch.js": [
     [
      {}
@@ -177198,6 +177209,12 @@
      {}
     ]
    ],
+   "2dcontext/imagebitmap/createImageBitmap-bounds.html": [
+    [
+     "/2dcontext/imagebitmap/createImageBitmap-bounds.html",
+     {}
+    ]
+   ],
    "2dcontext/imagebitmap/createImageBitmap-drawImage.html": [
     [
      "/2dcontext/imagebitmap/createImageBitmap-drawImage.html",
@@ -184440,6 +184457,24 @@
      {}
     ]
    ],
+   "client-hints/accept_ch_lifetime_cross_origin_iframe.tentative.sub.https.html": [
+    [
+     "/client-hints/accept_ch_lifetime_cross_origin_iframe.tentative.sub.https.html",
+     {}
+    ]
+   ],
+   "client-hints/accept_ch_lifetime_same_origin_iframe.tentative.https.html": [
+    [
+     "/client-hints/accept_ch_lifetime_same_origin_iframe.tentative.https.html",
+     {}
+    ]
+   ],
+   "client-hints/accept_ch_lifetime_subresource.tentative.https.html": [
+    [
+     "/client-hints/accept_ch_lifetime_subresource.tentative.https.html",
+     {}
+    ]
+   ],
    "client-hints/accept_ch_malformed_header.https.html": [
     [
      "/client-hints/accept_ch_malformed_header.https.html",
@@ -187192,6 +187227,12 @@
      {}
     ]
    ],
+   "cookie-store/serviceworker_cookieStore_subscriptions_eventhandler_attribute.tentative.https.html": [
+    [
+     "/cookie-store/serviceworker_cookieStore_subscriptions_eventhandler_attribute.tentative.https.html",
+     {}
+    ]
+   ],
    "cookie-store/serviceworker_cookieStore_subscriptions_mismatch.tentative.https.html": [
     [
      "/cookie-store/serviceworker_cookieStore_subscriptions_mismatch.tentative.https.html",
@@ -209976,6 +210017,12 @@
      {}
     ]
    ],
+   "fetch/api/abort/destroyed-context.html": [
+    [
+     "/fetch/api/abort/destroyed-context.html",
+     {}
+    ]
+   ],
    "fetch/api/abort/general.any.js": [
     [
      "/fetch/api/abort/general.any.html",
@@ -268299,6 +268346,10 @@
    "5da74cfd37ef072aa5b50c9a5fb658754984216b",
    "support"
   ],
+  "2dcontext/imagebitmap/createImageBitmap-bounds.html": [
+   "cf1d9de3474c61c5827094cead43313883bc2408",
+   "testharness"
+  ],
   "2dcontext/imagebitmap/createImageBitmap-drawImage.html": [
    "adef50e6043c6ecb80bdc4a6b7f9d9a599a80656",
    "testharness"
@@ -274468,7 +274519,7 @@
    "support"
   ],
   "client-hints/accept_ch.tentative.https.html": [
-   "342de3ae30d962249bc0c282aac5b6e4192badfd",
+   "64f3e60bbc14c208a2fbe8193c694429fe394b31",
    "testharness"
   ],
   "client-hints/accept_ch.tentative.sub.https.html": [
@@ -274480,7 +274531,19 @@
    "support"
   ],
   "client-hints/accept_ch_lifetime.tentative.https.html": [
-   "58a6a6dafb4a6a3e8daa8742a1da137399353370",
+   "0e1756a8ea48e53011ada28ed0fa6070a0713691",
+   "testharness"
+  ],
+  "client-hints/accept_ch_lifetime_cross_origin_iframe.tentative.sub.https.html": [
+   "0006c59d1d9c305e94dfe60511c00539fb1f0887",
+   "testharness"
+  ],
+  "client-hints/accept_ch_lifetime_same_origin_iframe.tentative.https.html": [
+   "020fc61613776711177970917ddaacf3ed641a82",
+   "testharness"
+  ],
+  "client-hints/accept_ch_lifetime_subresource.tentative.https.html": [
+   "b6235b48fa3132c5f5e0cb6187f25134abdee57e",
    "testharness"
   ],
   "client-hints/accept_ch_malformed_header.https.html": [
@@ -274524,15 +274587,15 @@
    "support"
   ],
   "client-hints/resources/accept_ch_lifetime.html.headers": [
-   "6e96c4ec282ce390e9becb2c50944031fb36f4a0",
+   "22488fcaec4a0a0f227b972ccc8c911e006f3286",
    "support"
   ],
   "client-hints/resources/do_not_expect_client_hints_headers.html": [
-   "f48190cb980ceef479f6858cd6cc121d136c52a3",
+   "0c036c2a388518922878380659da0f7e13d20543",
    "support"
   ],
   "client-hints/resources/expect_client_hints_headers.html": [
-   "88247405d94960fc58d49b0969f5c9357ee84fad",
+   "1fcc20d9ff0da7712aeeaa10db51fffb2fd97c50",
    "support"
   ],
   "clipboard-apis/META.yml": [
@@ -274951,6 +275014,10 @@
    "ee18f8a672534b478ca15990026638a73588fcf4",
    "testharness"
   ],
+  "console/console-timing-logging-manual.html": [
+   "8b2d2e8d6675efacf99f49fec95c8be52f38407e",
+   "manual"
+  ],
   "content-security-policy/META.yml": [
    "5819f0331b11875efb46ad15e02d28f59770cc9d",
    "support"
@@ -277644,7 +277711,7 @@
    "testharness"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions.js": [
-   "7e140635e7587de1c606a0faf4a0bf8d8eb8c41e",
+   "7197cdc912d381a258a7b80daaa0d12e20a66fe5",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions.tentative.https.html": [
@@ -277652,7 +277719,7 @@
    "testharness"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_basic.js": [
-   "9b477518ee4c8cdc103d3cab11cca371b7b2f72d",
+   "503a93f435cf7784ff2b98dc7c3f5d1a1ba1fb14",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_basic.tentative.https.html": [
@@ -277660,15 +277727,23 @@
    "testharness"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_empty.js": [
-   "fd8cf9d3dab06824cf0497c44a388c0cea7d02d6",
+   "a90b1e59e0708838ad84618c4acfb6291ec82bd9",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_empty.tentative.https.html": [
    "3f8ec6177bc54738213fab8a1f8947d58714456d",
    "testharness"
   ],
+  "cookie-store/serviceworker_cookieStore_subscriptions_eventhandler_attribute.js": [
+   "4cc19c733cea09c1143dba9ef017ccb59aee8ddc",
+   "support"
+  ],
+  "cookie-store/serviceworker_cookieStore_subscriptions_eventhandler_attribute.tentative.https.html": [
+   "e0d44d998137cea66fc66d88a12b485386962b34",
+   "testharness"
+  ],
   "cookie-store/serviceworker_cookieStore_subscriptions_mismatch.js": [
-   "fa57006fdb09070feb6c7a83553d300d725761b6",
+   "464447630cdf01b80e4469fb79756c9898653cc4",
    "support"
   ],
   "cookie-store/serviceworker_cookieStore_subscriptions_mismatch.tentative.https.html": [
@@ -352743,6 +352818,10 @@
    "9465007a35059e9d72d4ab1dd8bff0d44f47c3d6",
    "testharness"
   ],
+  "fetch/api/abort/destroyed-context.html": [
+   "5cc67576c6b355dcb16b7934f075506b1ebc970b",
+   "testharness"
+  ],
   "fetch/api/abort/general-serviceworker.https-expected.txt": [
    "4881cf0f195fffbbe3ab01348d5ef09eea07b65a",
    "support"
@@ -353592,7 +353671,7 @@
    "testharness"
   ],
   "fetch/api/response/response-cancel-stream.html": [
-   "453323c2a0f9a908966df3cb53211c0b0a1fa19d",
+   "ad839d3e6234d16aa61338b732f765572cf8291f",
    "testharness"
   ],
   "fetch/api/response/response-clone-expected.txt": [
@@ -375752,7 +375831,7 @@
    "support"
   ],
   "interfaces/cookie-store.idl": [
-   "468487d9aee05767b52a112275155fa883720aa0",
+   "fe873252f8a58c66f736fbabd90d6d37a15df139",
    "support"
   ],
   "interfaces/cors-rfc1918.idl": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-bounds.html b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-bounds.html
new file mode 100644
index 0000000..544bd77
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-bounds.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<title>createImageBitmap: clipping to the bitmap</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/canvas-tests.js"></script>
+<script>
+promise_test(function(t) {
+    return new Promise(function(resolve, reject) {
+        const image = new Image();
+        image.onload = function() { resolve(image); };
+        image.onerror = function() { reject(); };
+        image.src = "/images/green-16x16.png";
+    }).then(function(image) {
+        return createImageBitmap(image, 8, 8, 16, 16);
+    }).then(function(imageBitmap) {
+        const color = 204;
+
+        const canvas = document.createElement("canvas");
+        canvas.width = 16;
+        canvas.height = 16;
+
+        // debug
+        document.body.appendChild(canvas);
+        canvas.setAttribute("style", "width: 100px; height: 100px;");
+
+        const ctx = canvas.getContext("2d");
+        ctx.fillStyle = `rgb(${color}, ${color}, ${color})`;
+        ctx.fillRect(0, 0, 20, 20);
+        ctx.drawImage(imageBitmap, 0, 0);
+
+        const expected = [
+            [ 4,  4, 0,255,0,255],
+            [12,  4, color,color,color,255],
+            [ 4, 12, color,color,color,255],
+            [12, 12, color,color,color,255],
+        ];
+        for (let [x, y, r, g, b, a] of expected) {
+            _assertPixel(canvas, x,y, r,g,b,a, `${x},${y}`, `${r},${g},${b},${a}`);
+        }
+
+    });
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/console/console-timing-logging-manual.html b/third_party/WebKit/LayoutTests/external/wpt/console/console-timing-logging-manual.html
new file mode 100644
index 0000000..3b9e5ce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/console/console-timing-logging-manual.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Console Timing Methods - Logging Manual Test</title>
+<meta name="author" title="Dominic Farolino" href="mailto:domfarolino@gmail.com">
+<meta name="assert" content="Console timing methods">
+<link rel="help" href="https://console.spec.whatwg.org/#timing">
+</head>
+<body>
+<p>Open the console inside the developer tools. It should contain entries whose contents are:</p>
+<p><code>default: &lt;some time></code></p>
+<p><code>default: &lt;some time></code></p>
+
+<p><code>default: &lt;some time></code></p>
+<p><code>default: &lt;some time> extra data</code></p>
+<p><code>default: &lt;some time></code></p>
+
+<p><code>default: &lt;some time></code></p>
+<p><code>default: &lt;some time> extra data</code></p>
+<p><code>default: &lt;some time></code></p>
+
+<p><code>default: &lt;some time></code></p>
+<p><code>default: &lt;some time> extra data</code></p>
+<p><code>default: &lt;some time></code></p>
+
+<p><code>custom toString(): &lt;some time></code></p>
+<p><code>custom toString(): &lt;some time> extra data</code></p>
+<p><code>custom toString(): &lt;some time></code></p>
+
+<p><code>a label: &lt;some time></code></p>
+<p><code>a label: &lt;some time> extra data</code></p>
+<p><code>a label: &lt;some time></code></p>
+
+<p style="color:grey;">[some warning message indicating that a timer for label "b" does not exist]</p>
+
+<script>
+console.time();
+console.timeLog();
+console.timeEnd();
+
+console.time(undefined);
+console.timeLog(undefined);
+console.timeLog(undefined, "extra data");
+console.timeEnd(undefined);
+
+console.time("default");
+console.timeLog("default");
+console.timeLog("default", "extra data");
+console.timeEnd("default");
+
+console.time({toString() {return "default"}});
+console.timeLog({toString() {return "default"}});
+console.timeLog({toString() {return "default"}}, "extra data");
+console.timeEnd({toString() {return "default"}});
+
+console.time({toString() {return "custom toString()"}});
+console.timeLog({toString() {return "custom toString()"}});
+console.timeLog({toString() {return "custom toString()"}}, "extra data");
+console.timeEnd({toString() {return "custom toString()"}});
+
+console.time("a label");
+console.timeLog("a label");
+console.timeLog("a label", "extra data");
+console.timeEnd("a label");
+
+console.timeLog("b"); // should produce a warning
+console.timeEnd("b"); // should produce a warning
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-color-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-color-expected.txt
index ae88111..5ae75b67 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-color-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-color-expected.txt
@@ -1,33 +1,43 @@
 This is a testharness.js-based test.
 PASS Test that logical border-*-color properties are supported.
 PASS Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: ltr; '.
+PASS Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: rtl; '.
+PASS Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: rtl; '.
+PASS Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 FAIL Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', border-bottom-color expected "rgb(1, 1, 1)" but got "rgb(4, 4, 4)"
+FAIL Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', border-bottom-color expected "rgb(1, 1, 1)" but got "rgb(0, 0, 0)"
 FAIL Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'border-inline-start-color' last on single declaration, 'writing-mode: sideways-rl; direction: rtl; ', border-block-end-color expected "rgb(1, 1, 1)" but got "rgb(4, 4, 4)"
 FAIL Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'border-inline-start-color', two declarations, 'writing-mode: sideways-rl; direction: rtl; ', border-block-end-color expected "rgb(1, 1, 1)" but got "rgb(4, 4, 4)"
 PASS Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: ltr; '.
+PASS Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 FAIL Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', border-top-color expected "rgb(1, 1, 1)" but got "rgb(3, 3, 3)"
+FAIL Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', border-top-color expected "rgb(1, 1, 1)" but got "rgb(0, 0, 0)"
 FAIL Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'border-inline-start-color' last on single declaration, 'writing-mode: sideways-rl; direction: ltr; ', border-left-color expected "rgb(1, 1, 1)" but got "rgb(5, 5, 5)"
 FAIL Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'border-inline-start-color', two declarations, 'writing-mode: sideways-rl; direction: ltr; ', border-left-color expected "rgb(1, 1, 1)" but got "rgb(5, 5, 5)"
 PASS Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: rtl; '.
+PASS Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 FAIL Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', border-bottom-color expected "rgb(1, 1, 1)" but got "rgb(4, 4, 4)"
+FAIL Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', border-bottom-color expected "rgb(1, 1, 1)" but got "rgb(0, 0, 0)"
 FAIL Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'border-inline-start-color' last on single declaration, 'writing-mode: sideways-lr; direction: ltr; ', border-left-color expected "rgb(1, 1, 1)" but got "rgb(5, 5, 5)"
 FAIL Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'border-inline-start-color', two declarations, 'writing-mode: sideways-lr; direction: ltr; ', border-left-color expected "rgb(1, 1, 1)" but got "rgb(5, 5, 5)"
 PASS Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: ltr; '.
+PASS Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 FAIL Test that logical border-*-color properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', border-top-color expected "rgb(1, 1, 1)" but got "rgb(3, 3, 3)"
+FAIL Test that border-*-color shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', border-top-color expected "rgb(1, 1, 1)" but got "rgb(0, 0, 0)"
 FAIL Test that border-*-color properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'border-inline-start-color' last on single declaration, 'writing-mode: sideways-lr; direction: rtl; ', border-block-start-color expected "rgb(1, 1, 1)" but got "rgb(3, 3, 3)"
 FAIL Test that border-*-color properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'border-inline-start-color', two declarations, 'writing-mode: sideways-lr; direction: rtl; ', border-block-start-color expected "rgb(1, 1, 1)" but got "rgb(3, 3, 3)"
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-color.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-color.html
index 9cc7e244..c279ef4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-color.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-color.html
@@ -3,7 +3,7 @@
 <title>CSS Logical Properties: Flow-Relative Border Colors</title>
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
 <link rel="help" href="https://drafts.csswg.org/css-logical/#border-color">
-<meta name="assert" content="This test checks the interaction of the flow-relative border-*-color longhand properties with the physical ones in different writing modes." />
+<meta name="assert" content="This test checks the interaction of the flow-relative border-*-color properties with the physical ones in different writing modes." />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-shorthands-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-shorthands-expected.txt
index be33641..e0dc976f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-shorthands-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-shorthands-expected.txt
@@ -1,33 +1,43 @@
 This is a testharness.js-based test.
 PASS Test that logical border-* properties are supported.
 PASS Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: ltr; '.
+PASS Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: rtl; '.
+PASS Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: rtl; '.
+PASS Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 FAIL Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', border-bottom expected "1px solid rgb(1, 1, 1)" but got "4px double rgb(4, 4, 4)"
+FAIL Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', border-bottom expected "1px solid rgb(1, 1, 1)" but got "0px none rgb(0, 0, 0)"
 FAIL Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'border-inline-start' last on single declaration, 'writing-mode: sideways-rl; direction: rtl; ', border-block-end expected "1px solid rgb(1, 1, 1)" but got "4px double rgb(4, 4, 4)"
 FAIL Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'border-inline-start', two declarations, 'writing-mode: sideways-rl; direction: rtl; ', border-block-end expected "1px solid rgb(1, 1, 1)" but got "4px double rgb(4, 4, 4)"
 PASS Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: ltr; '.
+PASS Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 FAIL Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', border-top expected "1px solid rgb(1, 1, 1)" but got "3px dotted rgb(3, 3, 3)"
+FAIL Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', border-top expected "1px solid rgb(1, 1, 1)" but got "0px none rgb(0, 0, 0)"
 FAIL Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'border-inline-start' last on single declaration, 'writing-mode: sideways-rl; direction: ltr; ', border-left expected "1px solid rgb(1, 1, 1)" but got "5px groove rgb(5, 5, 5)"
 FAIL Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'border-inline-start', two declarations, 'writing-mode: sideways-rl; direction: ltr; ', border-left expected "1px solid rgb(1, 1, 1)" but got "5px groove rgb(5, 5, 5)"
 PASS Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: rtl; '.
+PASS Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 FAIL Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', border-bottom expected "1px solid rgb(1, 1, 1)" but got "4px double rgb(4, 4, 4)"
+FAIL Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', border-bottom expected "1px solid rgb(1, 1, 1)" but got "0px none rgb(0, 0, 0)"
 FAIL Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'border-inline-start' last on single declaration, 'writing-mode: sideways-lr; direction: ltr; ', border-left expected "1px solid rgb(1, 1, 1)" but got "5px groove rgb(5, 5, 5)"
 FAIL Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'border-inline-start', two declarations, 'writing-mode: sideways-lr; direction: ltr; ', border-left expected "1px solid rgb(1, 1, 1)" but got "5px groove rgb(5, 5, 5)"
 PASS Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: ltr; '.
+PASS Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 FAIL Test that logical border-* properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', border-top expected "1px solid rgb(1, 1, 1)" but got "3px dotted rgb(3, 3, 3)"
+FAIL Test that border-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', border-top expected "1px solid rgb(1, 1, 1)" but got "0px none rgb(0, 0, 0)"
 FAIL Test that border-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'border-inline-start' last on single declaration, 'writing-mode: sideways-lr; direction: rtl; ', border-block-start expected "1px solid rgb(1, 1, 1)" but got "3px dotted rgb(3, 3, 3)"
 FAIL Test that border-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'border-inline-start', two declarations, 'writing-mode: sideways-lr; direction: rtl; ', border-block-start expected "1px solid rgb(1, 1, 1)" but got "3px dotted rgb(3, 3, 3)"
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-style-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-style-expected.txt
index a509119..7f039fb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-style-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-style-expected.txt
@@ -1,33 +1,43 @@
 This is a testharness.js-based test.
 PASS Test that logical border-*-style properties are supported.
 PASS Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: ltr; '.
+PASS Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: rtl; '.
+PASS Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: rtl; '.
+PASS Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 FAIL Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', border-bottom-style expected "solid" but got "double"
+FAIL Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', border-bottom-style expected "solid" but got "none"
 FAIL Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'border-inline-start-style' last on single declaration, 'writing-mode: sideways-rl; direction: rtl; ', border-block-end-style expected "solid" but got "double"
 FAIL Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'border-inline-start-style', two declarations, 'writing-mode: sideways-rl; direction: rtl; ', border-block-end-style expected "solid" but got "double"
 PASS Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: ltr; '.
+PASS Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 FAIL Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', border-top-style expected "solid" but got "dotted"
+FAIL Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', border-top-style expected "solid" but got "none"
 FAIL Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'border-inline-start-style' last on single declaration, 'writing-mode: sideways-rl; direction: ltr; ', border-left-style expected "solid" but got "groove"
 FAIL Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'border-inline-start-style', two declarations, 'writing-mode: sideways-rl; direction: ltr; ', border-left-style expected "solid" but got "groove"
 PASS Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: rtl; '.
+PASS Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 FAIL Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', border-bottom-style expected "solid" but got "double"
+FAIL Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', border-bottom-style expected "solid" but got "none"
 FAIL Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'border-inline-start-style' last on single declaration, 'writing-mode: sideways-lr; direction: ltr; ', border-left-style expected "solid" but got "groove"
 FAIL Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'border-inline-start-style', two declarations, 'writing-mode: sideways-lr; direction: ltr; ', border-left-style expected "solid" but got "groove"
 PASS Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: ltr; '.
+PASS Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 FAIL Test that logical border-*-style properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', border-top-style expected "solid" but got "dotted"
+FAIL Test that border-*-style shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', border-top-style expected "solid" but got "none"
 FAIL Test that border-*-style properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'border-inline-start-style' last on single declaration, 'writing-mode: sideways-lr; direction: rtl; ', border-block-start-style expected "solid" but got "dotted"
 FAIL Test that border-*-style properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'border-inline-start-style', two declarations, 'writing-mode: sideways-lr; direction: rtl; ', border-block-start-style expected "solid" but got "dotted"
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-style.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-style.html
index 6a32f4e2..4954bac3 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-style.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-style.html
@@ -3,7 +3,7 @@
 <title>CSS Logical Properties: Flow-Relative Border Styles</title>
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
 <link rel="help" href="https://drafts.csswg.org/css-logical/#border-style">
-<meta name="assert" content="This test checks the interaction of the flow-relative border-*-style longhand properties with the physical ones in different writing modes." />
+<meta name="assert" content="This test checks the interaction of the flow-relative border-*-style properties with the physical ones in different writing modes." />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-width-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-width-expected.txt
index a2f56397..3f45255 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-width-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-width-expected.txt
@@ -1,33 +1,43 @@
 This is a testharness.js-based test.
 PASS Test that logical border-*-width properties are supported.
 PASS Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: ltr; '.
+PASS Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: rtl; '.
+PASS Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: rtl; '.
+PASS Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 FAIL Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', border-bottom-width expected "1px" but got "4px"
+FAIL Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', border-bottom-width expected "1px" but got "3px"
 FAIL Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'border-inline-start-width' last on single declaration, 'writing-mode: sideways-rl; direction: rtl; ', border-block-end-width expected "1px" but got "4px"
 FAIL Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'border-inline-start-width', two declarations, 'writing-mode: sideways-rl; direction: rtl; ', border-block-end-width expected "1px" but got "4px"
 PASS Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: ltr; '.
+PASS Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 FAIL Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', border-top-width expected "1px" but got "3px"
+FAIL Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', border-top-width expected "1px" but got "3px"
 FAIL Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'border-inline-start-width' last on single declaration, 'writing-mode: sideways-rl; direction: ltr; ', border-left-width expected "1px" but got "5px"
 FAIL Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'border-inline-start-width', two declarations, 'writing-mode: sideways-rl; direction: ltr; ', border-left-width expected "1px" but got "5px"
 PASS Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: rtl; '.
+PASS Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 FAIL Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', border-bottom-width expected "1px" but got "4px"
+FAIL Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', border-bottom-width expected "1px" but got "3px"
 FAIL Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'border-inline-start-width' last on single declaration, 'writing-mode: sideways-lr; direction: ltr; ', border-left-width expected "1px" but got "5px"
 FAIL Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'border-inline-start-width', two declarations, 'writing-mode: sideways-lr; direction: ltr; ', border-left-width expected "1px" but got "5px"
 PASS Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: ltr; '.
+PASS Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 FAIL Test that logical border-*-width properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', border-top-width expected "1px" but got "3px"
+FAIL Test that border-*-width shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', border-top-width expected "1px" but got "3px"
 FAIL Test that border-*-width properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'border-inline-start-width' last on single declaration, 'writing-mode: sideways-lr; direction: rtl; ', border-block-start-width expected "1px" but got "3px"
 FAIL Test that border-*-width properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'border-inline-start-width', two declarations, 'writing-mode: sideways-lr; direction: rtl; ', border-block-start-width expected "1px" but got "3px"
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-width.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-width.html
index 40d6634..7396ce7 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-width.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-border-width.html
@@ -3,7 +3,7 @@
 <title>CSS Logical Properties: Flow-Relative Border Widths</title>
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
 <link rel="help" href="https://drafts.csswg.org/css-logical/#border-width">
-<meta name="assert" content="This test checks the interaction of the flow-relative border-*-width longhand properties with the physical ones in different writing modes." />
+<meta name="assert" content="This test checks the interaction of the flow-relative border-*-width properties with the physical ones in different writing modes." />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-inset-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-inset-expected.txt
index 38f431b6..62e3fc56 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-inset-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-inset-expected.txt
@@ -1,33 +1,43 @@
 This is a testharness.js-based test.
 FAIL Test that logical inset-* properties are supported. assert_equals: logical properties in inline style, inset-inline-start expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: horizontal-tb; direction: ltr; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: horizontal-tb; direction: ltr; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: horizontal-tb; direction: ltr; ', left expected "5px" but got "1px"
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: horizontal-tb; direction: ltr; ', left expected "5px" but got "1px"
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: horizontal-tb; direction: rtl; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: horizontal-tb; direction: rtl; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: horizontal-tb; direction: rtl; ', inset-inline-end expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: horizontal-tb; direction: rtl; ', inset-inline-end expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: vertical-rl; direction: rtl; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: vertical-rl; direction: rtl; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: vertical-rl; direction: rtl; ', inset-block-end expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: vertical-rl; direction: rtl; ', inset-block-end expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: sideways-rl; direction: rtl; ', inset-block-end expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: sideways-rl; direction: rtl; ', inset-block-end expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: vertical-rl; direction: ltr; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: vertical-rl; direction: ltr; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: vertical-rl; direction: ltr; ', inset-block-end expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: vertical-rl; direction: ltr; ', inset-block-end expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: sideways-rl; direction: ltr; ', inset-block-end expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: sideways-rl; direction: ltr; ', inset-block-end expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: vertical-lr; direction: rtl; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: vertical-lr; direction: rtl; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: vertical-lr; direction: rtl; ', inset-block-start expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: vertical-lr; direction: rtl; ', inset-block-start expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: sideways-lr; direction: ltr; ', inset-block-start expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: sideways-lr; direction: ltr; ', inset-block-start expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: vertical-lr; direction: ltr; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: vertical-lr; direction: ltr; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: vertical-lr; direction: ltr; ', inset-block-start expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: vertical-lr; direction: ltr; ', inset-block-start expected "1px" but got ""
 FAIL Test that logical inset-* properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', inset-inline-start expected "1px" but got ""
+FAIL Test that inset-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', inset-inline-start expected "1px" but got ""
 FAIL Test that inset-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'inset-inline-start' last on single declaration, 'writing-mode: sideways-lr; direction: rtl; ', inset-block-start expected "1px" but got ""
 FAIL Test that inset-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'inset-inline-start', two declarations, 'writing-mode: sideways-lr; direction: rtl; ', inset-block-start expected "1px" but got ""
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-inset.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-inset.html
index 0741c79..005a269 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-inset.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-inset.html
@@ -3,7 +3,7 @@
 <title>CSS Logical Properties: Flow-Relative Offsets</title>
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
 <link rel="help" href="https://drafts.csswg.org/css-logical/#inset-properties">
-<meta name="assert" content="This test checks the interaction of the flow-relative inset-* longhand properties with the physical ones in different writing modes." />
+<meta name="assert" content="This test checks the interaction of the flow-relative inset-* properties with the physical ones in different writing modes." />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-margin-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-margin-expected.txt
index f874011..080766a6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-margin-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-margin-expected.txt
@@ -1,33 +1,43 @@
 This is a testharness.js-based test.
 PASS Test that logical margin-* properties are supported.
 PASS Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: ltr; '.
+PASS Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: rtl; '.
+PASS Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: rtl; '.
+PASS Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 FAIL Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', margin-bottom expected "1px" but got "4px"
+FAIL Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', margin-bottom expected "1px" but got "0px"
 FAIL Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'margin-inline-start' last on single declaration, 'writing-mode: sideways-rl; direction: rtl; ', margin-block-end expected "1px" but got "4px"
 FAIL Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'margin-inline-start', two declarations, 'writing-mode: sideways-rl; direction: rtl; ', margin-block-end expected "1px" but got "4px"
 PASS Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: ltr; '.
+PASS Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 FAIL Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', margin-top expected "1px" but got "3px"
+FAIL Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', margin-top expected "1px" but got "0px"
 FAIL Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'margin-inline-start' last on single declaration, 'writing-mode: sideways-rl; direction: ltr; ', margin-left expected "1px" but got "5px"
 FAIL Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'margin-inline-start', two declarations, 'writing-mode: sideways-rl; direction: ltr; ', margin-left expected "1px" but got "5px"
 PASS Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: rtl; '.
+PASS Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 FAIL Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', margin-bottom expected "1px" but got "4px"
+FAIL Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', margin-bottom expected "1px" but got "0px"
 FAIL Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'margin-inline-start' last on single declaration, 'writing-mode: sideways-lr; direction: ltr; ', margin-left expected "1px" but got "5px"
 FAIL Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'margin-inline-start', two declarations, 'writing-mode: sideways-lr; direction: ltr; ', margin-left expected "1px" but got "5px"
 PASS Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: ltr; '.
+PASS Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 FAIL Test that logical margin-* properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', margin-top expected "1px" but got "3px"
+FAIL Test that margin-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', margin-top expected "1px" but got "0px"
 FAIL Test that margin-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'margin-inline-start' last on single declaration, 'writing-mode: sideways-lr; direction: rtl; ', margin-block-start expected "1px" but got "3px"
 FAIL Test that margin-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'margin-inline-start', two declarations, 'writing-mode: sideways-lr; direction: rtl; ', margin-block-start expected "1px" but got "3px"
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-margin.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-margin.html
index 3ad6c8b..5fcd5c38 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-margin.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-margin.html
@@ -3,7 +3,7 @@
 <title>CSS Logical Properties: Flow-Relative Margins</title>
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
 <link rel="help" href="https://drafts.csswg.org/css-logical/#margin-properties">
-<meta name="assert" content="This test checks the interaction of the flow-relative margin-* longhand properties with the physical ones in different writing modes." />
+<meta name="assert" content="This test checks the interaction of the flow-relative margin-* properties with the physical ones in different writing modes." />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-padding-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-padding-expected.txt
index 1ef801d..7c041b8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-padding-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-padding-expected.txt
@@ -1,33 +1,43 @@
 This is a testharness.js-based test.
 PASS Test that logical padding-* properties are supported.
 PASS Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: ltr; '.
+PASS Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: ltr; '.
 PASS Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: horizontal-tb; direction: rtl; '.
+PASS Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: horizontal-tb; direction: rtl; '.
 PASS Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: rtl; '.
+PASS Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 PASS Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: rtl; '.
 FAIL Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', padding-bottom expected "1px" but got "4px"
+FAIL Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: rtl; ', padding-bottom expected "1px" but got "0px"
 FAIL Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'padding-inline-start' last on single declaration, 'writing-mode: sideways-rl; direction: rtl; ', padding-block-end expected "1px" but got "4px"
 FAIL Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: rtl; '. assert_equals: 'padding-inline-start', two declarations, 'writing-mode: sideways-rl; direction: rtl; ', padding-block-end expected "1px" but got "4px"
 PASS Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: vertical-rl; direction: ltr; '.
+PASS Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 PASS Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-rl; direction: ltr; '.
 FAIL Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', padding-top expected "1px" but got "3px"
+FAIL Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-rl; direction: ltr; ', padding-top expected "1px" but got "0px"
 FAIL Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'padding-inline-start' last on single declaration, 'writing-mode: sideways-rl; direction: ltr; ', padding-left expected "1px" but got "5px"
 FAIL Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-rl; direction: ltr; '. assert_equals: 'padding-inline-start', two declarations, 'writing-mode: sideways-rl; direction: ltr; ', padding-left expected "1px" but got "5px"
 PASS Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: rtl; '.
+PASS Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 PASS Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: rtl; '.
 FAIL Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', padding-bottom expected "1px" but got "4px"
+FAIL Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: ltr; ', padding-bottom expected "1px" but got "0px"
 FAIL Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'padding-inline-start' last on single declaration, 'writing-mode: sideways-lr; direction: ltr; ', padding-left expected "1px" but got "5px"
 FAIL Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: ltr; '. assert_equals: 'padding-inline-start', two declarations, 'writing-mode: sideways-lr; direction: ltr; ', padding-left expected "1px" but got "5px"
 PASS Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: vertical-lr; direction: ltr; '.
+PASS Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 PASS Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: vertical-lr; direction: ltr; '.
 FAIL Test that logical padding-* properties share computed values with their physical associates, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: logical properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', padding-top expected "1px" but got "3px"
+FAIL Test that padding-* shorthands set the computed value of both logical and physical longhands, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: shorthand properties on one declaration, writing mode properties on another, 'writing-mode: sideways-lr; direction: rtl; ', padding-top expected "1px" but got "0px"
 FAIL Test that padding-* properties honor order of appearance when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'padding-inline-start' last on single declaration, 'writing-mode: sideways-lr; direction: rtl; ', padding-block-start expected "1px" but got "3px"
 FAIL Test that padding-* properties honor selector specificty when both logical and physical associates are declared, with 'writing-mode: sideways-lr; direction: rtl; '. assert_equals: 'padding-inline-start', two declarations, 'writing-mode: sideways-lr; direction: rtl; ', padding-block-start expected "1px" but got "3px"
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-padding.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-padding.html
index 9d99721..b3f6b6f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-padding.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/logical-box-padding.html
@@ -3,7 +3,7 @@
 <title>CSS Logical Properties: Flow-Relative Padding</title>
 <link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
 <link rel="help" href="https://drafts.csswg.org/css-logical/#padding-properties">
-<meta name="assert" content="This test checks the interaction of the flow-relative padding-* longhand properties with the physical ones in different writing modes." />
+<meta name="assert" content="This test checks the interaction of the flow-relative padding-* properties with the physical ones in different writing modes." />
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/resources/test-box-properties.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/resources/test-box-properties.js
index da47747..5170769 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/resources/test-box-properties.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical/resources/test-box-properties.js
@@ -90,6 +90,9 @@
    *   }, logical: {
    *     inlineStart: "margin-inline-start", inlineEnd: "margin-inline-end",
    *     blockStart: "margin-block-start", blockEnd: "margin-block-end",
+   *   }, shorthands: {
+   *     inline: ["margin-inline-start", "margin-inline-end"],
+   *     block: ["margin-block-start", "margin-block-end"],
    *   }, type: ["length"], prerequisites: "...", property: "'margin-*'" }
    *
    * @param {string} property
@@ -105,9 +108,18 @@
   exports.createBoxPropertyGroup = function(property, descriptor) {
     const logical = {};
     const physical = {};
-    for (const logicalSide of ["inline-start", "inline-end", "block-start", "block-end"]) {
-      const camelCase = logicalSide.replace(/-(.)/g, (match, $1) => $1.toUpperCase());
-      logical[camelCase] = property.replace("*", logicalSide);
+    const shorthands = {};
+    for (const axis of ["inline", "block"]) {
+      const shorthand = property.replace("*", axis);
+      const longhands = [];
+      shorthands[shorthand] = longhands;
+      for (const side of ["start", "end"]) {
+        const logicalSide = axis + "-" + side;
+        const camelCase = logicalSide.replace(/-(.)/g, (match, $1) => $1.toUpperCase());
+        const longhand = property.replace("*", logicalSide);
+        logical[camelCase] = longhand;
+        longhands.push(longhand);
+      }
     }
     const isInset = property === "inset-*";
     let prerequisites = "";
@@ -116,7 +128,7 @@
       prerequisites += makeDeclaration(descriptor.prerequisites, physicalSide);
     }
     const type = [].concat(descriptor.type);
-    return {name, logical, physical, type, prerequisites, property};
+    return {name, logical, physical, shorthands, type, prerequisites, property};
   };
 
   /**
@@ -153,6 +165,7 @@
     });
     const logicals = Object.values(group.logical);
     const physicals = Object.values(group.physical);
+    const shorthands = group.shorthands ? Object.entries(group.shorthands) : null;
 
     test(function() {
       const expected = [];
@@ -196,6 +209,33 @@
         }, `Test that logical ${group.property} properties share computed values `
          + `with their physical associates, with '${writingModeDecl}'.`);
 
+
+        // Test logical shorthand properties.
+        if (shorthands) {
+          test(function() {
+            for (const [shorthand, longhands] of shorthands) {
+              let shorthandValues;
+              if (group.type.length > 1) {
+                shorthandValues = [values[0]];
+              } else {
+                shorthandValues = testValues[group.type].slice(0, longhands.length);
+              }
+              const decl = group.prerequisites + `${shorthand}: ${shorthandValues.join(" ")}; `;
+              const expected = [];
+              for (let [i, longhand] of longhands.entries()) {
+                const longhandValue = shorthandValues[group.type.length > 1 ? 0 : i];
+                expected.push([longhand, longhandValue]);
+                expected.push([associated[longhand], longhandValue]);
+              }
+              testComputedValues("shorthand properties on one declaration, writing " +
+                                 `mode properties on another, '${writingModeDecl}'`,
+                                 `.test { ${writingModeDecl} } .test { ${decl} }`,
+                                 expected);
+            }
+          }, `Test that ${group.property} shorthands set the computed value of both `
+           + `logical and physical longhands, with '${writingModeDecl}'.`);
+        }
+
         // Test that logical and physical properties are cascaded together,
         // honoring their relative order on a single declaration
         // (a) with a single logical property after the physical ones
diff --git a/third_party/WebKit/LayoutTests/external/wpt/editing/run/delete-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/editing/run/delete-expected.txt
index 28ba42d..f1f3dfc 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/editing/run/delete-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/editing/run/delete-expected.txt
@@ -1 +1,6746 @@
-#CRASHED - renderer
+This is a testharness.js-based test.
+Found 6742 tests; 6568 PASS, 174 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS [["delete",""]] "foo[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo[]bar" compare innerHTML
+PASS [["delete",""]] "foo[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>" checks for modifications to non-editable content
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>" compare innerHTML
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>" queryCommandState("delete") before
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>" queryCommandValue("delete") before
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>" queryCommandState("delete") after
+PASS [["delete",""]] "<span>foo</span>{}<span>bar</span>" queryCommandValue("delete") after
+PASS [["delete",""]] "<span>foo[</span><span>]bar</span>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span>foo[</span><span>]bar</span>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<span>foo[</span><span>]bar</span>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<span>foo</span><span>bar</span>" but got "<span>fo</span><span>bar</span>"
+PASS [["delete",""]] "<span>foo[</span><span>]bar</span>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span>foo[</span><span>]bar</span>" queryCommandState("delete") before
+PASS [["delete",""]] "<span>foo[</span><span>]bar</span>" queryCommandValue("delete") before
+PASS [["delete",""]] "<span>foo[</span><span>]bar</span>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span>foo[</span><span>]bar</span>" queryCommandState("delete") after
+PASS [["delete",""]] "<span>foo[</span><span>]bar</span>" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandIndeterm("stylewithcss") before
+FAIL [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandState("stylewithcss") before assert_equals: Wrong result returned expected false but got true
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<span style=display:none>bar</span>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<script>bar</script>[]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<script>bar</script>[]baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<script>bar</script>[]baz" compare innerHTML
+PASS [["delete",""]] "foo<script>bar</script>[]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<script>bar</script>[]baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<script>bar</script>[]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<script>bar</script>[]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<script>bar</script>[]baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<script>bar</script>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "fo&ouml;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "fo&ouml;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "fo&ouml;[]bar" compare innerHTML
+PASS [["delete",""]] "fo&ouml;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "fo&ouml;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "fo&ouml;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "fo&ouml;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "fo&ouml;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "fo&ouml;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo&#x308;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo&#x308;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo&#x308;[]bar" compare innerHTML
+PASS [["delete",""]] "foo&#x308;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo&#x308;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo&#x308;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo&#x308;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo&#x308;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo&#x308;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar" compare innerHTML
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo&#x308;&#x327;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "&ouml;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "&ouml;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "&ouml;[]bar" compare innerHTML
+PASS [["delete",""]] "&ouml;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "&ouml;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "&ouml;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "&ouml;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "&ouml;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "&ouml;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "o&#x308;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "o&#x308;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "o&#x308;[]bar" compare innerHTML
+PASS [["delete",""]] "o&#x308;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "o&#x308;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "o&#x308;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "o&#x308;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "o&#x308;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "o&#x308;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "o&#x308;&#x327;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "o&#x308;&#x327;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "o&#x308;&#x327;[]bar" compare innerHTML
+PASS [["delete",""]] "o&#x308;&#x327;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "o&#x308;&#x327;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "o&#x308;&#x327;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "o&#x308;&#x327;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "o&#x308;&#x327;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "o&#x308;&#x327;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;": execCommand("delete", false, "") return value
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;" checks for modifications to non-editable content
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;" compare innerHTML
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;" queryCommandState("delete") before
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;" queryCommandValue("delete") before
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;" queryCommandState("delete") after
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;[]&#x5dc;&#x5d5;&#x5b9;&#x5dd;" queryCommandValue("delete") after
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;": execCommand("delete", false, "") return value
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;" checks for modifications to non-editable content
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;" compare innerHTML
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;" queryCommandState("delete") before
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;" queryCommandValue("delete") before
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;" queryCommandState("delete") after
+PASS [["delete",""]] "&#x5e9;&#x5c1;&#x5b8;&#x5dc;&#x5d5;&#x5b9;[]&#x5dd;" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo</p>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo</p>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo</p>[]bar" compare innerHTML
+PASS [["delete",""]] "<p>foo</p>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo</p>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo</p>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo</p>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo</p>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo</p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br></p><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<br></p>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<br></p>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo<br></p>[]bar" compare innerHTML
+PASS [["delete",""]] "<p>foo<br></p>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<br></p>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<br></p>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<br></p>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<br></p>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<br></p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<br>bar</p>" but got "<p>foo<br>bar<br></p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<br>bar</p>" but got "<p>foo<br>bar<br></p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br></p><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<br><br></p>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<br><br></p>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p>foo<br><br></p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<br>bar</p>" but got "<p>foo<br>bar<br></p>"
+PASS [["delete",""]] "<p>foo<br><br></p>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<br><br></p>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<br><br></p>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<br><br></p>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<br><br></p>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<br><br></p>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>" compare innerHTML
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<br><br><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><div><p>[]bar</p></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo</p></div><div><p>[]bar</p></div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar" compare innerHTML
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<div><p>foo</p></div>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><p>[]bar</p></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo</div><div>[]bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<pre>foo</pre>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<pre>foo</pre>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<pre>foo</pre>[]bar" compare innerHTML
+PASS [["delete",""]] "<pre>foo</pre>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<pre>foo</pre>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<pre>foo</pre>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<pre>foo</pre>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<pre>foo</pre>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<pre>foo</pre>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<br>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<br>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<br>[]bar" compare innerHTML
+PASS [["delete",""]] "foo<br>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<br>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo<br>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<br>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<br>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo<br>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<br><b>[]bar</b>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<br><b>[]bar</b>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<br><b>[]bar</b>" compare innerHTML
+PASS [["delete",""]] "foo<br><b>[]bar</b>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<br><b>[]bar</b>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<br><b>[]bar</b>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<br><b>[]bar</b>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<br><b>[]bar</b>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<br><b>[]bar</b>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<hr>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<hr>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<hr>[]bar" compare innerHTML
+PASS [["delete",""]] "foo<hr>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<hr>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo<hr>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<hr>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<hr>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo<hr>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<hr><p>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<hr><p>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo<hr><p>[]bar" compare innerHTML
+PASS [["delete",""]] "<p>foo<hr><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<hr><p>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<hr><p>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<hr><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<hr><p>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<hr><p>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>" compare innerHTML
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo</p><br><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>" compare innerHTML
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo</p><br><br><p>[]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p><img src=/img/lion.svg><p>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar" compare innerHTML
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo<img src=/img/lion.svg>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<a>foo</a>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<a>foo</a>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<a>foo</a>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foobar" but got "<a>fo</a>bar"
+PASS [["delete",""]] "<a>foo</a>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<a>foo</a>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<a>foo</a>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<a>foo</a>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<a>foo</a>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<a>foo</a>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<a href=/>foo</a>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<a href=/>foo</a>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<a href=/>foo</a>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foobar" but got "<a href=\"/\">fo</a>bar"
+PASS [["delete",""]] "<a href=/>foo</a>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<a href=/>foo</a>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<a href=/>foo</a>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<a href=/>foo</a>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<a href=/>foo</a>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<a href=/>foo</a>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<a name=abc>foo</a>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<a name=abc>foo</a>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<a name=abc>foo</a>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foobar" but got "<a name=\"abc\">fo</a>bar"
+PASS [["delete",""]] "<a name=abc>foo</a>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<a name=abc>foo</a>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<a name=abc>foo</a>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<a name=abc>foo</a>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<a name=abc>foo</a>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<a name=abc>foo</a>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<a href=/ name=abc>foo</a>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<a href=/ name=abc>foo</a>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<a href=/ name=abc>foo</a>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foobar" but got "<a href=\"/\" name=\"abc\">fo</a>bar"
+PASS [["delete",""]] "<a href=/ name=abc>foo</a>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<a href=/ name=abc>foo</a>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<a href=/ name=abc>foo</a>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<a href=/ name=abc>foo</a>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<a href=/ name=abc>foo</a>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<a href=/ name=abc>foo</a>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<span><a>foo</a></span>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span><a>foo</a></span>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<span><a>foo</a></span>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<span>foo</span>bar" but got "<span><a>fo</a></span>bar"
+PASS [["delete",""]] "<span><a>foo</a></span>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span><a>foo</a></span>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<span><a>foo</a></span>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<span><a>foo</a></span>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span><a>foo</a></span>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<span><a>foo</a></span>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<span><a href=/>foo</a></span>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span><a href=/>foo</a></span>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<span><a href=/>foo</a></span>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<span>foo</span>bar" but got "<span><a href=\"/\">fo</a></span>bar"
+PASS [["delete",""]] "<span><a href=/>foo</a></span>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span><a href=/>foo</a></span>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<span><a href=/>foo</a></span>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<span><a href=/>foo</a></span>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span><a href=/>foo</a></span>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<span><a href=/>foo</a></span>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<span><a name=abc>foo</a></span>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span><a name=abc>foo</a></span>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<span><a name=abc>foo</a></span>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<span>foo</span>bar" but got "<span><a name=\"abc\">fo</a></span>bar"
+PASS [["delete",""]] "<span><a name=abc>foo</a></span>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span><a name=abc>foo</a></span>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<span><a name=abc>foo</a></span>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<span><a name=abc>foo</a></span>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span><a name=abc>foo</a></span>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<span><a name=abc>foo</a></span>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<span>foo</span>bar" but got "<span><a href=\"/\" name=\"abc\">fo</a></span>bar"
+PASS [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<span><a href=/ name=abc>foo</a></span>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<a>[]bar</a>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<a>[]bar</a>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<a>[]bar</a>" compare innerHTML
+PASS [["delete",""]] "foo<a>[]bar</a>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<a>[]bar</a>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<a>[]bar</a>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<a>[]bar</a>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<a>[]bar</a>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<a>[]bar</a>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<a href=/>[]bar</a>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<a href=/>[]bar</a>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<a href=/>[]bar</a>" compare innerHTML
+PASS [["delete",""]] "foo<a href=/>[]bar</a>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<a href=/>[]bar</a>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<a href=/>[]bar</a>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<a href=/>[]bar</a>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<a href=/>[]bar</a>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<a href=/>[]bar</a>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>" compare innerHTML
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<a name=abc>[]bar</a>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>" compare innerHTML
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<a href=/ name=abc>[]bar</a>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo &nbsp;[]": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo &nbsp;[]" checks for modifications to non-editable content
+PASS [["delete",""]] "foo &nbsp;[]" compare innerHTML
+PASS [["delete",""]] "foo &nbsp;[]" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo &nbsp;[]" queryCommandState("delete") before
+PASS [["delete",""]] "foo &nbsp;[]" queryCommandValue("delete") before
+PASS [["delete",""]] "foo &nbsp;[]" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo &nbsp;[]" queryCommandState("delete") after
+PASS [["delete",""]] "foo &nbsp;[]" queryCommandValue("delete") after
+PASS [["delete",""]] "&nbsp;[] foo": execCommand("delete", false, "") return value
+PASS [["delete",""]] "&nbsp;[] foo" checks for modifications to non-editable content
+PASS [["delete",""]] "&nbsp;[] foo" compare innerHTML
+PASS [["delete",""]] "&nbsp;[] foo" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "&nbsp;[] foo" queryCommandState("delete") before
+PASS [["delete",""]] "&nbsp;[] foo" queryCommandValue("delete") before
+PASS [["delete",""]] "&nbsp;[] foo" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "&nbsp;[] foo" queryCommandState("delete") after
+PASS [["delete",""]] "&nbsp;[] foo" queryCommandValue("delete") after
+PASS [["delete",""]] "foo &nbsp;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo &nbsp;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo &nbsp;[]bar" compare innerHTML
+PASS [["delete",""]] "foo &nbsp;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo &nbsp;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo &nbsp;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo &nbsp;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo &nbsp;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo &nbsp;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo&nbsp; []bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo&nbsp; []bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo&nbsp; []bar" compare innerHTML
+PASS [["delete",""]] "foo&nbsp; []bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo&nbsp; []bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo&nbsp; []bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo&nbsp; []bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo&nbsp; []bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo&nbsp; []bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar" compare innerHTML
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo&nbsp;&nbsp;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo  []bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo  []bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo  []bar" compare innerHTML
+PASS [["delete",""]] "foo  []bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo  []bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo  []bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo  []bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo  []bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo  []bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo []&nbsp; bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo []&nbsp; bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo []&nbsp; bar" compare innerHTML
+PASS [["delete",""]] "foo []&nbsp; bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo []&nbsp; bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo []&nbsp; bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo []&nbsp; bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo []&nbsp; bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo []&nbsp; bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo &nbsp;[] bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo &nbsp;[] bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo &nbsp;[] bar" compare innerHTML
+PASS [["delete",""]] "foo &nbsp;[] bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo &nbsp;[] bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo &nbsp;[] bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo &nbsp;[] bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo &nbsp;[] bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo &nbsp;[] bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo &nbsp; []bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo &nbsp; []bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo &nbsp; []bar" compare innerHTML
+PASS [["delete",""]] "foo &nbsp; []bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo &nbsp; []bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo &nbsp; []bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo &nbsp; []bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo &nbsp; []bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo &nbsp; []bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar" compare innerHTML
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo []<span>&nbsp;</span> bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo <span>&nbsp;</span>[] bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo <span>&nbsp;</span>[] bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo <span>&nbsp;</span>[] bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo&nbsp; bar" but got "foo &nbsp;bar"
+PASS [["delete",""]] "foo <span>&nbsp;</span>[] bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo <span>&nbsp;</span>[] bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo <span>&nbsp;</span>[] bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo <span>&nbsp;</span>[] bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo <span>&nbsp;</span>[] bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo <span>&nbsp;</span>[] bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo <span>&nbsp;</span> []bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo <span>&nbsp;</span> []bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo <span>&nbsp;</span> []bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo&nbsp;<span> </span>bar" but got "foo <span>&nbsp;</span>bar"
+PASS [["delete",""]] "foo <span>&nbsp;</span> []bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo <span>&nbsp;</span> []bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo <span>&nbsp;</span> []bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo <span>&nbsp;</span> []bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo <span>&nbsp;</span> []bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo <span>&nbsp;</span> []bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar" compare innerHTML
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<b>foo </b>&nbsp;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<b>foo&nbsp;</b> []bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<b>foo&nbsp;</b> []bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<b>foo&nbsp;</b> []bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<b>foo </b>bar" but got "<b>foo&nbsp;</b>bar"
+PASS [["delete",""]] "<b>foo&nbsp;</b> []bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<b>foo&nbsp;</b> []bar" queryCommandState("delete") before
+PASS [["delete",""]] "<b>foo&nbsp;</b> []bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<b>foo&nbsp;</b> []bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<b>foo&nbsp;</b> []bar" queryCommandState("delete") after
+PASS [["delete",""]] "<b>foo&nbsp;</b> []bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<b>foo </b>bar" but got "<b>foo&nbsp;</b>bar"
+PASS [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<b>foo&nbsp;</b>&nbsp;[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<b>foo </b> []bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<b>foo </b> []bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<b>foo </b> []bar" compare innerHTML
+PASS [["delete",""]] "<b>foo </b> []bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<b>foo </b> []bar" queryCommandState("delete") before
+PASS [["delete",""]] "<b>foo </b> []bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<b>foo </b> []bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<b>foo </b> []bar" queryCommandState("delete") after
+PASS [["delete",""]] "<b>foo </b> []bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo </p><p>[] bar</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>" checks for modifications to non-editable content
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>" compare innerHTML
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>" queryCommandState("delete") before
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>" queryCommandValue("delete") before
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>" queryCommandState("delete") after
+PASS [["delete",""]] "<pre>foo &nbsp;[]</pre>" queryCommandValue("delete") after
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>" checks for modifications to non-editable content
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>" compare innerHTML
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>" queryCommandState("delete") before
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>" queryCommandValue("delete") before
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>" queryCommandState("delete") after
+PASS [["delete",""]] "<pre>&nbsp;[] foo</pre>" queryCommandValue("delete") after
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>" checks for modifications to non-editable content
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>" compare innerHTML
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>" queryCommandState("delete") before
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>" queryCommandValue("delete") before
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>" queryCommandState("delete") after
+PASS [["delete",""]] "<pre>foo &nbsp;[]bar</pre>" queryCommandValue("delete") after
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>" checks for modifications to non-editable content
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>" compare innerHTML
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>" queryCommandState("delete") before
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>" queryCommandValue("delete") before
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>" queryCommandState("delete") after
+PASS [["delete",""]] "<pre>foo&nbsp; []bar</pre>" queryCommandValue("delete") after
+PASS [["delete",""]] "<pre>foo  []bar</pre>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<pre>foo  []bar</pre>" checks for modifications to non-editable content
+PASS [["delete",""]] "<pre>foo  []bar</pre>" compare innerHTML
+PASS [["delete",""]] "<pre>foo  []bar</pre>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<pre>foo  []bar</pre>" queryCommandState("delete") before
+PASS [["delete",""]] "<pre>foo  []bar</pre>" queryCommandValue("delete") before
+PASS [["delete",""]] "<pre>foo  []bar</pre>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<pre>foo  []bar</pre>" queryCommandState("delete") after
+PASS [["delete",""]] "<pre>foo  []bar</pre>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>&nbsp;[] foo</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo &nbsp;[]bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo&nbsp; []bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre>foo  []bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>&nbsp;[] foo</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo &nbsp;[]bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo&nbsp; []bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-wrap>foo  []bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>&nbsp;[] foo</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo &nbsp;[]bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo&nbsp; []bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:pre-line>foo  []bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>&nbsp;[] foo</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo &nbsp;[]bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo&nbsp; []bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>" checks for modifications to non-editable content
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>" compare innerHTML
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div style=white-space:nowrap>foo  []bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz" compare innerHTML
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<table><tr><td>[]bar</table>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz" compare innerHTML
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar</table>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz" compare innerHTML
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>[]bar</table><p>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><table><tbody><tr><td>bar</td></tr></tbody></table><p>baz</p>" but got "<p>foo</p><table><tbody><tr><td>bar</td></tr></tbody></table>baz"
+PASS [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar</table><p>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>" compare innerHTML
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<td>[]bar</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>" compare innerHTML
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<tr><td>[]bar</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<table><tbody><tr><td>bar</td></tr></tbody></table>baz" but got "foo<br><table><tbody><tr><td>bar</td></tr></tbody></table>baz"
+PASS [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<br><table><tr><td>[]bar</table>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz" compare innerHTML
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<br></table>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz" compare innerHTML
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<br><table><tr><td>[]bar</table><p>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><table><tbody><tr><td>bar<br></td></tr></tbody></table><p>baz</p>" but got "<p>foo</p><table><tbody><tr><td>bar<br></td></tr></tbody></table>baz"
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br></table><p>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<table><tbody><tr><td>foo</td><td>bar</td></tr></tbody></table>" but got "<table><tbody><tr><td>foo<br></td><td>bar</td></tr></tbody></table>"
+PASS [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><td>[]bar</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<table><tbody><tr><td>foo</td></tr><tr><td>bar</td></tr></tbody></table>" but got "<table><tbody><tr><td>foo<br></td></tr><tr><td>bar</td></tr></tbody></table>"
+PASS [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><tr><td>[]bar</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz" compare innerHTML
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<br><br><table><tr><td>[]bar</table>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz" compare innerHTML
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<br><br></table>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz" compare innerHTML
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<br><br><table><tr><td>[]bar</table><p>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><table><tbody><tr><td>bar<br><br></td></tr></tbody></table><p>baz</p>" but got "<p>foo</p><table><tbody><tr><td>bar<br><br></td></tr></tbody></table>baz"
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>bar<br><br></table><p>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>" compare innerHTML
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><br><td>[]bar</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>" compare innerHTML
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<br><br><tr><td>[]bar</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz" compare innerHTML
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<hr><table><tr><td>[]bar</table>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz" compare innerHTML
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<table><tr><td>bar<hr></table>[]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>" compare innerHTML
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<hr><td>[]bar</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>" compare innerHTML
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tr><td>foo<hr><tr><td>[]bar</table>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div>bar</div><ol><li>baz</li></ol>" but got "foobar<ol><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<p>bar</p><ol><li>baz</li></ol>" but got "foobar<ol><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div>bar</div><ol><li>baz</li></ol>" but got "foobar<ol><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<p>bar</p><ol><li>baz</li></ol>" but got "foobar<ol><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<br><br><div>bar</div><ol><li>baz</li></ol>" but got "foo<br><ol><li>bar</li><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<br><br><p>bar</p><ol><li>baz</li></ol>" but got "foo<br><ol><li>bar</li><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br><ol><li>[]bar<li>baz</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<li>[]bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<li>[]bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<li>[]bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<br>bar</li></ol>" but got "<ol><li>foobar</li></ol>"
+PASS [["delete",""]] "<ol><li>foo<li>[]bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<li>[]bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<li>[]bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<li>[]bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<li>[]bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<li>[]bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<br>bar</li></ol>" but got "<ol><li>foobar</li></ol>"
+PASS [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><li>[]bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<br><br>bar</li></ol>" but got "<ol><li>foo<br>bar<br></li></ol>"
+PASS [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br><li>[]bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<br>bar<br>baz</li></ol>" but got "<ol><li>foobar</li><li>baz</li></ol>"
+PASS [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<li>[]bar<br>baz</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<br>bar<br>baz</li></ol>" but got "<ol><li>foo<br>barbaz</li></ol>"
+PASS [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<br>bar<li>[]baz</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>" compare innerHTML
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li><p>foo</p>{}bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li><p>foo</p>bar</li></ol>" but got "<ol><li><p>foobar</p></li></ol>"
+PASS [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li><p>foo<li>[]bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<p>bar</p></li></ol>" but got "<ol><li>foobar</li></ol>"
+PASS [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><p>[]bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li><p>foo</p><p>bar</p></li></ol>" but got "<ol><li><p>foobar</p></li></ol>"
+PASS [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li><p>foo<li><p>[]bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>bar</li></ol>" but got "<ol><li>foobar</li></ol>"
+PASS [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<ul><li>[]bar</ul></ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<ol><li>bar</li></ol>" but got "foobar"
+PASS [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<ol><ol><li>[]bar</ol></ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div><div>bar</div></div>" but got "foobar"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div><p>bar</p></div>" but got "foobar"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><ol><li>[]bar</ol></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div>bar</div><dl><dd>baz</dd></dl>" but got "foobar<dl><dd>baz</dd></dl>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<p>bar</p><dl><dd>baz</dd></dl>" but got "foobar<dl><dd>baz</dd></dl>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dt>[]bar<dd>baz</dl>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div>bar</div>" but got "foobar"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<p>bar</p>" but got "foobar"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<dl><dd>[]bar</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<dl><dt>foo<br>bar</dt></dl>" but got "<dl><dt>foobar</dt></dl>"
+PASS [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>" queryCommandState("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>" queryCommandValue("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>" queryCommandState("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>[]bar</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<dl><dt>foo<br>bar</dt><dd>baz</dd></dl>" but got "<dl><dt>foobar</dt><dd>baz</dd></dl>"
+PASS [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>" queryCommandState("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>" queryCommandValue("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>" queryCommandState("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dt>[]bar<dd>baz</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<dl><dt>foo</dt><dd>bar<br>baz</dd></dl>" but got "<dl><dt>foo</dt><dd>barbaz</dd></dl>"
+PASS [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>" queryCommandState("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>" queryCommandValue("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>" queryCommandState("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>bar<dd>[]baz</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<br></ol>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<br><br></ol>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<br>bar</li></ol>" but got "<ol><li>foo<br>bar<br></li></ol>"
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li><br></ol>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li><br></ol>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li><br></ol>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>bar</li></ol>" but got "<ol><li>bar<br></li></ol>"
+PASS [["delete",""]] "<ol><li><br></ol>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li><br></ol>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li><br></ol>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li><br></ol>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li><br></ol>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li><br></ol>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>[]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo<li><br></ol>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>bar</li></ol>" but got "<ol><li>foo</li><li>bar<br></li></ol>"
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<br>bar</li></ol>" but got "<ol><li>foo<br>bar<br></li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo<br>bar</li></ol>" but got "<ol><li>foo<br>bar<br></li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>bar</li></ol>" but got "<ol><li>bar<br></li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>bar</li></ol>" but got "<ol><li>bar<br></li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>bar</li></ol>" but got "<ol><li>foo</li><li>bar<br></li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>bar</li></ol>" but got "<ol><li>foo</li><li>bar<br></li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<br></ol>{}<br>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<br><br></ol>{}<br>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>" compare innerHTML
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li><br></ol>{}<br>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo<li><br></ol>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br></ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<br><br></ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><br></ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo<li><br></ol><p>{}<br>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote>[]bar</blockquote>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote>[]bar</blockquote>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote>[]bar</blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<br>bar" but got "foobar"
+PASS [["delete",""]] "foo<blockquote>[]bar</blockquote>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote>[]bar</blockquote>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote>[]bar</blockquote>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote>[]bar</blockquote>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote>[]bar</blockquote>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote>[]bar</blockquote>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<blockquote>bar</blockquote>" but got "foobar"
+PASS [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote><blockquote>[]bar</blockquote></blockquote>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div>bar</div>" but got "foobar"
+PASS [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote><div>[]bar</div></blockquote>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div style=\"color:rgb(0, 0, 255)\">bar</div>" but got "foo<span style=\"color:rgb(0, 0, 255)\">bar</span>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div style=\"color:rgb(0, 0, 255)\">bar</div>" but got "foo<span style=\"color:rgb(0, 0, 255)\">bar</span>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\">[]bar</blockquote>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<blockquote><p>bar</p><blockquote><p>baz</p></blockquote></blockquote>" but got "foobar<blockquote><blockquote><p>baz</p></blockquote></blockquote>"
+PASS [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote><blockquote><p>[]bar<p>baz</blockquote></blockquote>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div><p>bar</p><blockquote><p>baz</p></blockquote></div>" but got "foobar<blockquote><p>baz</p></blockquote>"
+PASS [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote><div><p>[]bar<p>baz</div></blockquote>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div style=\"color:rgb(0, 0, 255)\"><p>bar</p><blockquote><p>baz</p></blockquote></div>" but got "foo<span style=\"color:rgb(0, 0, 255)\">bar</span><blockquote style=\"color:rgb(0, 0, 255)\"><p>baz</p></blockquote>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<div style=\"color:rgb(0, 0, 255)\"><p>bar</p><blockquote><p>baz</p></blockquote></div>" but got "foo<span style=\"color:rgb(0, 0, 255)\">bar</span><blockquote style=\"color:rgb(0, 0, 255)\"><p>baz</p></blockquote>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote style=\"color: blue\"><p>[]bar<p>baz</blockquote>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<p><b>bar</b></p><blockquote><p>baz</p></blockquote>" but got "foo<b>bar</b><blockquote><p>baz</p></blockquote>"
+PASS [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote><p><b>[]bar</b><p>baz</blockquote>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<p><strong>bar</strong></p><blockquote><p>baz</p></blockquote>" but got "foo<strong>bar</strong><blockquote><p>baz</p></blockquote>"
+PASS [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote><p><strong>[]bar</strong><p>baz</blockquote>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<p><span>bar</span></p><blockquote><p>baz</p></blockquote>" but got "foobar<blockquote><p>baz</p></blockquote>"
+PASS [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote><p><span>[]bar</span><p>baz</blockquote>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<blockquote><div>bar</div></blockquote><p>extra</p>" but got "foobar<p>extra</p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<blockquote><p>bar</p></blockquote><p>extra</p>" but got "foobar<p>extra</p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote><ol><li>[]bar</ol></blockquote><p>extra" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<blockquote>bar<div>baz</div>quz</blockquote><p>extra</p>" but got "foo<blockquote>barbaz<br>quz</blockquote><p>extra</p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<blockquote>bar<p>baz</p>quz</blockquote><p>extra</p>" but got "foo<blockquote>barbaz<br>quz</blockquote><p>extra</p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<blockquote>bar<ol><li>[]baz</ol>quz</blockquote><p>extra" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<blockquote><ol><li>bar</li><li>baz</li><li>quz</li></ol></blockquote><p>extra</p>" but got "foo<blockquote><ol><li>barbaz</li><li>quz</li></ol></blockquote><p>extra</p>"
+PASS [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra" queryCommandState("delete") before
+PASS [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra" queryCommandState("delete") after
+PASS [["delete",""]] "foo<blockquote><ol><li>bar</li><ol><li>[]baz</ol><li>quz</ol></blockquote><p>extra" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<span></span>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<span></span>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<span></span>[]bar" compare innerHTML
+PASS [["delete",""]] "foo<span></span>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<span></span>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo<span></span>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<span></span>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<span></span>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo<span></span>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<span><span></span></span>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<span><span></span></span>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<span><span></span></span>[]bar" compare innerHTML
+PASS [["delete",""]] "foo<span><span></span></span>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<span><span></span></span>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo<span><span></span></span>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<span><span></span></span>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<span><span></span></span>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo<span><span></span></span>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<quasit></quasit>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<quasit></quasit>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<quasit></quasit>[]bar" compare innerHTML
+PASS [["delete",""]] "foo<quasit></quasit>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<quasit></quasit>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo<quasit></quasit>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<quasit></quasit>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<quasit></quasit>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo<quasit></quasit>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<br><span></span>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<br><span></span>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<br><span></span>[]bar" compare innerHTML
+PASS [["delete",""]] "foo<br><span></span>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<br><span></span>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo<br><span></span>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<br><span></span>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<br><span></span>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo<br><span></span>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar" compare innerHTML
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<span>foo<span></span></span>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>" compare innerHTML
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<span></span><span>[]bar</span>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p>[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><p><!--abc-->[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><div><!--abc--><p>[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<div><!--abc--><div><p>[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<!--abc--><div><div><p>[]bar</div></div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar" compare innerHTML
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div></div>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar" compare innerHTML
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div></div><!--abc-->[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar" compare innerHTML
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<div><div><p>foo</div><!--abc--></div>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar" compare innerHTML
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<div><div><p>foo</p><!--abc--></div></div>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar" compare innerHTML
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<div><div><p>foo<!--abc--></div></div>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo<!--abc--></p></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p><!--abc--></div></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div><!--abc--></div><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><!--abc--><div><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><!--abc--><div><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><!--abc--><div>[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><div><p>foo</p></div></div><div><div><div><!--abc-->[]bar</div></div></div>" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><span style=\"color:rgb(0, 0, 255)\">foo</span>bar</p>" but got "<p style=\"color:rgb(0, 0, 255)\">foobar</p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><font color=\"#0000ff\">foo</font>bar</p>" but got "<p style=\"color:rgb(0, 0, 255)\">foobar</p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><span style=\"color:rgb(0, 0, 255)\">foo</span>bar</p>" but got "<p style=\"color:rgb(0, 0, 255)\">foobar</p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><font color=\"#0000ff\">foo</font>bar</p>" but got "<p style=\"color:rgb(0, 0, 255)\">foobar</p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p style=\"color:rgb(0, 0, 255)\">foo<font color=\"#a52a2a\">bar</font></p>" but got "<p style=\"color:rgb(0, 0, 255)\">foo<span style=\"color:rgb(165, 42, 42)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p style=\"color:rgb(0, 0, 255)\">foo<font color=\"#a52a2a\">bar</font></p>" but got "<p style=\"color:rgb(0, 0, 255)\">foo<span style=\"color:rgb(165, 42, 42)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" compare innerHTML
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" compare innerHTML
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" compare innerHTML
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" compare innerHTML
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<font color=\"#a52a2a\">bar</font></p>" but got "<p>foo<span style=\"color:rgb(165, 42, 42)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<font color=\"#a52a2a\">bar</font></p>" but got "<p>foo<span style=\"color:rgb(165, 42, 42)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><font color=\"blue\">foo</font><font color=\"brown\">bar</font></p>" but got "<p><font color=\"blue\">foo</font><span style=\"color:rgb(165, 42, 42)\">bar</span></p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><font color=\"blue\">foo</font><font color=\"brown\">bar</font></p>" but got "<p><font color=\"blue\">foo</font><span style=\"color:rgb(165, 42, 42)\">bar</span></p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><font color=blue>foo</font><p><font color=brown>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<font color=\"brown\">bar</font></p>" but got "<p>foo<span style=\"color:rgb(165, 42, 42)\">bar</span></p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<font color=\"brown\">bar</font></p>" but got "<p>foo<span style=\"color:rgb(165, 42, 42)\">bar</span></p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><font color=brown>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=color:blue>foo</font><p><span style=color:brown>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=color:brown>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p style=\"background-color:rgb(0, 255, 255)\">foobar</p>" but got "<p style=\"background-color:rgb(0, 255, 255)\">foo<span style=\"background-color:rgb(210, 180, 140)\">bar</span></p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p style=\"background-color:rgb(0, 255, 255)\">foobar</p>" but got "<p style=\"background-color:rgb(0, 255, 255)\">foo<span style=\"background-color:rgb(210, 180, 140)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p style=\"background-color:rgb(0, 255, 255)\">foobar</p>" but got "<p style=\"background-color:rgb(0, 255, 255)\">foo<span style=\"background-color:rgb(210, 180, 140)\">bar</span></p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p style=\"background-color:rgb(0, 255, 255)\">foobar</p>" but got "<p style=\"background-color:rgb(0, 255, 255)\">foo<span style=\"background-color:rgb(210, 180, 140)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=background-color:aqua>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foobar</p>" but got "<p>foo<span style=\"background-color:rgb(210, 180, 140)\">bar</span></p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foobar</p>" but got "<p>foo<span style=\"background-color:rgb(210, 180, 140)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foobar</p>" but got "<p>foo<span style=\"background-color:rgb(210, 180, 140)\">bar</span></p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foobar</p>" but got "<p>foo<span style=\"background-color:rgb(210, 180, 140)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=background-color:tan>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><span style=background-color:aqua>foo</font><p><span style=background-color:tan>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><span style=background-color:tan>[]bar</font>" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><span style=\"text-decoration:underline\">foo</span>bar</p>" but got "<p style=\"text-decoration:underline\">foobar</p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><u>foo</u>bar</p>" but got "<p style=\"text-decoration:underline\">foobar</p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><span style=\"text-decoration:underline\">foo</span>bar</p>" but got "<p style=\"text-decoration:underline\">foobar</p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><u>foo</u>bar</p>" but got "<p style=\"text-decoration:underline\">foobar</p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><span style=\"text-decoration:underline\">foo</span><span style=\"text-decoration:line-through\">bar</span></p>" but got "<p style=\"text-decoration:underline\">foo<span style=\"text-decoration-line:line-through\">bar</span></p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><u>foo</u><s>bar</s></p>" but got "<p style=\"text-decoration:underline\">foo<span style=\"text-decoration-line:line-through\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><span style=\"text-decoration:underline\">foo</span><span style=\"text-decoration:line-through\">bar</span></p>" but got "<p style=\"text-decoration:underline\">foo<span style=\"text-decoration-line:line-through\">bar</span></p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><u>foo</u><s>bar</s></p>" but got "<p style=\"text-decoration:underline\">foo<span style=\"text-decoration-line:line-through\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=text-decoration:underline>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<span style=\"text-decoration:line-through\">bar</span></p>" but got "<p>foo<span style=\"text-decoration-line:line-through\">bar</span></p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<s>bar</s></p>" but got "<p>foo<span style=\"text-decoration-line:line-through\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<span style=\"text-decoration:line-through\">bar</span></p>" but got "<p>foo<span style=\"text-decoration-line:line-through\">bar</span></p>"
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<s>bar</s></p>" but got "<p>foo<span style=\"text-decoration-line:line-through\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p style=text-decoration:line-through>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p>[]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><u>foo</u><p><s>[]bar</s>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<p><s>[]bar</s>" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><span style=\"color:rgb(0, 0, 255)\">foo</span>bar</p>" but got "<p style=\"color:rgb(0, 0, 255)\">foobar</p>"
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><font color=\"#0000ff\">foo</font>bar</p>" but got "<p style=\"color:rgb(0, 0, 255)\">foobar</p>"
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p style=color:blue>foo</p>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<font color=\"#a52a2a\">bar</font>" but got "foo<span style=\"color:rgb(165, 42, 42)\">bar</span>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<font color=\"#a52a2a\">bar</font>" but got "foo<span style=\"color:rgb(165, 42, 42)\">bar</span>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "foo<p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<div><p><span style=\"color:rgb(0, 128, 0)\">foo</span>bar</p></div>" but got "<div style=\"color:rgb(0, 0, 255)\"><p style=\"color:rgb(0, 128, 0)\">foobar</p></div>"
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<div><p><font color=\"#008000\">foo</font>bar</p></div>" but got "<div style=\"color:rgb(0, 0, 255)\"><p style=\"color:rgb(0, 128, 0)\">foobar</p></div>"
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<div style=\"color:rgb(0, 0, 255)\"><p style=\"color:rgb(0, 128, 0)\">foo<font color=\"#a52a2a\">bar</font></p></div>" but got "<div style=\"color:rgb(0, 0, 255)\"><p style=\"color:rgb(0, 128, 0)\">foo<span style=\"color:rgb(165, 42, 42)\">bar</span></p></div>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<div style=\"color:rgb(0, 0, 255)\"><p style=\"color:rgb(0, 128, 0)\">foo<font color=\"#a52a2a\">bar</font></p></div>" but got "<div style=\"color:rgb(0, 0, 255)\"><p style=\"color:rgb(0, 128, 0)\">foo<span style=\"color:rgb(165, 42, 42)\">bar</span></p></div>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<div style=color:blue><p style=color:green>foo</div><p style=color:brown>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p style=\"color:rgb(0, 0, 255)\">foo<font color=\"#008000\">bar</font></p>" but got "<p style=\"color:rgb(0, 0, 255)\">foo<span style=\"color:rgb(0, 128, 0)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p style=\"color:rgb(0, 0, 255)\">foo<font color=\"#008000\">bar</font></p>" but got "<p style=\"color:rgb(0, 0, 255)\">foo<span style=\"color:rgb(0, 128, 0)\">bar</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p style=color:blue>foo<div style=color:brown><p style=color:green>[]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "foo[bar]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo[bar]baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo[bar]baz" compare innerHTML
+PASS [["delete",""]] "foo[bar]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo[bar]baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo[bar]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo[bar]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo[bar]baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo[bar]baz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar]</span>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar}</span>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo{<span style=color:#aBcDeF>bar</span>}baz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>[foo<span style=color:#aBcDeF>bar]</span>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>{foo<span style=color:#aBcDeF>bar}</span>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span>baz]" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>{bar</span>baz}" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<p>foo<span style=color:#aBcDeF>[bar</span><span style=color:#fEdCbA>baz]</span>quz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>[bar]</b>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo<b>{bar}</b>baz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "foo{<b>bar</b>}baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<span>[bar]</span>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<span>[bar]</span>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<span>[bar]</span>baz" compare innerHTML
+PASS [["delete",""]] "foo<span>[bar]</span>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<span>[bar]</span>baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<span>[bar]</span>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<span>[bar]</span>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<span>[bar]</span>baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<span>[bar]</span>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<span>{bar}</span>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<span>{bar}</span>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<span>{bar}</span>baz" compare innerHTML
+PASS [["delete",""]] "foo<span>{bar}</span>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<span>{bar}</span>baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<span>{bar}</span>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<span>{bar}</span>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<span>{bar}</span>baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<span>{bar}</span>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo{<span>bar</span>}baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo{<span>bar</span>}baz" checks for modifications to non-editable content
+PASS [["delete",""]] "foo{<span>bar</span>}baz" compare innerHTML
+PASS [["delete",""]] "foo{<span>bar</span>}baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo{<span>bar</span>}baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo{<span>bar</span>}baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo{<span>bar</span>}baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo{<span>bar</span>}baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo{<span>bar</span>}baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>" checks for modifications to non-editable content
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>" compare innerHTML
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>" queryCommandState("delete") before
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>" queryCommandValue("delete") before
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>" queryCommandState("delete") after
+PASS [["delete",""]] "<b>foo[bar</b><i>baz]quz</i>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>" compare innerHTML
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo</p><p>[bar]</p><p>baz</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>" compare innerHTML
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo</p><p>{bar}</p><p>baz</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><p><br></p><p>baz</p>" but got "<p>foo</p><p>baz<br></p>"
+PASS [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo</p><p>{bar</p>}<p>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><br><p>baz</p>" but got "<p>foo</p><p><br></p><p>baz</p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><br><p>baz</p>" but got "<p>foo</p><p><br></p><p>baz</p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar}</p><p>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><p>baz</p>" but got "<p>foo</p><p>baz<br></p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><p>baz</p>" but got "<p>foo</p><p>baz<br></p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo</p>{<p>bar</p>}<p>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p>baz]quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<div>baz]quz</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>" compare innerHTML
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo[bar<h1>baz]quz</h1>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div>foo[bar</div><p>baz]quz" queryCommandValue("delete") after
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>" checks for modifications to non-editable content
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>" compare innerHTML
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>" queryCommandState("delete") before
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>" queryCommandValue("delete") before
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>" queryCommandState("delete") after
+PASS [["delete",""]] "<blockquote>foo[bar</blockquote><pre>baz]quz</pre>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p><b>foo[bar</b><p>baz]quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo[bar</div><p>baz]quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<blockquote><p>baz]quz<p>qoz</blockquote" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<font color=\"#0000ff\">quz</font></p>" but got "<p>foo<span style=\"color:rgb(0, 0, 255)\">quz</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" compare innerHTML
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<font color=\"#0000ff\">quz</font></p>" but got "<p>foo<span style=\"color:rgb(0, 0, 255)\">quz</span></p>"
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("defaultparagraphseparator") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("defaultparagraphseparator") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p style=color:blue>baz]quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[bar<p><b>baz]quz</b>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<div><p>foo</p><p><br></p></div>" but got "<p>foo</p><p><br></p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<div><p>foo</p><p><br></p></div>" but got "<p>foo</p><p><br></p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<div><p>foo<p>[bar<p>baz]</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo[<br>]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo[<br>]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "foo[<br>]bar" compare innerHTML
+PASS [["delete",""]] "foo[<br>]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo[<br>]bar" queryCommandState("delete") before
+PASS [["delete",""]] "foo[<br>]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "foo[<br>]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo[<br>]bar" queryCommandState("delete") after
+PASS [["delete",""]] "foo[<br>]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foobar<br>baz</p>" but got "<p>foobar</p><p>baz</p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foobar<br>baz</p>" but got "<p>foobar</p><p>baz</p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo[</p><p>]bar<br>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>}bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>}bar</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>" compare innerHTML
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>" queryCommandState("delete") before
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>" queryCommandState("delete") after
+PASS [["delete",""]] "foo[<p>]bar<br>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<p>]bar</p>baz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar</p>}baz" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<p>{bar</p>}baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<p>{bar</p>}baz" checks for modifications to non-editable content
+FAIL [["delete",""]] "foo<p>{bar</p>}baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<p>baz</p>" but got "foo<p>baz<br></p>"
+PASS [["delete",""]] "foo<p>{bar</p>}baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<p>{bar</p>}baz" queryCommandState("delete") before
+PASS [["delete",""]] "foo<p>{bar</p>}baz" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<p>{bar</p>}baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<p>{bar</p>}baz" queryCommandState("delete") after
+PASS [["delete",""]] "foo<p>{bar</p>}baz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo{<p>bar}</p>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo[</p>]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo[</p>]bar" compare innerHTML
+PASS [["delete",""]] "<p>foo[</p>]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo{</p>}bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo{</p>}bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo{</p>}bar" compare innerHTML
+PASS [["delete",""]] "<p>foo{</p>}bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo{</p>}bar" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo{</p>}bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo{</p>}bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo{</p>}bar" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo{</p>}bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz" compare innerHTML
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar<br>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>" compare innerHTML
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo[</p>]bar<p>baz</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar" compare innerHTML
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<div><p>foo[</p></div>]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo[<div><p>]bar</p>baz</div>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>" compare innerHTML
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>" queryCommandState("delete") before
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>" queryCommandState("delete") after
+PASS [["delete",""]] "foo[<div>]bar<p>baz</p></div>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz" checks for modifications to non-editable content
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz" compare innerHTML
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz" queryCommandState("delete") before
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz" queryCommandState("delete") after
+PASS [["delete",""]] "<div><p>foo</p>bar[</div>]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz" checks for modifications to non-editable content
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz" compare innerHTML
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz" queryCommandState("delete") before
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz" queryCommandState("delete") after
+PASS [["delete",""]] "<div>foo<p>bar[</p></div>]baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<br>{</p>]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<br>{</p>]bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo<br>{</p>]bar" compare innerHTML
+PASS [["delete",""]] "<p>foo<br>{</p>]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<br>{</p>]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<br>{</p>]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<br>{</p>]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<br>{</p>]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<br>{</p>]bar" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<br><br>{</p>]bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<br><br>{</p>]bar" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p>foo<br><br>{</p>]bar" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<br>bar</p>" but got "<p>foo<br>bar<br></p>"
+PASS [["delete",""]] "<p>foo<br><br>{</p>]bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<br><br>{</p>]bar" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<br><br>{</p>]bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<br><br>{</p>]bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<br><br>{</p>]bar" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<br><br>{</p>]bar" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br>{<p>]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<br>bar" but got "foo<br><p>bar</p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<br>bar" but got "foo<br><p>bar</p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "foo<br><br>{<p>]bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br>{</p><p>}bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<br>bar</p>" but got "<p>foo<br>bar<br></p>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo<br>bar</p>" but got "<p>foo<br>bar<br></p>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<br><br>{</p><p>}bar</p>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>" compare innerHTML
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>[bar]<th>baz<tr><td>quz<td>qoz<td>qiz</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" compare innerHTML
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>ba[r<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<table><tbody><tr><th>fo</th><th><br></th><th>az</th></tr><tr><td>quz</td><td>qoz</td><td>qiz</td></tr></tbody></table>" but got "<table><tbody><tr><th>fo</th><th></th><th>az</th></tr><tr><td>quz</td><td>qoz</td><td>qiz</td></tr></tbody></table>"
+PASS [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>fo[o<th>bar<th>b]az<tr><td>quz<td>qoz<td>qiz</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>" checks for modifications to non-editable content
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>" compare innerHTML
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>foo<th>bar<th>ba[z<tr><td>q]uz<td>qoz<td>qiz</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<table><tbody><tr><th><br></th><th><br></th><th><br></th></tr><tr><td>quz</td><td>qoz</td><td>qiz</td></tr></tbody></table>" but got "<table><tbody><tr><th><br></th><th></th><th></th></tr><tr><td>quz</td><td>qoz</td><td>qiz</td></tr></tbody></table>"
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz]<tr><td>quz<td>qoz<td>qiz</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<table><tbody><tr><th><br></th><th><br></th><th><br></th></tr><tr><td><br></td><td><br></td><td><br></td></tr></tbody></table>" but got "<br>"
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tbody><tr><th>[foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz]</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}": execCommand("delete", false, "") return value
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}" checks for modifications to non-editable content
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}" compare innerHTML
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}" queryCommandState("delete") before
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}" queryCommandValue("delete") before
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}" queryCommandState("delete") after
+PASS [["delete",""]] "{<table><tbody><tr><th>foo<th>bar<th>baz<tr><td>quz<td>qoz<td>qiz</table>}" queryCommandValue("delete") after
+PASS [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<table><tbody><tr><td>foo</td><td>ba</td></tr><tr><td><br></td><td><br></td></tr><tr><td>oz</td><td>qiz</td></tr></tbody></table>" but got "<table><tbody><tr><td>foo</td><td>ba</td></tr><tr><td>oz</td><td>qiz</td></tr></tbody></table>"
+PASS [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>" queryCommandState("delete") before
+PASS [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>" queryCommandValue("delete") before
+PASS [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>" queryCommandState("delete") after
+PASS [["delete",""]] "<table><tbody><tr><td>foo<td>ba[r<tr><td>baz<td>quz<tr><td>q]oz<td>qiz</table>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz" compare innerHTML
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>fo[o<table><tr><td>b]ar</table><p>baz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p>foo</p><table><tbody><tr><td>ba</td></tr></tbody></table><p>az</p>" but got "<p>foo</p><table><tbody><tr><td>baaz</td></tr></tbody></table>"
+PASS [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<table><tr><td>ba[r</table><p>b]az" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<table><tr><td>bar</table><p>b]az" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz" compare innerHTML
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<ol><li>ba[r<li>b]az</ol><p>quz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz" compare innerHTML
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>foo<ol><li>bar<li>[baz]</ol><p>quz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz" compare innerHTML
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>fo[o<ol><li>b]ar<li>baz</ol><p>quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>foo<ol><li>bar<li>ba[z</ol><p>q]uz" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz" checks for modifications to non-editable content
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz" compare innerHTML
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz" queryCommandState("delete") before
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz" queryCommandState("delete") after
+PASS [["delete",""]] "<p>fo[o<ol><li>bar<li>b]az</ol><p>quz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<p>fo[o<ol><li>bar<li>baz</ol><p>q]uz" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foar</li></ol>" but got "<ol><li>fo</li><li>ar</li></ol>"
+PASS [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>fo[o</ol><ol><li>b]ar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>" compare innerHTML
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>fo[o</ol><ul><li>b]ar</ul>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>" compare innerHTML
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "foo[<ol><li>]bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo[<li>]bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>" compare innerHTML
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>" queryCommandState("delete") before
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>" queryCommandState("delete") after
+PASS [["delete",""]] "foo[<dl><dt>]bar<dd>baz</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>" compare innerHTML
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>" queryCommandState("delete") before
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>" queryCommandState("delete") after
+PASS [["delete",""]] "foo[<dl><dd>]bar</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>" checks for modifications to non-editable content
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>" compare innerHTML
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>" queryCommandState("delete") before
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>" queryCommandValue("delete") before
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>" queryCommandState("delete") after
+PASS [["delete",""]] "<dl><dt>foo[<dd>]bar</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>" checks for modifications to non-editable content
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>" compare innerHTML
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>" queryCommandState("delete") before
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>" queryCommandValue("delete") before
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>" queryCommandState("delete") after
+PASS [["delete",""]] "<dl><dt>foo[<dt>]bar<dd>baz</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>" checks for modifications to non-editable content
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>" compare innerHTML
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>" queryCommandState("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>" queryCommandValue("delete") before
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>" queryCommandState("delete") after
+PASS [["delete",""]] "<dl><dt>foo<dd>bar[<dd>]baz</dl>" queryCommandValue("delete") after
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]" checks for modifications to non-editable content
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]" compare innerHTML
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]" queryCommandState("delete") before
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]" queryCommandValue("delete") before
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]" queryCommandState("delete") after
+PASS [["delete",""]] "<b>foo [&nbsp;</b>bar]" queryCommandValue("delete") after
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>" checks for modifications to non-editable content
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>" compare innerHTML
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>" queryCommandState("delete") before
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>" queryCommandValue("delete") before
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>" queryCommandState("delete") after
+PASS [["delete",""]] "foo<b> [&nbsp;bar]</b>" queryCommandValue("delete") after
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar" checks for modifications to non-editable content
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar" compare innerHTML
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar" queryCommandState("delete") before
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar" queryCommandValue("delete") before
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar" queryCommandState("delete") after
+PASS [["delete",""]] "<b>[foo&nbsp;] </b>bar" queryCommandValue("delete") after
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>" checks for modifications to non-editable content
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>" compare innerHTML
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>" queryCommandState("delete") before
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>" queryCommandValue("delete") before
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>" queryCommandState("delete") after
+PASS [["delete",""]] "[foo<b>&nbsp;] bar</b>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar" checks for modifications to non-editable content
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar" compare innerHTML
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar" queryCommandState("delete") before
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar" queryCommandValue("delete") before
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar" queryCommandState("delete") after
+PASS [["delete",""]] "<p style=display:inline>fo[o<p style=display:inline>b]ar" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" checks for modifications to non-editable content
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" compare innerHTML
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" checks for modifications to non-editable content
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" compare innerHTML
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<span style=display:block>fo[o</span><span style=display:block>b]ar</span>" queryCommandValue("delete") after
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>" checks for modifications to non-editable content
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>" compare innerHTML
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>" queryCommandState("delete") before
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>" queryCommandValue("delete") before
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>" queryCommandState("delete") after
+PASS [["delete",""]] "<span style=display:inline-block>fo[o</span><span style=display:inline-block>b]ar</span>" queryCommandValue("delete") after
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>" checks for modifications to non-editable content
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>" compare innerHTML
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>" queryCommandState("delete") before
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>" queryCommandValue("delete") before
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>" queryCommandState("delete") after
+PASS [["delete",""]] "<span style=display:inline-table>fo[o</span><span style=display:inline-table>b]ar</span>" queryCommandValue("delete") after
+PASS [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<span style=\"display:none\">fo</span><span style=\"display:none\">ar</span>" but got ""
+PASS [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>" queryCommandState("delete") before
+PASS [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>" queryCommandValue("delete") before
+PASS [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>" queryCommandState("delete") after
+PASS [["delete",""]] "<span style=display:none>fo[o</span><span style=display:none>b]ar</span>" queryCommandValue("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>": execCommand("delete", false, "") return value
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<quasit style=\"display:block\">foar</quasit>" but got "<quasit style=\"display:block\">fo<span style=\"text-align:inherit\">ar</span></quasit>"
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandState("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandValue("delete") before
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandState("delete") after
+PASS [["stylewithcss","true"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandValue("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>": execCommand("delete", false, "") return value
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<quasit style=\"display:block\">foar</quasit>" but got "<quasit style=\"display:block\">fo<span style=\"text-align:inherit\">ar</span></quasit>"
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandIndeterm("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandState("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandValue("delete") before
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandIndeterm("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandState("delete") after
+PASS [["stylewithcss","false"],["delete",""]] "<quasit style=display:block>fo[o</quasit><quasit style=display:block>b]ar</quasit>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>bar</li></ol>" but got "<ol><li>foo</li></ol><ol><li>bar</li></ol>"
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>bar</li></ol>" but got "<ol><li>foo</li></ol><ol><li>bar</li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>bar</li></ol>" but got "<ol><li>foo</li></ol><ol><li>bar</li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li><p>foo</p></li><li>bar</li></ol>" but got "<ol><li><p>foo</p></li></ol><ol><li>bar</li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li><p>foo</p></li><li>bar</li></ol>" but got "<ol><li><p>foo</p></li></ol><ol><li>bar</li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo</ol><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol id=\"a\"><li>foo</li><li>bar</li></ol>" but got "<ol id=\"a\"><li>foo</li></ol><ol><li>bar</li></ol>"
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>bar</li></ol>" but got "<ol><li>foo</li></ol><ol id=\"b\"><li>bar</li></ol>"
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol id=\"a\"><li>foo</li><li>bar</li></ol>" but got "<ol id=\"a\"><li>foo</li></ol><ol id=\"b\"><li>bar</li></ol>"
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol id=a><li>foo</ol>{}<br><ol id=b><li>bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol class=\"a\"><li>foo</li><li>bar</li></ol>" but got "<ol class=\"a\"><li>foo</li></ol><ol class=\"b\"><li>bar</li></ol>"
+PASS [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol class=a><li>foo</ol>{}<br><ol class=b><li>bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><ol><li>foo</li><li>bar</li></ol></ol>" but got "<ol><ol><li>foo</li></ol><ol><li>bar</li></ol></ol>"
+PASS [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><ol><li>foo</ol><li>{}<br></li><ol><li>bar</ol></ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>baz</li></ol>" but got "<ol><li>foo</li></ol><ol><li>baz</li></ol>"
+PASS [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo[</ol>bar]<ol><li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>baz</li></ol>" but got "<ol><li>foo</li></ol><ol><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>baz</li></ol>" but got "<ol><li>foo</li></ol><ol><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li><p>foo</p></li><li>baz</li></ol>" but got "<ol><li><p>foo</p></li></ol><ol><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li><p>foo</p></li><li>baz</li></ol>" but got "<ol><li><p>foo</p></li></ol><ol><li>baz</li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li><p>foo[</ol><p>bar]<ol><li>baz</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo[]</ol><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li></ol>baz" but got "<ol><li>foo</li></ol><ol><li>baz</li></ol>"
+PASS [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>[bar<ol><li>]baz</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li></ol><p>baz</p>" but got "<ol><li>foo</li></ol><ol><li>baz</li></ol>"
+PASS [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li>]baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li></ol><p>baz</p>" but got "<ol><li>foo</li></ol><ol><li><p>baz</p></li></ol>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li></ol><p>baz</p>" but got "<ol><li>foo</li></ol><ol><li><p>baz</p></li></ol>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>[bar<ol><li><p>]baz</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol><ol><li>b[]ar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><ol><li>foo</li></ol><li>quz</li></ol>" but got "<ol><ol><li>foo</li></ol></ol><ol><li>quz</li></ol>"
+PASS [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><ol><li>foo[</ol><li>bar</ol>baz]<ol><li>quz</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ul><li>foo</li><li>bar</li></ul>" but got "<ul><li>foo</li></ul><ul><li>bar</li></ul>"
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>" queryCommandState("delete") before
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>" queryCommandState("delete") after
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ul><li>bar</ul>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ul><li>foo</li><li>bar</li></ul>" but got "<ul><li>foo</li></ul><ul><li>bar</li></ul>"
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" checks for modifications to non-editable content
+FAIL [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ul><li>foo</li><li>bar</li></ul>" but got "<ul><li>foo</li></ul><ul><li>bar</li></ul>"
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<ol><li>foo</li><li>baz</li><li>quz</li></ol>" but got "<ol><li>foo</li></ol><ol><li>baz</li></ol><ol><li>quz</li></ol>"
+PASS [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo[<li>bar]</ol><ol><li>baz</ol><ol><li>quz</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>" compare innerHTML
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>" queryCommandState("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>" queryCommandState("delete") after
+PASS [["delete",""]] "<ol><li>foo</ol>{}<br><ul><li>bar</ul>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ol><li>foo</ol><p>{}<br></p><ul><li>bar</ul>" queryCommandValue("delete") after
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>" checks for modifications to non-editable content
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>" compare innerHTML
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["delete",""]] "<ul><li>foo</ul>{}<br><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>": execCommand("defaultparagraphseparator", false, "div") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" compare innerHTML
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","div"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>": execCommand("defaultparagraphseparator", false, "p") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>": execCommand("delete", false, "") return value
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" checks for modifications to non-editable content
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" compare innerHTML
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandState("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("defaultparagraphseparator") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") before
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandIndeterm("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandState("delete") after
+PASS [["defaultparagraphseparator","p"],["delete",""]] "<ul><li>foo</ul><p>{}<br></p><ol><li>bar</ol>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p><b>[foo]</b>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p><b>[foo]</b>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p><b>[foo]</b>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><b><br></b></p>" but got "<p><br></p>"
+PASS [["delete",""]] "<p><b>[foo]</b>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p><b>[foo]</b>" queryCommandState("delete") before
+PASS [["delete",""]] "<p><b>[foo]</b>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p><b>[foo]</b>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p><b>[foo]</b>" queryCommandState("delete") after
+PASS [["delete",""]] "<p><b>[foo]</b>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p><quasit>[foo]</quasit>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p><quasit>[foo]</quasit>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p><quasit>[foo]</quasit>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><quasit><br></quasit></p>" but got "<p><br></p>"
+PASS [["delete",""]] "<p><quasit>[foo]</quasit>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p><quasit>[foo]</quasit>" queryCommandState("delete") before
+PASS [["delete",""]] "<p><quasit>[foo]</quasit>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p><quasit>[foo]</quasit>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p><quasit>[foo]</quasit>" queryCommandState("delete") after
+PASS [["delete",""]] "<p><quasit>[foo]</quasit>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p><b><i>[foo]</i></b>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p><b><i>[foo]</i></b>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p><b><i>[foo]</i></b>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><b><i><br></i></b></p>" but got "<p><br></p>"
+PASS [["delete",""]] "<p><b><i>[foo]</i></b>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p><b><i>[foo]</i></b>" queryCommandState("delete") before
+PASS [["delete",""]] "<p><b><i>[foo]</i></b>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p><b><i>[foo]</i></b>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p><b><i>[foo]</i></b>" queryCommandState("delete") after
+PASS [["delete",""]] "<p><b><i>[foo]</i></b>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p><b>{foo}</b>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p><b>{foo}</b>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p><b>{foo}</b>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><b><br></b></p>" but got "<p><br></p>"
+PASS [["delete",""]] "<p><b>{foo}</b>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p><b>{foo}</b>" queryCommandState("delete") before
+PASS [["delete",""]] "<p><b>{foo}</b>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p><b>{foo}</b>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p><b>{foo}</b>" queryCommandState("delete") after
+PASS [["delete",""]] "<p><b>{foo}</b>" queryCommandValue("delete") after
+PASS [["delete",""]] "<p>{<b>foo</b>}": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p>{<b>foo</b>}" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p>{<b>foo</b>}" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><b><br></b></p>" but got "<p><br></p>"
+PASS [["delete",""]] "<p>{<b>foo</b>}" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p>{<b>foo</b>}" queryCommandState("delete") before
+PASS [["delete",""]] "<p>{<b>foo</b>}" queryCommandValue("delete") before
+PASS [["delete",""]] "<p>{<b>foo</b>}" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p>{<b>foo</b>}" queryCommandState("delete") after
+PASS [["delete",""]] "<p>{<b>foo</b>}" queryCommandValue("delete") after
+PASS [["delete",""]] "<p><b>f[]</b>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<p><b>f[]</b>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<p><b>f[]</b>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<p><b><br></b></p>" but got "<p><br></p>"
+PASS [["delete",""]] "<p><b>f[]</b>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<p><b>f[]</b>" queryCommandState("delete") before
+PASS [["delete",""]] "<p><b>f[]</b>" queryCommandValue("delete") before
+PASS [["delete",""]] "<p><b>f[]</b>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<p><b>f[]</b>" queryCommandState("delete") after
+PASS [["delete",""]] "<p><b>f[]</b>" queryCommandValue("delete") after
+PASS [["delete",""]] "<b>[foo]</b>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<b>[foo]</b>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<b>[foo]</b>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<b><br></b>" but got "<br>"
+PASS [["delete",""]] "<b>[foo]</b>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<b>[foo]</b>" queryCommandState("delete") before
+PASS [["delete",""]] "<b>[foo]</b>" queryCommandValue("delete") before
+PASS [["delete",""]] "<b>[foo]</b>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<b>[foo]</b>" queryCommandState("delete") after
+PASS [["delete",""]] "<b>[foo]</b>" queryCommandValue("delete") after
+PASS [["delete",""]] "<div><b>[foo]</b></div>": execCommand("delete", false, "") return value
+PASS [["delete",""]] "<div><b>[foo]</b></div>" checks for modifications to non-editable content
+FAIL [["delete",""]] "<div><b>[foo]</b></div>" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "<div><b><br></b></div>" but got "<br>"
+PASS [["delete",""]] "<div><b>[foo]</b></div>" queryCommandIndeterm("delete") before
+PASS [["delete",""]] "<div><b>[foo]</b></div>" queryCommandState("delete") before
+PASS [["delete",""]] "<div><b>[foo]</b></div>" queryCommandValue("delete") before
+PASS [["delete",""]] "<div><b>[foo]</b></div>" queryCommandIndeterm("delete") after
+PASS [["delete",""]] "<div><b>[foo]</b></div>" queryCommandState("delete") after
+PASS [["delete",""]] "<div><b>[foo]</b></div>" queryCommandValue("delete") after
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/abort/destroyed-context.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/abort/destroyed-context.html
new file mode 100644
index 0000000..161d39b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/abort/destroyed-context.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+// This is a regression test for crbug.com/860063.
+window.controller = new AbortController();
+async_test(t => {
+  onmessage = t.step_func(event => {
+    assert_equals(event.data, 'started');
+    const iframe = document.querySelector('iframe');
+    document.body.removeChild(iframe);
+    controller.abort();
+    t.done();
+  });
+}, 'aborting a fetch in a destroyed context should not crash');
+</script>
+<iframe srcdoc="
+                <!DOCTYPE html>
+                <meta charset=utf-8>
+                <script>
+                fetch('../resources/infinite-slow-response.py', { signal: parent.controller.signal }).then(() => {
+                  parent.postMessage('started', '*');
+                });
+                </script>
+                ">
+</iframe>
diff --git a/third_party/WebKit/LayoutTests/fast/block/rtl-abs-pos-container-with-scrollbar-expected.html b/third_party/WebKit/LayoutTests/fast/block/rtl-abs-pos-container-with-scrollbar-expected.html
new file mode 100644
index 0000000..bf38238
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/rtl-abs-pos-container-with-scrollbar-expected.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<style>
+  #outer {
+    direction: rtl;
+    width: 200px;
+    height: 200px;
+    overflow-y: scroll;
+  }
+  #inner {
+    width: 100%;
+    height: 300px;
+    background: green;
+  }
+  #absolute {
+    width: 100px;
+    height: 100px;
+    background: blue;
+    position: absolute;
+  }
+</style>
+
+<div id="outer">
+  <div id="inner">
+    <div id="absolute"></div>
+  </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/block/rtl-abs-pos-container-with-scrollbar.html b/third_party/WebKit/LayoutTests/fast/block/rtl-abs-pos-container-with-scrollbar.html
new file mode 100644
index 0000000..8d867c0c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/rtl-abs-pos-container-with-scrollbar.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<style>
+  #outer {
+    direction: rtl;
+    position: relative;
+    width: 200px;
+    height: 200px;
+    overflow-y: scroll;
+  }
+  #inner {
+    width: 100%;
+    height: 300px;
+    background: green;
+  }
+  #absolute {
+    width: 100px;
+    height: 100px;
+    background: blue;
+    position: absolute;
+  }
+</style>
+
+<div id="outer">
+  <div id="inner">
+    <div id="absolute"></div>
+  </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/invalid/table-residual-style-crash-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/invalid/table-residual-style-crash-expected.txt
deleted file mode 100644
index 596d6eb..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/invalid/table-residual-style-crash-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutNGBlockFlow {HTML} at (0,0) size 800x600
-    LayoutNGBlockFlow {BODY} at (8,16) size 784x576
-      LayoutNGBlockFlow (anonymous) at (0,0) size 784x0
-        LayoutInline {FONT} at (0,0) size 0x0
-          LayoutText {#text} at (0,0) size 0x0
-      LayoutNGBlockFlow (anonymous) at (0,0) size 784x0
-        LayoutNGBlockFlow {FORM} at (0,0) size 784x0
-      LayoutNGBlockFlow (anonymous) at (0,0) size 784x0
-        LayoutInline {FONT} at (0,0) size 0x0
-      LayoutTable {TABLE} at (0,0) size 0x0
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
index 3016884..38bc9f2 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-protocol/resources/inspector-protocol-test.js
@@ -520,7 +520,7 @@
 DevToolsAPI._sendCommandOrDie = function(method, params) {
   return DevToolsAPI._sendCommand(method, params).then(message => {
     if (message.error)
-      DevToolsAPI._die('Error communicating with harness', new Error(message.error));
+      DevToolsAPI._die('Error communicating with harness', new Error(JSON.stringify(message.error)));
     return message.result;
   });
 };
diff --git a/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt b/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt
index a32a51fb..6bce4802 100644
--- a/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/css-properties-as-js-properties-expected.txt
@@ -33,6 +33,8 @@
 baselineShift
 blockSize
 border
+borderBlock
+borderBlockColor
 borderBlockEnd
 borderBlockEndColor
 borderBlockEndStyle
@@ -41,6 +43,8 @@
 borderBlockStartColor
 borderBlockStartStyle
 borderBlockStartWidth
+borderBlockStyle
+borderBlockWidth
 borderBottom
 borderBottomColor
 borderBottomLeftRadius
@@ -55,6 +59,8 @@
 borderImageSlice
 borderImageSource
 borderImageWidth
+borderInline
+borderInlineColor
 borderInlineEnd
 borderInlineEndColor
 borderInlineEndStyle
@@ -63,6 +69,8 @@
 borderInlineStartColor
 borderInlineStartStyle
 borderInlineStartWidth
+borderInlineStyle
+borderInlineWidth
 borderLeft
 borderLeftColor
 borderLeftStyle
@@ -195,9 +203,11 @@
 listStylePosition
 listStyleType
 margin
+marginBlock
 marginBlockEnd
 marginBlockStart
 marginBottom
+marginInline
 marginInlineEnd
 marginInlineStart
 marginLeft
@@ -247,9 +257,11 @@
 overscrollBehaviorX
 overscrollBehaviorY
 padding
+paddingBlock
 paddingBlockEnd
 paddingBlockStart
 paddingBottom
+paddingInline
 paddingInlineEnd
 paddingInlineStart
 paddingLeft
diff --git a/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt
index 21f978e1..5086356e 100644
--- a/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/css-property-listing-expected.txt
@@ -450,6 +450,12 @@
         border-top-color
         border-top-style
         border-top-width
+    border-block
+        border-block-end
+        border-block-start
+    border-block-color
+        border-block-end-color
+        border-block-start-color
     border-block-end
         border-block-end-color
         border-block-end-style
@@ -458,6 +464,12 @@
         border-block-start-color
         border-block-start-style
         border-block-start-width
+    border-block-style
+        border-block-end-style
+        border-block-start-style
+    border-block-width
+        border-block-end-width
+        border-block-start-width
     border-bottom
         border-bottom-color
         border-bottom-style
@@ -473,6 +485,12 @@
         border-image-slice
         border-image-source
         border-image-width
+    border-inline
+        border-inline-end
+        border-inline-start
+    border-inline-color
+        border-inline-end-color
+        border-inline-start-color
     border-inline-end
         border-inline-end-color
         border-inline-end-style
@@ -481,6 +499,12 @@
         border-inline-start-color
         border-inline-start-style
         border-inline-start-width
+    border-inline-style
+        border-inline-end-style
+        border-inline-start-style
+    border-inline-width
+        border-inline-end-width
+        border-inline-start-width
     border-left
         border-left-color
         border-left-style
@@ -582,6 +606,12 @@
         margin-left
         margin-right
         margin-top
+    margin-block
+        margin-block-end
+        margin-block-start
+    margin-inline
+        margin-inline-end
+        margin-inline-start
     marker
         marker-end
         marker-mid
@@ -607,6 +637,12 @@
         padding-left
         padding-right
         padding-top
+    padding-block
+        padding-block-end
+        padding-block-start
+    padding-inline
+        padding-inline-end
+        padding-inline-start
     page-break-after
         break-after
     page-break-before
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 3bbc183..3e0a2f4 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -739,6 +739,7 @@
     ":web_client_hints_types_mojo_bindings",
     ":web_feature_mojo_bindings",
     "//components/payments/mojom",
+    "//components/services/font/public/interfaces",
     "//device/bluetooth/public/mojom",
     "//mojo/public/mojom/base",
     "//services/device/public/mojom",
diff --git a/third_party/blink/public/mojom/use_counter/css_property_id.mojom b/third_party/blink/public/mojom/use_counter/css_property_id.mojom
index 13a6afe..0dec4c15 100644
--- a/third_party/blink/public/mojom/use_counter/css_property_id.mojom
+++ b/third_party/blink/public/mojom/use_counter/css_property_id.mojom
@@ -4,7 +4,7 @@
 
 module blink.mojom;
 
-const int32 kMaximumCSSSampleId = 617;
+const int32 kMaximumCSSSampleId = 629;
 
 // This CSSSampleId represents page load for CSS histograms. It is recorded once
 // per page visit for each CSS histogram being logged on the blink side and the
diff --git a/third_party/blink/public/web/web_embedded_worker.h b/third_party/blink/public/web/web_embedded_worker.h
index 0406137..f8f58fd 100644
--- a/third_party/blink/public/web/web_embedded_worker.h
+++ b/third_party/blink/public/web/web_embedded_worker.h
@@ -57,6 +57,7 @@
       std::unique_ptr<WebServiceWorkerContextClient>,
       std::unique_ptr<WebServiceWorkerInstalledScriptsManager>,
       mojo::ScopedMessagePipeHandle content_settings_handle,
+      mojo::ScopedMessagePipeHandle cache_storage,
       mojo::ScopedMessagePipeHandle interface_provider);
 
   virtual ~WebEmbeddedWorker() = default;
diff --git a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
index b341b43..55f9850 100644
--- a/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/generated_code_helper.cc
@@ -7,6 +7,7 @@
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/bindings/core/v8/scheduled_action.h b/third_party/blink/renderer/bindings/core/v8/scheduled_action.h
index b532cb7..4a62e0f 100644
--- a/third_party/blink/renderer/bindings/core/v8/scheduled_action.h
+++ b/third_party/blink/renderer/bindings/core/v8/scheduled_action.h
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "v8/include/v8.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc b/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
index 974c8f4..d5de7130 100644
--- a/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
+++ b/third_party/blink/renderer/bindings/core/v8/script_custom_element_definition.cc
@@ -17,6 +17,7 @@
 #include "third_party/blink/renderer/core/html/html_element.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "v8/include/v8.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc b/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc
index 109473b..41ef61f5 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_context_snapshot.cc
@@ -17,6 +17,7 @@
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
 #include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h b/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h
index 3ffb391..66ad07a 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h
+++ b/third_party/blink/renderer/bindings/core/v8/v8_v0_custom_element_lifecycle_callbacks.h
@@ -41,6 +41,7 @@
 
 namespace blink {
 
+class V0CustomElementBinding;
 class V0CustomElementLifecycleCallbacks;
 class Element;
 class V8PerContextData;
diff --git a/third_party/blink/renderer/bindings/core/v8/window_proxy.h b/third_party/blink/renderer/bindings/core/v8/window_proxy.h
index 04403ed..112c808 100644
--- a/third_party/blink/renderer/bindings/core/v8/window_proxy.h
+++ b/third_party/blink/renderer/bindings/core/v8/window_proxy.h
@@ -43,6 +43,7 @@
 
 class DOMWindow;
 class Frame;
+struct WrapperTypeInfo;
 
 // WindowProxy implements the split window model of a window for a frame. In the
 // HTML standard, the split window model is composed of the Window interface
diff --git a/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py b/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
index 537112e..5ce2b04 100755
--- a/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
+++ b/third_party/blink/renderer/bindings/scripts/generate_origin_trial_features.py
@@ -162,6 +162,7 @@
         'core/origin_trials/origin_trials.h',
         'platform/bindings/origin_trial_features.h',
         'platform/bindings/script_state.h',
+        'platform/bindings/v8_per_context_data.h',
         # TODO(iclelland): Remove the need to explicitly include this; it is
         # here because the ContextFeatureSettings code needs it.
         'bindings/core/v8/v8_window.h',
diff --git a/third_party/blink/renderer/bindings/scripts/v8_attributes.py b/third_party/blink/renderer/bindings/scripts/v8_attributes.py
index d8d9ab6..082c09b1 100644
--- a/third_party/blink/renderer/bindings/scripts/v8_attributes.py
+++ b/third_party/blink/renderer/bindings/scripts/v8_attributes.py
@@ -120,6 +120,10 @@
     if is_cached_accessor:
         includes.add('platform/bindings/v8_private_property.h')
 
+    # [LogActivity]
+    if 'LogActivity' in extended_attributes:
+        includes.add('platform/bindings/v8_per_context_data.h')
+
     context = {
         'activity_logging_world_list_for_getter': v8_utilities.activity_logging_world_list(attribute, 'Getter'),  # [ActivityLogging]
         'activity_logging_world_list_for_setter': v8_utilities.activity_logging_world_list(attribute, 'Setter'),  # [ActivityLogging]
diff --git a/third_party/blink/renderer/bindings/scripts/v8_callback_interface.py b/third_party/blink/renderer/bindings/scripts/v8_callback_interface.py
index 0f5b8341..d3d8728 100644
--- a/third_party/blink/renderer/bindings/scripts/v8_callback_interface.py
+++ b/third_party/blink/renderer/bindings/scripts/v8_callback_interface.py
@@ -50,6 +50,7 @@
 ])
 LEGACY_CALLBACK_INTERFACE_H_INCLUDES = frozenset([
     'platform/bindings/dom_wrapper_world.h',
+    'platform/bindings/wrapper_type_info.h',
 ])
 LEGACY_CALLBACK_INTERFACE_CPP_INCLUDES = frozenset([
     'bindings/core/v8/v8_dom_configuration.h',
diff --git a/third_party/blink/renderer/bindings/scripts/v8_interface.py b/third_party/blink/renderer/bindings/scripts/v8_interface.py
index 4fa121b7..6356594 100644
--- a/third_party/blink/renderer/bindings/scripts/v8_interface.py
+++ b/third_party/blink/renderer/bindings/scripts/v8_interface.py
@@ -342,6 +342,7 @@
                             ' specified on partial interface definitions: '
                             '%s' % interface.name)
         if named_constructor:
+            includes.add('platform/bindings/v8_per_context_data.h')
             includes.add('platform/bindings/v8_private_property.h')
 
         includes.add('platform/bindings/v8_object_constructor.h')
@@ -476,6 +477,8 @@
             sorted(origin_trial_features(interface, context['constants'], context['attributes'], context['methods']) +
                    context_enabled_features(context['attributes'])),
     })
+    if context['optional_features']:
+        includes.add('platform/bindings/v8_per_context_data.h')
 
     # Cross-origin interceptors
     has_cross_origin_named_getter = False
diff --git a/third_party/blink/renderer/bindings/scripts/v8_methods.py b/third_party/blink/renderer/bindings/scripts/v8_methods.py
index 37f20d1..4e5e737 100644
--- a/third_party/blink/renderer/bindings/scripts/v8_methods.py
+++ b/third_party/blink/renderer/bindings/scripts/v8_methods.py
@@ -178,6 +178,10 @@
     else:
         side_effect_type = 'V8DOMConfiguration::kHasSideEffect'
 
+    # [LogActivity]
+    if 'LogActivity' in extended_attributes:
+        includes.add('platform/bindings/v8_per_context_data.h')
+
     argument_contexts = [
         argument_context(interface, method, argument, index, is_visible=is_visible)
         for index, argument in enumerate(arguments)]
diff --git a/third_party/blink/renderer/bindings/tests/results/core/origin_trial_features_for_core.cc b/third_party/blink/renderer/bindings/tests/results/core/origin_trial_features_for_core.cc
index 4311e26..013a13f 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/origin_trial_features_for_core.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/origin_trial_features_for_core.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
 #include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_constants.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_constants.cc
index c1f0b7d..f686d4b82 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_constants.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_constants.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/get_ptr.h"
 
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_constructor.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_constructor.cc
index 1aa0bd7..58bb7bc 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_constructor.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_constructor.cc
@@ -24,6 +24,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 #include "third_party/blink/renderer/platform/wtf/get_ptr.h"
 
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_event_target.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_event_target.cc
index de3717b..46ff0a0 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_event_target.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_event_target.cc
@@ -18,6 +18,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 #include "third_party/blink/renderer/platform/wtf/get_ptr.h"
 
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_named_constructor.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_named_constructor.cc
index b96ca84..ab2112a7 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_named_constructor.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_named_constructor.cc
@@ -21,6 +21,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 #include "third_party/blink/renderer/platform/wtf/get_ptr.h"
 
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_named_constructor_2.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_named_constructor_2.cc
index 01dd0d9..998dd91 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_named_constructor_2.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_named_constructor_2.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 #include "third_party/blink/renderer/platform/wtf/get_ptr.h"
 
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_legacy_callback_interface.h b/third_party/blink/renderer/bindings/tests/results/core/v8_test_legacy_callback_interface.h
index 6502a6c..f99cf7db0 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_legacy_callback_interface.h
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_legacy_callback_interface.h
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/bindings/callback_interface_base.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
+#include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc
index 72d299ee..d9e9701e 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_object.cc
@@ -74,6 +74,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/bindings/v8_private_property.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/get_ptr.h"
diff --git a/third_party/blink/renderer/bindings/tests/results/modules/origin_trial_features_for_modules.cc b/third_party/blink/renderer/bindings/tests/results/modules/origin_trial_features_for_modules.cc
index fc782ddd..546c2905 100644
--- a/third_party/blink/renderer/bindings/tests/results/modules/origin_trial_features_for_modules.cc
+++ b/third_party/blink/renderer/bindings/tests/results/modules/origin_trial_features_for_modules.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
 #include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/bindings/tests/results/modules/v8_test_interface_partial.cc b/third_party/blink/renderer/bindings/tests/results/modules/v8_test_interface_partial.cc
index 7f1a3f4..4e96d6d 100644
--- a/third_party/blink/renderer/bindings/tests/results/modules/v8_test_interface_partial.cc
+++ b/third_party/blink/renderer/bindings/tests/results/modules/v8_test_interface_partial.cc
@@ -28,6 +28,7 @@
 #include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/get_ptr.h"
 
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index 1dee664..7d68fa3 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -756,14 +756,22 @@
     "properties/shorthands/background_custom.cc",
     "properties/shorthands/background_position_custom.cc",
     "properties/shorthands/background_repeat_custom.cc",
+    "properties/shorthands/border_block_color_custom.cc",
+    "properties/shorthands/border_block_custom.cc",
     "properties/shorthands/border_block_end_custom.cc",
     "properties/shorthands/border_block_start_custom.cc",
+    "properties/shorthands/border_block_style_custom.cc",
+    "properties/shorthands/border_block_width_custom.cc",
     "properties/shorthands/border_bottom_custom.cc",
     "properties/shorthands/border_color_custom.cc",
     "properties/shorthands/border_custom.cc",
     "properties/shorthands/border_image_custom.cc",
+    "properties/shorthands/border_inline_color_custom.cc",
+    "properties/shorthands/border_inline_custom.cc",
     "properties/shorthands/border_inline_end_custom.cc",
     "properties/shorthands/border_inline_start_custom.cc",
+    "properties/shorthands/border_inline_style_custom.cc",
+    "properties/shorthands/border_inline_width_custom.cc",
     "properties/shorthands/border_left_custom.cc",
     "properties/shorthands/border_radius_custom.cc",
     "properties/shorthands/border_right_custom.cc",
@@ -787,13 +795,17 @@
     "properties/shorthands/grid_row_gap_custom.cc",
     "properties/shorthands/grid_template_custom.cc",
     "properties/shorthands/list_style_custom.cc",
+    "properties/shorthands/margin_block_custom.cc",
     "properties/shorthands/margin_custom.cc",
+    "properties/shorthands/margin_inline_custom.cc",
     "properties/shorthands/marker_custom.cc",
     "properties/shorthands/offset_custom.cc",
     "properties/shorthands/outline_custom.cc",
     "properties/shorthands/overflow_custom.cc",
     "properties/shorthands/overscroll_behavior_custom.cc",
+    "properties/shorthands/padding_block_custom.cc",
     "properties/shorthands/padding_custom.cc",
+    "properties/shorthands/padding_inline_custom.cc",
     "properties/shorthands/page_break_after_custom.cc",
     "properties/shorthands/page_break_before_custom.cc",
     "properties/shorthands/page_break_inside_custom.cc",
diff --git a/third_party/blink/renderer/core/css/CSSProperties.json5 b/third_party/blink/renderer/core/css/CSSProperties.json5
index ed8ce36..2207614 100644
--- a/third_party/blink/renderer/core/css/CSSProperties.json5
+++ b/third_party/blink/renderer/core/css/CSSProperties.json5
@@ -4520,6 +4520,18 @@
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
     },
     {
+      name: "border-block",
+      longhands: ["border-block-start", "border-block-end"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
+      name: "border-block-color",
+      longhands: ["border-block-start-color", "border-block-end-color"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
       name: "border-block-end",
       longhands: [
         "border-block-end-width", "border-block-end-style",
@@ -4544,6 +4556,18 @@
       },
     },
     {
+      name: "border-block-style",
+      longhands: ["border-block-start-style", "border-block-end-style"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
+      name: "border-block-width",
+      longhands: ["border-block-start-width", "border-block-end-width"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
       name: "border-bottom",
       longhands: [
         "border-bottom-width", "border-bottom-style", "border-bottom-color"
@@ -4567,6 +4591,18 @@
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
     },
     {
+      name: "border-inline",
+      longhands: ["border-inline-start", "border-inline-end"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
+      name: "border-inline-color",
+      longhands: ["border-inline-start-color", "border-inline-end-color"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
       name: "border-inline-end",
       longhands: [
         "border-inline-end-width", "border-inline-end-style",
@@ -4591,6 +4627,18 @@
       },
     },
     {
+      name: "border-inline-style",
+      longhands: ["border-inline-start-style", "border-inline-end-style"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
+      name: "border-inline-width",
+      longhands: ["border-inline-start-width", "border-inline-end-width"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
       name: "border-left",
       longhands: [
         "border-left-width", "border-left-style", "border-left-color"
@@ -4751,6 +4799,18 @@
       layout_dependent: true,
     },
     {
+      name: "margin-block",
+      longhands: ["margin-block-start", "margin-block-end"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
+      name: "margin-inline",
+      longhands: ["margin-inline-start", "margin-inline-end"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
       name: "marker",
       longhands: ["marker-start", "marker-mid", "marker-end"],
       property_methods: ["ParseShorthand"],
@@ -4788,6 +4848,18 @@
       layout_dependent: true,
     },
     {
+      name: "padding-block",
+      longhands: ["padding-block-start", "padding-block-end"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
+      name: "padding-inline",
+      longhands: ["padding-inline-start", "padding-inline-end"],
+      property_methods: ["ParseShorthand"],
+      runtime_flag: "CSSLogical",
+    },
+    {
       name: "page-break-after",
       longhands: ["break-after"],
       property_methods: ["ParseShorthand", "CSSValueFromComputedStyleInternal"],
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
index 1ec7f49e..a33826a7 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
@@ -955,6 +955,46 @@
   return true;
 }
 
+bool ConsumeBorderShorthand(CSSParserTokenRange& range,
+                            const CSSParserContext& context,
+                            const CSSValue*& result_width,
+                            const CSSValue*& result_style,
+                            const CSSValue*& result_color) {
+  while (!result_width || !result_style || !result_color) {
+    if (!result_width) {
+      result_width = CSSPropertyParserHelpers::ConsumeLineWidth(
+          range, context.Mode(),
+          CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
+      if (result_width)
+        continue;
+    }
+    if (!result_style) {
+      result_style = CSSPropertyParserHelpers::ParseLonghand(
+          CSSPropertyBorderLeftStyle, CSSPropertyBorder, context, range);
+      if (result_style)
+        continue;
+    }
+    if (!result_color) {
+      result_color =
+          CSSPropertyParserHelpers::ConsumeColor(range, context.Mode());
+      if (result_color)
+        continue;
+    }
+    break;
+  }
+
+  if (!result_width && !result_style && !result_color)
+    return false;
+
+  if (!result_width)
+    result_width = CSSInitialValue::Create();
+  if (!result_style)
+    result_style = CSSInitialValue::Create();
+  if (!result_color)
+    result_color = CSSInitialValue::Create();
+  return true;
+}
+
 // This should go away once we drop support for -webkit-gradient
 static CSSPrimitiveValue* ConsumeDeprecatedGradientPoint(
     CSSParserTokenRange& args,
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
index f1870b17..bd4cd25c 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
@@ -101,6 +101,11 @@
                                    UnitlessQuirk,
                                    CSSValue*& result_x,
                                    CSSValue*& result_y);
+bool ConsumeBorderShorthand(CSSParserTokenRange&,
+                            const CSSParserContext&,
+                            const CSSValue*& result_width,
+                            const CSSValue*& result_style,
+                            const CSSValue*& result_color);
 
 enum class ConsumeGeneratedImagePolicy { kAllow, kForbid };
 
diff --git a/third_party/blink/renderer/core/css/parser/css_proto_converter.cc b/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
index 03175244..4fce488 100644
--- a/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
+++ b/third_party/blink/renderer/core/css/parser/css_proto_converter.cc
@@ -1458,6 +1458,18 @@
     "border-block-end",
     "border-inline-start",
     "border-inline-end",
+    "margin-block",
+    "margin-inline",
+    "padding-block",
+    "padding-inline",
+    "border-block-width",
+    "border-block-style",
+    "border-block-color",
+    "border-inline-width",
+    "border-inline-style",
+    "border-inline-color",
+    "border-block",
+    "border-inline",
     "INVALID_PROPERTY",
 };
 
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_block_color_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_block_color_custom.cc
new file mode 100644
index 0000000..a067b26f
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_block_color_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/border_block_color.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool BorderBlockColor::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      borderBlockColorShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_block_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_block_custom.cc
new file mode 100644
index 0000000..111168b
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_block_custom.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 "third_party/blink/renderer/core/css/properties/shorthands/border_block.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool BorderBlock::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  const CSSValue* width = nullptr;
+  const CSSValue* style = nullptr;
+  const CSSValue* color = nullptr;
+
+  if (!CSSPropertyParserHelpers::ConsumeBorderShorthand(range, context, width,
+                                                        style, color)) {
+    return false;
+  };
+
+  CSSPropertyParserHelpers::AddExpandedPropertyForValue(
+      CSSPropertyBorderBlockWidth, *width, important, properties);
+  CSSPropertyParserHelpers::AddExpandedPropertyForValue(
+      CSSPropertyBorderBlockStyle, *style, important, properties);
+  CSSPropertyParserHelpers::AddExpandedPropertyForValue(
+      CSSPropertyBorderBlockColor, *color, important, properties);
+
+  return range.AtEnd();
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_block_style_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_block_style_custom.cc
new file mode 100644
index 0000000..9258ef7
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_block_style_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/border_block_style.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool BorderBlockStyle::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      borderBlockStyleShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_block_width_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_block_width_custom.cc
new file mode 100644
index 0000000..da61939
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_block_width_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/border_block_width.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool BorderBlockWidth::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      borderBlockWidthShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc
index ba242f9..7dff25ea 100644
--- a/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_custom.cc
@@ -19,43 +19,14 @@
     const CSSParserContext& context,
     const CSSParserLocalContext&,
     HeapVector<CSSPropertyValue, 256>& properties) const {
-  CSSValue* width = nullptr;
+  const CSSValue* width = nullptr;
   const CSSValue* style = nullptr;
-  CSSValue* color = nullptr;
+  const CSSValue* color = nullptr;
 
-  while (!width || !style || !color) {
-    if (!width) {
-      width = CSSPropertyParserHelpers::ConsumeLineWidth(
-          range, context.Mode(),
-          CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
-      if (width)
-        continue;
-    }
-    if (!style) {
-      bool needs_legacy_parsing = false;
-      style = CSSPropertyParserHelpers::ParseLonghand(
-          CSSPropertyBorderLeftStyle, CSSPropertyBorder, context, range);
-      DCHECK(!needs_legacy_parsing);
-      if (style)
-        continue;
-    }
-    if (!color) {
-      color = CSSPropertyParserHelpers::ConsumeColor(range, context.Mode());
-      if (color)
-        continue;
-    }
-    break;
-  }
-
-  if (!width && !style && !color)
+  if (!CSSPropertyParserHelpers::ConsumeBorderShorthand(range, context, width,
+                                                        style, color)) {
     return false;
-
-  if (!width)
-    width = CSSInitialValue::Create();
-  if (!style)
-    style = CSSInitialValue::Create();
-  if (!color)
-    color = CSSInitialValue::Create();
+  };
 
   CSSPropertyParserHelpers::AddExpandedPropertyForValue(
       CSSPropertyBorderWidth, *width, important, properties);
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_inline_color_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_inline_color_custom.cc
new file mode 100644
index 0000000..315135b5
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_inline_color_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/border_inline_color.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool BorderInlineColor::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      borderInlineColorShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_inline_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_inline_custom.cc
new file mode 100644
index 0000000..67d569590
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_inline_custom.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 "third_party/blink/renderer/core/css/properties/shorthands/border_inline.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool BorderInline::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  const CSSValue* width = nullptr;
+  const CSSValue* style = nullptr;
+  const CSSValue* color = nullptr;
+
+  if (!CSSPropertyParserHelpers::ConsumeBorderShorthand(range, context, width,
+                                                        style, color)) {
+    return false;
+  };
+
+  CSSPropertyParserHelpers::AddExpandedPropertyForValue(
+      CSSPropertyBorderInlineWidth, *width, important, properties);
+  CSSPropertyParserHelpers::AddExpandedPropertyForValue(
+      CSSPropertyBorderInlineStyle, *style, important, properties);
+  CSSPropertyParserHelpers::AddExpandedPropertyForValue(
+      CSSPropertyBorderInlineColor, *color, important, properties);
+
+  return range.AtEnd();
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_inline_style_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_inline_style_custom.cc
new file mode 100644
index 0000000..83859ed
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_inline_style_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/border_inline_style.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool BorderInlineStyle::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      borderInlineStyleShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/border_inline_width_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/border_inline_width_custom.cc
new file mode 100644
index 0000000..1fdacb1
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/border_inline_width_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/border_inline_width.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool BorderInlineWidth::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      borderInlineWidthShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/margin_block_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/margin_block_custom.cc
new file mode 100644
index 0000000..3d91f6d
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/margin_block_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/margin_block.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool MarginBlock::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      marginBlockShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/margin_inline_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/margin_inline_custom.cc
new file mode 100644
index 0000000..3dabd4b
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/margin_inline_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/margin_inline.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool MarginInline::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      marginInlineShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/padding_block_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/padding_block_custom.cc
new file mode 100644
index 0000000..959c9ed
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/padding_block_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/padding_block.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool PaddingBlock::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      paddingBlockShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/padding_inline_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/padding_inline_custom.cc
new file mode 100644
index 0000000..79c0a3b0
--- /dev/null
+++ b/third_party/blink/renderer/core/css/properties/shorthands/padding_inline_custom.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/css/properties/shorthands/padding_inline.h"
+
+#include "third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h"
+#include "third_party/blink/renderer/core/style_property_shorthand.h"
+
+namespace blink {
+namespace CSSShorthand {
+
+bool PaddingInline::ParseShorthand(
+    bool important,
+    CSSParserTokenRange& range,
+    const CSSParserContext& context,
+    const CSSParserLocalContext&,
+    HeapVector<CSSPropertyValue, 256>& properties) const {
+  return CSSPropertyParserHelpers::ConsumeShorthandVia2Longhands(
+      paddingInlineShorthand(), important, context, range, properties);
+}
+
+}  // namespace CSSShorthand
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/editing/frame_selection.h b/third_party/blink/renderer/core/editing/frame_selection.h
index e164ea2..7b1ecd42 100644
--- a/third_party/blink/renderer/core/editing/frame_selection.h
+++ b/third_party/blink/renderer/core/editing/frame_selection.h
@@ -64,9 +64,7 @@
 enum class CaretVisibility;
 
 enum class HandleVisibility { kNotVisible, kVisible };
-
-// TODO(yoichio): Rename this to SelectSoftLineBreak
-enum class SelectLineBreak { kNotSelected, kSelected };
+enum class SelectSoftLineBreak { kNotSelected, kSelected };
 
 // This is return type of ComputeLayoutSelectionStatus(paintfragment).
 // This structure represents how the fragment is selected.
@@ -81,7 +79,7 @@
 
   LayoutSelectionStatus(unsigned passed_start,
                         unsigned passed_end,
-                        SelectLineBreak passed_line_break)
+                        SelectSoftLineBreak passed_line_break)
       : start(passed_start), end(passed_end), line_break(passed_line_break) {
     DCHECK_LE(start, end);
   }
@@ -92,7 +90,7 @@
 
   unsigned start;
   unsigned end;
-  SelectLineBreak line_break;
+  SelectSoftLineBreak line_break;
 };
 
 class CORE_EXPORT FrameSelection final
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
index f7a30b8..535a184 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_test.cc
@@ -123,8 +123,7 @@
   String text_chunks;
   for (; !iterator.AtEnd(); iterator.Advance()) {
     text_chunks.append('[');
-    text_chunks.append(
-        iterator.GetText().Substring(0, iterator.GetText().length()));
+    text_chunks.append(iterator.GetText().GetTextForTesting());
     text_chunks.append(']');
   }
   return std::string(text_chunks.Utf8().data());
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.cc b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.cc
index 66c79b7..7170b04b 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.cc
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.cc
@@ -73,18 +73,10 @@
   return text_[text_start_offset_ + index];
 }
 
-String TextIteratorTextState::Substring(unsigned position,
-                                        unsigned length) const {
-  SECURITY_DCHECK(position <= this->length());
-  SECURITY_DCHECK(position + length <= this->length());
-  if (!length)
-    return g_empty_string;
-  if (single_character_buffer_) {
-    DCHECK_EQ(position, 0u);
-    DCHECK_EQ(length, 1u);
+String TextIteratorTextState::GetTextForTesting() const {
+  if (single_character_buffer_)
     return String(&single_character_buffer_, 1);
-  }
-  return text_.Substring(text_start_offset_ + position, length);
+  return text_.Substring(text_start_offset_, length());
 }
 
 void TextIteratorTextState::AppendTextToStringBuilder(
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h
index e185b2f..9b880d5 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator_text_state.h
@@ -49,7 +49,7 @@
   // Return properties of the current text.
   unsigned length() const { return text_length_; }
   UChar CharacterAt(unsigned index) const;
-  String Substring(unsigned position, unsigned length) const;
+  String GetTextForTesting() const;
   void AppendTextToStringBuilder(StringBuilder&,
                                  unsigned position = 0,
                                  unsigned max_length = UINT_MAX) const;
diff --git a/third_party/blink/renderer/core/editing/layout_selection.cc b/third_party/blink/renderer/core/editing/layout_selection.cc
index d3aa88b..2286b3e 100644
--- a/third_party/blink/renderer/core/editing/layout_selection.cc
+++ b/third_party/blink/renderer/core/editing/layout_selection.cc
@@ -752,7 +752,7 @@
       ToNGPhysicalTextFragmentOrDie(fragment.PhysicalFragment());
   // We don't paint selection on ellipsis.
   if (text_fragment.StyleVariant() == NGStyleVariant::kEllipsis)
-    return {0, 0, SelectLineBreak::kNotSelected};
+    return {0, 0, SelectSoftLineBreak::kNotSelected};
   switch (text_fragment.GetLayoutObject()->GetSelectionState()) {
     case SelectionState::kStart: {
       DCHECK(SelectionStart().has_value());
@@ -761,8 +761,8 @@
       return {ClampOffset(start_in_block, text_fragment),
               text_fragment.EndOffset(),
               (is_continuous && IsBeforeSoftLineBreak(fragment))
-                  ? SelectLineBreak::kSelected
-                  : SelectLineBreak::kNotSelected};
+                  ? SelectSoftLineBreak::kSelected
+                  : SelectSoftLineBreak::kNotSelected};
     }
     case SelectionState::kEnd: {
       DCHECK(SelectionEnd().has_value());
@@ -772,8 +772,8 @@
       const bool is_continuous = text_fragment.EndOffset() < end_in_block;
       return {text_fragment.StartOffset(), end_in_fragment,
               (is_continuous && IsBeforeSoftLineBreak(fragment))
-                  ? SelectLineBreak::kSelected
-                  : SelectLineBreak::kNotSelected};
+                  ? SelectSoftLineBreak::kSelected
+                  : SelectSoftLineBreak::kNotSelected};
     }
     case SelectionState::kStartAndEnd: {
       DCHECK(SelectionStart().has_value());
@@ -786,17 +786,18 @@
                                  text_fragment.EndOffset() < end_in_block;
       return {ClampOffset(start_in_block, text_fragment), end_in_fragment,
               (is_continuous && IsBeforeSoftLineBreak(fragment))
-                  ? SelectLineBreak::kSelected
-                  : SelectLineBreak::kNotSelected};
+                  ? SelectSoftLineBreak::kSelected
+                  : SelectSoftLineBreak::kNotSelected};
     }
     case SelectionState::kInside: {
       return {text_fragment.StartOffset(), text_fragment.EndOffset(),
-              IsBeforeSoftLineBreak(fragment) ? SelectLineBreak::kSelected
-                                              : SelectLineBreak::kNotSelected};
+              IsBeforeSoftLineBreak(fragment)
+                  ? SelectSoftLineBreak::kSelected
+                  : SelectSoftLineBreak::kNotSelected};
     }
     default:
       // This block is not included in selection.
-      return {0, 0, SelectLineBreak::kNotSelected};
+      return {0, 0, SelectSoftLineBreak::kNotSelected};
   }
 }
 
diff --git a/third_party/blink/renderer/core/editing/layout_selection_test.cc b/third_party/blink/renderer/core/editing/layout_selection_test.cc
index fb1f41b..92e94da 100644
--- a/third_party/blink/renderer/core/editing/layout_selection_test.cc
+++ b/third_party/blink/renderer/core/editing/layout_selection_test.cc
@@ -928,7 +928,7 @@
         GetNGPaintFragment(first_text->GetLayoutObject());
     const LayoutSelectionStatus& status =
         Selection().ComputeLayoutSelectionStatus(fragment);
-    return status.line_break == SelectLineBreak::kSelected;
+    return status.line_break == SelectSoftLineBreak::kSelected;
   }
 
   LayoutSelectionStatus ComputeLayoutSelectionStatus(const Node& node) {
@@ -946,9 +946,9 @@
 
 std::ostream& operator<<(std::ostream& ostream,
                          const LayoutSelectionStatus& status) {
-  const String line_break = (status.line_break == SelectLineBreak::kSelected)
-                                ? "kSelected"
-                                : "kNotSelected";
+  const String line_break =
+      (status.line_break == SelectSoftLineBreak::kSelected) ? "kSelected"
+                                                            : "kNotSelected";
   return ostream << status.start << ", " << status.end << ", " << std::boolalpha
                  << line_break;
 }
@@ -964,7 +964,7 @@
 
   LayoutObject* const foo =
       GetDocument().body()->firstChild()->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(0u, 0u, SelectLineBreak::kNotSelected),
+  EXPECT_EQ(LayoutSelectionStatus(0u, 0u, SelectSoftLineBreak::kNotSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo)));
   LayoutObject* const bar = GetDocument()
                                 .body()
@@ -972,7 +972,7 @@
                                 ->nextSibling()
                                 ->firstChild()
                                 ->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(4u, 5u, SelectLineBreak::kNotSelected),
+  EXPECT_EQ(LayoutSelectionStatus(4u, 5u, SelectSoftLineBreak::kNotSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(bar)));
 }
 
@@ -988,12 +988,12 @@
   const LayoutTextFragment* const foo_f =
       ToLayoutTextFragment(AssociatedLayoutObjectOf(*foo, 0));
   EXPECT_EQ(
-      LayoutSelectionStatus(0u, 1u, SelectLineBreak::kSelected),
+      LayoutSelectionStatus(0u, 1u, SelectSoftLineBreak::kSelected),
       Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo_f)));
   const LayoutTextFragment* const foo_oo =
       ToLayoutTextFragment(AssociatedLayoutObjectOf(*foo, 1));
   EXPECT_EQ(
-      LayoutSelectionStatus(1u, 2u, SelectLineBreak::kNotSelected),
+      LayoutSelectionStatus(1u, 2u, SelectSoftLineBreak::kNotSelected),
       Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo_oo)));
 }
 
@@ -1008,7 +1008,7 @@
   TEST_CHECK();
   LayoutObject* const foo =
       GetDocument().body()->firstChild()->firstChild()->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectLineBreak::kSelected),
+  EXPECT_EQ(LayoutSelectionStatus(1u, 3u, SelectSoftLineBreak::kSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(foo)));
   LayoutObject* const bar = GetDocument()
                                 .body()
@@ -1016,7 +1016,7 @@
                                 ->nextSibling()
                                 ->firstChild()
                                 ->GetLayoutObject();
-  EXPECT_EQ(LayoutSelectionStatus(0u, 2u, SelectLineBreak::kNotSelected),
+  EXPECT_EQ(LayoutSelectionStatus(0u, 2u, SelectSoftLineBreak::kNotSelected),
             Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(bar)));
 }
 
@@ -1101,10 +1101,10 @@
       "bar<img id=img2 width=10px height=10px>|</div>");
   Node* const foo =
       GetDocument().body()->firstChild()->firstChild()->nextSibling();
-  EXPECT_EQ(SelectLineBreak::kNotSelected,
+  EXPECT_EQ(SelectSoftLineBreak::kNotSelected,
             ComputeLayoutSelectionStatus(*foo).line_break);
   Node* const bar = foo->nextSibling()->nextSibling();
-  EXPECT_EQ(SelectLineBreak::kNotSelected,
+  EXPECT_EQ(SelectSoftLineBreak::kNotSelected,
             ComputeLayoutSelectionStatus(*bar).line_break);
 }
 
@@ -1117,7 +1117,7 @@
       GetDocument().QuerySelector("br")->GetLayoutObject();
   CHECK(layout_br->IsBR());
   EXPECT_EQ(
-      LayoutSelectionStatus(3u, 4u, SelectLineBreak::kNotSelected),
+      LayoutSelectionStatus(3u, 4u, SelectSoftLineBreak::kNotSelected),
       Selection().ComputeLayoutSelectionStatus(GetNGPaintFragment(layout_br)));
 }
 
diff --git a/third_party/blink/renderer/core/fetch/body_stream_buffer.cc b/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
index 2aae5ac..d5be0e6 100644
--- a/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
+++ b/third_party/blink/renderer/core/fetch/body_stream_buffer.cc
@@ -423,6 +423,11 @@
 }
 
 void BodyStreamBuffer::Abort() {
+  if (!Controller()) {
+    DCHECK(!GetExecutionContext());
+    DCHECK(!consumer_);
+    return;
+  }
   Controller()->GetError(DOMException::Create(DOMExceptionCode::kAbortError));
   CancelConsumer();
 }
diff --git a/third_party/blink/renderer/core/frame/report.h b/third_party/blink/renderer/core/frame/report.h
index 7391a8e..5163422 100644
--- a/third_party/blink/renderer/core/frame/report.h
+++ b/third_party/blink/renderer/core/frame/report.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_REPORT_H_
 
 #include "third_party/blink/renderer/core/frame/report_body.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/core/frame/use_counter.cc b/third_party/blink/renderer/core/frame/use_counter.cc
index 6bf1a6a..de7fd93 100644
--- a/third_party/blink/renderer/core/frame/use_counter.cc
+++ b/third_party/blink/renderer/core/frame/use_counter.cc
@@ -1186,6 +1186,30 @@
       return 616;
     case CSSPropertyBorderInlineEnd:
       return 617;
+    case CSSPropertyMarginBlock:
+      return 618;
+    case CSSPropertyMarginInline:
+      return 619;
+    case CSSPropertyPaddingBlock:
+      return 620;
+    case CSSPropertyPaddingInline:
+      return 621;
+    case CSSPropertyBorderBlockColor:
+      return 622;
+    case CSSPropertyBorderBlockStyle:
+      return 623;
+    case CSSPropertyBorderBlockWidth:
+      return 624;
+    case CSSPropertyBorderInlineColor:
+      return 625;
+    case CSSPropertyBorderInlineStyle:
+      return 626;
+    case CSSPropertyBorderInlineWidth:
+      return 627;
+    case CSSPropertyBorderBlock:
+      return 628;
+    case CSSPropertyBorderInline:
+      return 629;
     // 1. Add new features above this line (don't change the assigned numbers of
     // the existing items).
     // 2. Update kMaximumCSSSampleId (defined in
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 4d2516a..e54386b 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -5806,6 +5806,8 @@
   command attachToTarget
     parameters
       TargetID targetId
+      # Enables "flat" access to the session via specifying sessionId attribute in the commands.
+      experimental optional boolean flatten
     returns
       # Id assigned to the session.
       SessionID sessionId
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index dfbec903..7aa3da47 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3985,6 +3985,12 @@
     LayoutUnit static_position = child->Layer()->StaticInlinePosition() +
                                  container_logical_width +
                                  container_block->BorderLogicalLeft();
+    if (container_block->IsBox() &&
+        ToLayoutBox(container_block)
+            ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
+      static_position +=
+          ToLayoutBox(container_block)->OriginAdjustmentForScrollbars().Width();
+    }
     for (LayoutObject* curr = child->Parent(); curr; curr = curr->Container()) {
       if (curr->IsBox()) {
         if (curr == enclosing_box)
diff --git a/third_party/blink/renderer/core/layout/layout_view.cc b/third_party/blink/renderer/core/layout/layout_view.cc
index e86a0b1..6a26e8b 100644
--- a/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/third_party/blink/renderer/core/layout/layout_view.cc
@@ -148,7 +148,19 @@
     hit_layer = true;
     result = cache_result;
   } else {
-    hit_layer = Layer()->HitTest(location, result);
+    LocalFrameView* frame_view = GetFrameView();
+    LayoutRect hit_test_area;
+    if (frame_view) {
+      // Start with a rect sized to the frame, to ensure we include the
+      // scrollbars.
+      hit_test_area = LayoutRect(LayoutPoint(), LayoutSize(frame_view->Size()));
+      if (result.GetHitTestRequest().IgnoreClipping()) {
+        hit_test_area.Unite(
+            frame_view->DocumentToFrame(LayoutRect(DocumentRect())));
+      }
+    }
+
+    hit_layer = Layer()->HitTest(location, result, hit_test_area);
 
     // If hitTestResult include scrollbar, innerNode should be the parent of the
     // scrollbar.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index 5309915f..96d18a5 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -1379,8 +1379,12 @@
                          child_data.margins.block_end, &logical_block_offset,
                          &margin_strut);
   } else {
-    margin_strut.Append(child_data.margins.block_end,
-                        child.Style().HasMarginAfterQuirk());
+    // An empty block's end margin can "inherit" quirkiness from its start
+    // margin. E.g.
+    // <ol style="margin-bottom: 20px"></ol>
+    bool is_quirky = (is_empty_block && child.Style().HasMarginBeforeQuirk()) ||
+                     child.Style().HasMarginAfterQuirk();
+    margin_strut.Append(child_data.margins.block_end, is_quirky);
   }
 
   // This flag is subtle, but in order to determine our size correctly we need
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
index 86fbeeaa..3d21038 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.cc
@@ -138,7 +138,8 @@
   point_in_foreign_object.MoveBy(-Layer()->LayoutBoxLocation());
   HitTestLocation location(point_in_foreign_object);
   HitTestResult layer_result(result.GetHitTestRequest(), location);
-  bool retval = Layer()->HitTest(location, layer_result);
+  bool retval = Layer()->HitTest(location, layer_result,
+                                 LayoutRect(LayoutRect::InfiniteIntRect()));
 
   // Preserve the "point in inner node frame" from the original request,
   // since |layer_result| is a hit test rooted at the <foreignObject> element,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
index 04b1417..fe6dd083 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
@@ -286,7 +286,7 @@
   HitTestRequest request(HitTestRequest::kReadOnly | HitTestRequest::kActive);
   HitTestLocation location((LayoutPoint(206, 206)));
   HitTestResult result(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(target, result.InnerNode());
   EXPECT_EQ(LayoutPoint(206, 206), result.PointInInnerNodeFrame());
 }
@@ -310,19 +310,57 @@
 
   const auto& svg = *GetDocument().getElementById("svg");
   const auto& target = *GetDocument().getElementById("target");
-  const auto& foreignObject = *GetDocument().getElementById("foreignObject");
+  const auto& foreign_object = *GetDocument().getElementById("foreignObject");
 
   EXPECT_EQ(svg, GetDocument().ElementFromPoint(1, 1));
-  EXPECT_EQ(foreignObject, GetDocument().ElementFromPoint(231, 201));
+  EXPECT_EQ(foreign_object, GetDocument().ElementFromPoint(231, 201));
   EXPECT_EQ(target, GetDocument().ElementFromPoint(236, 206));
-  EXPECT_EQ(foreignObject, GetDocument().ElementFromPoint(235, 255));
+  EXPECT_EQ(foreign_object, GetDocument().ElementFromPoint(235, 255));
 
   HitTestRequest request(HitTestRequest::kReadOnly | HitTestRequest::kActive);
   HitTestLocation location((LayoutPoint(236, 206)));
   HitTestResult result(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(target, result.InnerNode());
   EXPECT_EQ(LayoutPoint(236, 206), result.PointInInnerNodeFrame());
 }
 
+TEST_F(LayoutSVGForeignObjectTest, HitTestUnderScrollingAncestor) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      * {
+        margin: 0
+      }
+    </style>
+    <div id=scroller style="width: 500px; height: 500px; overflow: auto">
+      <svg width="3000" height="3000">
+        <foreignObject width="3000" height="3000">
+          <div id="target" style="width: 3000px; height: 3000px; background: red">
+          </div>
+        </foreignObject>
+      </svg>
+    </div>
+  )HTML");
+
+  auto& scroller = *GetDocument().getElementById("scroller");
+  const auto& target = *GetDocument().getElementById("target");
+
+  EXPECT_EQ(target, GetDocument().ElementFromPoint(450, 450));
+
+  HitTestRequest request(HitTestRequest::kReadOnly | HitTestRequest::kActive);
+  HitTestLocation location((LayoutPoint(450, 450)));
+  HitTestResult result(request, location);
+  GetDocument().GetLayoutView()->HitTest(location, result);
+  EXPECT_EQ(target, result.InnerNode());
+  EXPECT_EQ(LayoutPoint(450, 450), result.PointInInnerNodeFrame());
+
+  scroller.setScrollTop(3000);
+
+  EXPECT_EQ(target, GetDocument().ElementFromPoint(450, 450));
+
+  GetDocument().GetLayoutView()->HitTest(location, result);
+  EXPECT_EQ(target, result.InnerNode());
+  EXPECT_EQ(LayoutPoint(450, 450), result.PointInInnerNodeFrame());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index a51d051..103f20d4 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -574,12 +574,6 @@
       document_loader_ == document_loader_->GetFrame()
                               ->Loader()
                               .GetProvisionalDocumentLoader()) {
-    FrameClientHintsPreferencesContext hints_context(GetFrame());
-    document_loader_->GetClientHintsPreferences()
-        .UpdateFromAcceptClientHintsHeader(
-            response.HttpHeaderField(HTTPNames::Accept_CH), response.Url(),
-            &hints_context);
-
     // When response is received with a provisional docloader, the resource
     // haven't committed yet, and we cannot load resources, only preconnect.
     resource_loading_policy = LinkLoader::kDoNotLoadResources;
@@ -1329,16 +1323,26 @@
 
 void FrameFetchContext::ParseAndPersistClientHints(
     const ResourceResponse& response) {
-  ClientHintsPreferences hints_preferences;
-  WebEnabledClientHints enabled_client_hints;
-  TimeDelta persist_duration;
   FrameClientHintsPreferencesContext hints_context(GetFrame());
-  hints_preferences.UpdatePersistentHintsFromHeaders(
-      response, &hints_context, enabled_client_hints, &persist_duration);
 
+  document_loader_->GetClientHintsPreferences()
+      .UpdateFromAcceptClientHintsLifetimeHeader(
+          response.HttpHeaderField(HTTPNames::Accept_CH_Lifetime),
+          response.Url(), &hints_context);
+
+  document_loader_->GetClientHintsPreferences()
+      .UpdateFromAcceptClientHintsHeader(
+          response.HttpHeaderField(HTTPNames::Accept_CH), response.Url(),
+          &hints_context);
+
+  // Notify content settings client of persistent client hints.
+  TimeDelta persist_duration =
+      document_loader_->GetClientHintsPreferences().GetPersistDuration();
   if (persist_duration.InSeconds() <= 0)
     return;
 
+  WebEnabledClientHints enabled_client_hints =
+      document_loader_->GetClientHintsPreferences().GetWebEnabledClientHints();
   if (!AllowScriptFromSourceWithoutNotifying(response.Url())) {
     // Do not persist client hint preferences if the JavaScript is disabled.
     return;
diff --git a/third_party/blink/renderer/core/loader/http_equiv.cc b/third_party/blink/renderer/core/loader/http_equiv.cc
index 5a936c7..8931a90 100644
--- a/third_party/blink/renderer/core/loader/http_equiv.cc
+++ b/third_party/blink/renderer/core/loader/http_equiv.cc
@@ -47,7 +47,7 @@
         kSecurityMessageSource, kErrorMessageLevel,
         "X-Frame-Options may only be set via an HTTP header sent along with a "
         "document. It may not be set inside <meta>."));
-  } else if (EqualIgnoringASCIICase(equiv, "accept-ch")) {
+  } else if (EqualIgnoringASCIICase(equiv, HTTPNames::Accept_CH)) {
     ProcessHttpEquivAcceptCH(document, content);
   } else if (EqualIgnoringASCIICase(equiv, "content-security-policy") ||
              EqualIgnoringASCIICase(equiv,
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 ae87746f..e1c94ea 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
@@ -66,7 +66,7 @@
     const LayoutSelectionStatus& selection_status) {
   // Expand paint rect if selection covers multiple lines and
   // this fragment is at the end of line.
-  if (selection_status.line_break == SelectLineBreak::kNotSelected)
+  if (selection_status.line_break == SelectSoftLineBreak::kNotSelected)
     return rect;
   if (paint_fragment.GetLayoutObject()
           ->EnclosingNGBlockFlow()
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index fc924df3..3d32c57 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1783,14 +1783,6 @@
   }
 }
 
-static inline LayoutRect FrameVisibleRect(LayoutObject& layout_object) {
-  LocalFrameView* frame_view = layout_object.GetDocument().View();
-  if (!frame_view)
-    return LayoutRect();
-
-  return LayoutRect(LayoutPoint(), LayoutSize(frame_view->Size()));
-}
-
 PaintLayer::HitTestRecursionData::HitTestRecursionData(
     const LayoutRect& rect_arg,
     const HitTestLocation& location_arg,
@@ -1801,7 +1793,8 @@
       intersects_location(location_arg.Intersects(rect_arg)) {}
 
 bool PaintLayer::HitTest(const HitTestLocation& hit_test_location,
-                         HitTestResult& result) {
+                         HitTestResult& result,
+                         const LayoutRect& hit_test_area) {
   DCHECK(IsSelfPaintingLayer() || HasSelfPaintingLayerDescendant());
 
   // LayoutView should make sure to update layout before entering hit testing
@@ -1810,15 +1803,6 @@
 
   const HitTestRequest& request = result.GetHitTestRequest();
 
-  // Start with frameVisibleRect to ensure we include the scrollbars.
-  LayoutRect hit_test_area = FrameVisibleRect(GetLayoutObject());
-  if (request.IgnoreClipping()) {
-    if (LocalFrameView* frame_view = GetLayoutObject().GetDocument().View()) {
-      hit_test_area.Unite(frame_view->DocumentToFrame(
-          LayoutRect(GetLayoutObject().View()->DocumentRect())));
-    }
-  }
-
   HitTestRecursionData recursion_data(hit_test_area, hit_test_location,
                                       hit_test_location);
   PaintLayer* inside_layer =
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index f175445..a4a681f 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -422,7 +422,11 @@
 
   // The hitTest() method looks for mouse events by walking layers that
   // intersect the point from front to back.
-  bool HitTest(const HitTestLocation& location, HitTestResult&);
+  // |hit_test_area| is the rect in the space of this PaintLayer's
+  // LayoutObject to consider for hit testing.
+  bool HitTest(const HitTestLocation& location,
+               HitTestResult&,
+               const LayoutRect& hit_test_area);
 
   bool IntersectsDamageRect(const LayoutRect& layer_bounds,
                             const LayoutRect& damage_rect,
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 d830509..f7bf202 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -1375,21 +1375,21 @@
   HitTestRequest request(HitTestRequest::kReadOnly | HitTestRequest::kActive);
   HitTestLocation location((LayoutPoint(50, 25)));
   HitTestResult result(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(child, result.InnerNode());
 
   // Same hit test, with stop node.
   request = HitTestRequest(HitTestRequest::kReadOnly | HitTestRequest::kActive,
                            hit->GetLayoutObject());
   result = HitTestResult(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(hit, result.InnerNode());
 
   // Regular hit test over 'overlap'
   request = HitTestRequest(HitTestRequest::kReadOnly | HitTestRequest::kActive);
   location = HitTestLocation((LayoutPoint(50, 75)));
   result = HitTestResult(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(overlap, result.InnerNode());
 
   // Same hit test, with stop node, should still hit 'overlap' because it's not
@@ -1397,7 +1397,7 @@
   request = HitTestRequest(HitTestRequest::kReadOnly | HitTestRequest::kActive,
                            hit->GetLayoutObject());
   result = HitTestResult(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(overlap, result.InnerNode());
 
   // List-based hit test with stop node
@@ -1406,7 +1406,7 @@
                            hit->GetLayoutObject());
   location = HitTestLocation((LayoutRect(40, 15, 20, 20)));
   result = HitTestResult(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(1u, result.ListBasedTestResult().size());
   EXPECT_EQ(hit, *result.ListBasedTestResult().begin());
 }
@@ -1435,13 +1435,13 @@
   HitTestRequest request(HitTestRequest::kReadOnly | HitTestRequest::kActive);
   HitTestLocation location((LayoutPoint(50, 50)));
   HitTestResult result(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(cell11, result.InnerNode());
 
   request = HitTestRequest(HitTestRequest::kReadOnly | HitTestRequest::kActive,
                            table->GetLayoutObject());
   result = HitTestResult(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(table, result.InnerNode());
 }
 
@@ -1456,13 +1456,13 @@
   HitTestRequest request(HitTestRequest::kReadOnly | HitTestRequest::kActive);
   HitTestLocation location((LayoutPoint(50, 50)));
   HitTestResult result(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(circle, result.InnerNode());
 
   request = HitTestRequest(HitTestRequest::kReadOnly | HitTestRequest::kActive,
                            svg->GetLayoutObject());
   result = HitTestResult(request, location);
-  GetDocument().GetLayoutView()->Layer()->HitTest(location, result);
+  GetDocument().GetLayoutView()->HitTest(location, result);
   EXPECT_EQ(svg, result.InnerNode());
 }
 
diff --git a/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc b/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
index 69e92d99..805d303 100644
--- a/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
+++ b/third_party/blink/renderer/core/svg/graphics/svg_image_test.cc
@@ -115,7 +115,7 @@
   // true for shouldPauseAnimation, this will result in the timeline being
   // suspended.
   test::RunDelayedTasks(TimeDelta::FromMilliseconds(1) +
-                        TimeDelta::FromSecondsD(timer->NextFireInterval()));
+                        timer->NextFireIntervalDelta());
   EXPECT_TRUE(chrome_client.IsSuspended());
   EXPECT_FALSE(timer->IsActive());
 
@@ -149,7 +149,7 @@
   // Fire the timer/trigger a frame update. The timeline will remain
   // suspended and no frame will be scheduled.
   test::RunDelayedTasks(TimeDelta::FromMillisecondsD(1) +
-                        TimeDelta::FromSecondsD(timer->NextFireInterval()));
+                        timer->NextFireIntervalDelta());
   EXPECT_TRUE(chrome_client.IsSuspended());
   EXPECT_FALSE(timer->IsActive());
 
@@ -226,7 +226,7 @@
   // Wait for the next animation frame to be triggered, and then trigger a new
   // frame. The image animation timeline should be running.
   test::RunDelayedTasks(TimeDelta::FromMilliseconds(1) +
-                        TimeDelta::FromSecondsD(timer->NextFireInterval()));
+                        timer->NextFireIntervalDelta());
   Compositor().BeginFrame();
 
   EXPECT_FALSE(svg_image_chrome_client.IsSuspended());
@@ -236,7 +236,7 @@
   // animation timeline.)
   WebView().SetVisibilityState(mojom::PageVisibilityState::kHidden, false);
   test::RunDelayedTasks(TimeDelta::FromMilliseconds(1) +
-                        TimeDelta::FromSecondsD(timer->NextFireInterval()));
+                        timer->NextFireIntervalDelta());
 
   EXPECT_TRUE(svg_image_chrome_client.IsSuspended());
 
@@ -244,7 +244,7 @@
   // frame and resume the image animation.
   WebView().SetVisibilityState(mojom::PageVisibilityState::kVisible, false);
   test::RunDelayedTasks(TimeDelta::FromMilliseconds(1) +
-                        TimeDelta::FromSecondsD(timer->NextFireInterval()));
+                        timer->NextFireIntervalDelta());
   Compositor().BeginFrame();
 
   EXPECT_FALSE(svg_image_chrome_client.IsSuspended());
diff --git a/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc b/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
index d6d86754..8995082 100644
--- a/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
+++ b/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/core/testing/worker_internals.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
 #include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 
 namespace WebCoreTestSupport {
 
diff --git a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
index 61ed37a8..8a8e790d 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_layout_object.cc
@@ -1665,7 +1665,8 @@
   HitTestRequest request(HitTestRequest::kReadOnly | HitTestRequest::kActive);
   HitTestLocation location(point);
   HitTestResult hit_test_result = HitTestResult(request, location);
-  layer->HitTest(location, hit_test_result);
+  layer->HitTest(location, hit_test_result,
+                 LayoutRect(LayoutRect::InfiniteIntRect()));
 
   Node* node = hit_test_result.InnerNode();
   if (!node)
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
index 455d69fee..cea538e5 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/modules/animationworklet/animation_worklet.h"
 
+#include "base/atomic_sequence_num.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/dom/animation_worklet_proxy_client.h"
 #include "third_party/blink/renderer/core/dom/document.h"
@@ -13,9 +14,18 @@
 #include "third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h"
 #include "third_party/blink/renderer/modules/animationworklet/animation_worklet_thread.h"
 
+base::AtomicSequenceNumber g_next_worklet_id;
+
+int NextId() {
+  // Start id from 1. This way it safe to use it as key in hashmap with default
+  // key traits.
+  return g_next_worklet_id.GetNext() + 1;
+}
+
 namespace blink {
 
-AnimationWorklet::AnimationWorklet(Document* document) : Worklet(document) {}
+AnimationWorklet::AnimationWorklet(Document* document)
+    : Worklet(document), scope_id_(NextId()), last_animation_id_(0) {}
 
 AnimationWorklet::~AnimationWorklet() = default;
 
@@ -31,7 +41,7 @@
 
   Document* document = ToDocument(GetExecutionContext());
   AnimationWorkletProxyClient* proxy_client =
-      AnimationWorkletProxyClientImpl::FromDocument(document);
+      AnimationWorkletProxyClientImpl::FromDocument(document, scope_id_);
 
   WorkerClients* worker_clients = WorkerClients::Create();
   ProvideAnimationWorkletProxyClientTo(worker_clients, proxy_client);
@@ -42,6 +52,12 @@
   return proxy;
 }
 
+WorkletAnimationId AnimationWorklet::NextWorkletAnimationId() {
+  // Id starts from 1. This way it safe to use it as key in hashmap with default
+  // key traits.
+  return {.scope_id = scope_id_, .animation_id = ++last_animation_id_};
+}
+
 void AnimationWorklet::Trace(blink::Visitor* visitor) {
   Worklet::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet.h b/third_party/blink/renderer/modules/animationworklet/animation_worklet.h
index 7abefd82..fa072689 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet.h
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet.h
@@ -7,6 +7,7 @@
 
 #include "third_party/blink/renderer/core/workers/worklet.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/graphics/compositor_animators_state.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 
 namespace blink {
@@ -25,9 +26,14 @@
   explicit AnimationWorklet(Document*);
   ~AnimationWorklet() override;
 
+  WorkletAnimationId NextWorkletAnimationId();
   void Trace(blink::Visitor*) override;
 
  private:
+  // Unique id associated with this worklet that is used by cc to identify all
+  // animations associated it.
+  int scope_id_;
+  int last_animation_id_;
 
   // Implements Worklet.
   bool NeedsToCreateGlobalScope() final;
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
index 9c2640c..d6f18952 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.cc
@@ -21,12 +21,12 @@
 
 void UpdateAnimation(Animator* animator,
                      ScriptState* script_state,
-                     int id,
+                     WorkletAnimationId id,
                      double current_time,
                      CompositorMutatorOutputState* result) {
   CompositorMutatorOutputState::AnimationState animation_output;
   if (animator->Animate(script_state, current_time, &animation_output)) {
-    animation_output.animation_id = id;
+    animation_output.worklet_animation_id = id;
     result->animations.push_back(std::move(animation_output));
   }
 }
@@ -77,23 +77,22 @@
   return animator;
 }
 
-std::unique_ptr<CompositorMutatorOutputState>
-AnimationWorkletGlobalScope::Mutate(
-    const CompositorMutatorInputState& mutator_input) {
+std::unique_ptr<AnimationWorkletOutput> AnimationWorkletGlobalScope::Mutate(
+    const AnimationWorkletInput& mutator_input) {
   DCHECK(IsContextThread());
 
   ScriptState* script_state = ScriptController()->GetScriptState();
   ScriptState::Scope scope(script_state);
 
-  std::unique_ptr<CompositorMutatorOutputState> result =
-      std::make_unique<CompositorMutatorOutputState>();
+  std::unique_ptr<AnimationWorkletOutput> result =
+      std::make_unique<AnimationWorkletOutput>();
 
-  for (const auto& id : mutator_input.removed_animations)
-    animators_.erase(id);
+  for (const auto& worklet_animation_id : mutator_input.removed_animations)
+    animators_.erase(worklet_animation_id.animation_id);
 
   for (const auto& animation : mutator_input.added_and_updated_animations) {
-    int id = animation.animation_id;
-    DCHECK(!animators_.at(id));
+    int id = animation.worklet_animation_id.animation_id;
+    DCHECK(!animators_.Contains(id));
     const String name =
         String::FromUTF8(animation.name.data(), animation.name.size());
 
@@ -105,19 +104,19 @@
     if (!animator)
       continue;
 
-    UpdateAnimation(animator, script_state, id, animation.current_time,
-                    result.get());
+    UpdateAnimation(animator, script_state, animation.worklet_animation_id,
+                    animation.current_time, result.get());
   }
 
   for (const auto& animation : mutator_input.updated_animations) {
-    int id = animation.animation_id;
+    int id = animation.worklet_animation_id.animation_id;
     Animator* animator = animators_.at(id);
     // We don't try to create an animator if there isn't any.
     if (!animator)
       continue;
 
-    UpdateAnimation(animator, script_state, id, animation.current_time,
-                    result.get());
+    UpdateAnimation(animator, script_state, animation.worklet_animation_id,
+                    animation.current_time, result.get());
   }
 
   return result;
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h
index fdce086..cfcb8da 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope.h
@@ -42,8 +42,7 @@
   bool IsAnimationWorkletGlobalScope() const final { return true; }
 
   // Invokes the |animate| function of all of its active animators.
-  std::unique_ptr<CompositorMutatorOutputState> Mutate(
-      const CompositorMutatorInputState&);
+  std::unique_ptr<AnimationWorkletOutput> Mutate(const AnimationWorkletInput&);
 
   // Registers a animator definition with the given name and constructor.
   void registerAnimator(const String& name,
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
index 7839039..461b599 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_global_scope_test.cc
@@ -222,10 +222,12 @@
 
     // Passing a new input state with a new animation id should cause the
     // worklet to create and animate an animator.
-    CompositorMutatorInputState state;
-    state.added_and_updated_animations.emplace_back(1, "test", 5000, nullptr);
+    cc::WorkletAnimationId animation_id = {1, 1};
+    AnimationWorkletInput state;
+    state.added_and_updated_animations.emplace_back(animation_id, "test", 5000,
+                                                    nullptr);
 
-    std::unique_ptr<CompositorMutatorOutputState> output =
+    std::unique_ptr<AnimationWorkletOutput> output =
         global_scope->Mutate(state);
     EXPECT_TRUE(output);
 
@@ -270,10 +272,12 @@
 
     // Passing a new input state with a new animation id should cause the
     // worklet to create and animate an animator.
-    CompositorMutatorInputState state;
-    state.added_and_updated_animations.emplace_back(1, "test", 5000, nullptr);
+    cc::WorkletAnimationId animation_id = {1, 1};
+    AnimationWorkletInput state;
+    state.added_and_updated_animations.emplace_back(animation_id, "test", 5000,
+                                                    nullptr);
 
-    std::unique_ptr<CompositorMutatorOutputState> output =
+    std::unique_ptr<AnimationWorkletOutput> output =
         global_scope->Mutate(state);
     EXPECT_TRUE(output);
 
@@ -311,8 +315,8 @@
             });
           )JS"));
 
-    int animation_id = 1;
-    CompositorMutatorInputState state;
+    cc::WorkletAnimationId animation_id = {1, 1};
+    AnimationWorkletInput state;
     state.updated_animations.push_back({animation_id, 5000});
     EXPECT_EQ(state.added_and_updated_animations.size(), 0u);
     EXPECT_EQ(state.updated_animations.size(), 1u);
@@ -359,8 +363,8 @@
             });
           )JS"));
 
-    int animation_id = 1;
-    CompositorMutatorInputState state;
+    cc::WorkletAnimationId animation_id = {1, 1};
+    AnimationWorkletInput state;
     state.added_and_updated_animations.push_back(
         {animation_id, "test", 5000, nullptr});
     EXPECT_EQ(state.added_and_updated_animations.size(), 1u);
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.cc b/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.cc
index d7288904..6a763ab 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.cc
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.cc
@@ -14,9 +14,11 @@
 namespace blink {
 
 AnimationWorkletProxyClientImpl::AnimationWorkletProxyClientImpl(
+    int scope_id,
     base::WeakPtr<CompositorMutatorImpl> mutator,
     scoped_refptr<base::SingleThreadTaskRunner> mutator_runner)
-    : mutator_(std::move(mutator)),
+    : scope_id_(scope_id),
+      mutator_(std::move(mutator)),
       mutator_runner_(std::move(mutator_runner)),
       state_(RunState::kUninitialized) {
   DCHECK(IsMainThread());
@@ -71,29 +73,36 @@
   state_ = RunState::kDisposed;
 }
 
-std::unique_ptr<CompositorMutatorOutputState>
-AnimationWorkletProxyClientImpl::Mutate(
-    const CompositorMutatorInputState& input_state) {
+std::unique_ptr<AnimationWorkletOutput> AnimationWorkletProxyClientImpl::Mutate(
+    std::unique_ptr<AnimationWorkletInput> input) {
+  DCHECK(input);
+#if DCHECK_IS_ON()
+  DCHECK(input->ValidateScope(scope_id_))
+      << "Input has state that does not belong to this global scope: "
+      << scope_id_;
+#endif
+
   if (!global_scope_)
     return nullptr;
 
-  auto output_state = global_scope_->Mutate(input_state);
+  auto output = global_scope_->Mutate(*input);
 
   // TODO(petermayo): https://crbug.com/791280 PostCrossThreadTask to supply
   // this rather than return it.
-  return output_state;
+  return output;
 }
 
 // static
 AnimationWorkletProxyClientImpl* AnimationWorkletProxyClientImpl::FromDocument(
-    Document* document) {
+    Document* document,
+    int scope_id) {
   WebLocalFrameImpl* local_frame =
       WebLocalFrameImpl::FromFrame(document->GetFrame());
   scoped_refptr<base::SingleThreadTaskRunner> mutator_queue;
   base::WeakPtr<CompositorMutatorImpl> mutator =
       local_frame->LocalRootFrameWidget()->EnsureCompositorMutator(
           &mutator_queue);
-  return new AnimationWorkletProxyClientImpl(std::move(mutator),
+  return new AnimationWorkletProxyClientImpl(scope_id, std::move(mutator),
                                              std::move(mutator_queue));
 }
 
diff --git a/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h b/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h
index 275a2b7c..a63b30e 100644
--- a/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h
+++ b/third_party/blink/renderer/modules/animationworklet/animation_worklet_proxy_client_impl.h
@@ -35,6 +35,7 @@
   // This client is hooked to the given |mutatee|, on the given
   // |mutatee_runner|.
   explicit AnimationWorkletProxyClientImpl(
+      int scope_id,
       base::WeakPtr<CompositorMutatorImpl> mutatee,
       scoped_refptr<base::SingleThreadTaskRunner> mutatee_runner);
   void Trace(blink::Visitor*) override;
@@ -45,12 +46,14 @@
 
   // CompositorAnimator:
   // These methods are invoked on the animation worklet thread.
-  std::unique_ptr<CompositorMutatorOutputState> Mutate(
-      const CompositorMutatorInputState&) override;
+  int GetScopeId() const override { return scope_id_; }
+  std::unique_ptr<AnimationWorkletOutput> Mutate(
+      std::unique_ptr<AnimationWorkletInput> input) override;
 
-  static AnimationWorkletProxyClientImpl* FromDocument(Document*);
+  static AnimationWorkletProxyClientImpl* FromDocument(Document*, int scope_id);
 
  private:
+  const int scope_id_;
   base::WeakPtr<CompositorMutatorImpl> mutator_;
   scoped_refptr<base::SingleThreadTaskRunner> mutator_runner_;
 
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
index 473186e..b6f11ab 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation.cc
@@ -14,13 +14,16 @@
 #include "third_party/blink/renderer/core/animation/timing.h"
 #include "third_party/blink/renderer/core/dom/node.h"
 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/modules/animationworklet/window_animation_worklet.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
 namespace {
+
 bool ConvertAnimationEffects(
     const AnimationEffectOrAnimationEffectSequence& effects,
     HeapVector<Member<KeyframeEffect>>& keyframe_effects,
@@ -197,21 +200,26 @@
 }  // namespace
 
 WorkletAnimation* WorkletAnimation::Create(
+    ExecutionContext* context,
     String animator_name,
     const AnimationEffectOrAnimationEffectSequence& effects,
     ExceptionState& exception_state) {
-  return Create(animator_name, effects, DocumentTimelineOrScrollTimeline(),
-                nullptr, exception_state);
+  return Create(context, animator_name, effects,
+                DocumentTimelineOrScrollTimeline(), nullptr, exception_state);
 }
 
 WorkletAnimation* WorkletAnimation::Create(
+    ExecutionContext* context,
+
     String animator_name,
     const AnimationEffectOrAnimationEffectSequence& effects,
     DocumentTimelineOrScrollTimeline timeline,
     ExceptionState& exception_state) {
-  return Create(animator_name, effects, timeline, nullptr, exception_state);
+  return Create(context, animator_name, effects, timeline, nullptr,
+                exception_state);
 }
 WorkletAnimation* WorkletAnimation::Create(
+    ExecutionContext* context,
     String animator_name,
     const AnimationEffectOrAnimationEffectSequence& effects,
     DocumentTimelineOrScrollTimeline timeline,
@@ -240,24 +248,31 @@
     return nullptr;
   }
 
+  AnimationWorklet* worklet =
+      WindowAnimationWorklet::animationWorklet(*context->ExecutingWindow());
+
+  WorkletAnimationId id = worklet->NextWorkletAnimationId();
+
   Document& document = keyframe_effects.at(0)->target()->GetDocument();
   AnimationTimeline* animation_timeline =
       ConvertAnimationTimeline(document, timeline);
 
   WorkletAnimation* animation =
-      new WorkletAnimation(animator_name, document, keyframe_effects,
+      new WorkletAnimation(id, animator_name, document, keyframe_effects,
                            animation_timeline, std::move(options));
 
   return animation;
 }
 
 WorkletAnimation::WorkletAnimation(
+    WorkletAnimationId id,
     const String& animator_name,
     Document& document,
     const HeapVector<Member<KeyframeEffect>>& effects,
     AnimationTimeline* timeline,
     scoped_refptr<SerializedScriptValue> options)
     : sequence_number_(NextSequenceNumber()),
+      id_(id),
       animator_name_(animator_name),
       play_state_(Animation::kIdle),
       document_(document),
@@ -402,7 +417,7 @@
 
   if (!compositor_animation_) {
     compositor_animation_ = CompositorAnimation::CreateWorkletAnimation(
-        animator_name_, ToCompositorScrollTimeline(timeline_),
+        id_, animator_name_, ToCompositorScrollTimeline(timeline_),
         std::move(options_));
     compositor_animation_->SetAnimationDelegate(this);
   }
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation.h b/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
index 66215939..433b9da2 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation.h
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/platform/animation/compositor_animation.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_client.h"
 #include "third_party/blink/renderer/platform/animation/compositor_animation_delegate.h"
+#include "third_party/blink/renderer/platform/graphics/compositor_animators_state.h"
 
 namespace blink {
 
@@ -43,15 +44,18 @@
 
  public:
   static WorkletAnimation* Create(
+      ExecutionContext*,
       String animator_name,
       const AnimationEffectOrAnimationEffectSequence&,
       ExceptionState&);
   static WorkletAnimation* Create(
+      ExecutionContext*,
       String animator_name,
       const AnimationEffectOrAnimationEffectSequence&,
       DocumentTimelineOrScrollTimeline,
       ExceptionState&);
   static WorkletAnimation* Create(
+      ExecutionContext*,
       String animator_name,
       const AnimationEffectOrAnimationEffectSequence&,
       DocumentTimelineOrScrollTimeline,
@@ -106,7 +110,8 @@
   void Trace(blink::Visitor*) override;
 
  private:
-  WorkletAnimation(const String& animator_name,
+  WorkletAnimation(WorkletAnimationId id,
+                   const String& animator_name,
                    Document&,
                    const HeapVector<Member<KeyframeEffect>>&,
                    AnimationTimeline*,
@@ -123,6 +128,8 @@
 
   unsigned sequence_number_;
 
+  WorkletAnimationId id_;
+
   const String animator_name_;
   Animation::AnimationPlayState play_state_;
   // Start time in ms.
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl b/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl
index da6688a..9c8bca9 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation.idl
@@ -12,6 +12,7 @@
                 optional (DocumentTimeline or ScrollTimeline) timeline,
                 optional SerializedScriptValue options),
     RaisesException=Constructor,
+    ConstructorCallWith=ExecutionContext,
     MeasureAs=WorkletAnimationConstructor,
     OriginTrialEnabled=AnimationWorklet
 ] interface WorkletAnimation {
diff --git a/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc b/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
index 58b9a94..5d36d29 100644
--- a/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
+++ b/third_party/blink/renderer/modules/animationworklet/worklet_animation_test.cc
@@ -40,15 +40,17 @@
   return KeyframeEffect::Create(element, CreateEffectModel(), timing);
 }
 
-WorkletAnimation* CreateWorkletAnimation(Element* element) {
+WorkletAnimation* CreateWorkletAnimation(ExecutionContext* context,
+                                         Element* element) {
   AnimationEffectOrAnimationEffectSequence effects;
   AnimationEffect* effect = CreateKeyframeEffect(element);
   effects.SetAnimationEffect(effect);
   DocumentTimelineOrScrollTimeline timeline;
   scoped_refptr<SerializedScriptValue> options;
   DummyExceptionStateForTesting exception_state;
-  return WorkletAnimation::Create("WorkletAnimation", effects, timeline,
-                                  std::move(options), exception_state);
+  return WorkletAnimation::Create(context, "WorkletAnimation", effects,
+                                  timeline, std::move(options),
+                                  exception_state);
 }
 
 }  // namespace
@@ -61,7 +63,7 @@
   void SetUp() override {
     RenderingTest::SetUp();
     element_ = GetDocument().CreateElementForBinding("test");
-    worklet_animation_ = CreateWorkletAnimation(element_);
+    worklet_animation_ = CreateWorkletAnimation(&GetDocument(), element_);
   }
 
   Persistent<Element> element_;
diff --git a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
index 0b6f998..6b54aede 100644
--- a/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
+++ b/third_party/blink/renderer/modules/cache_storage/cache_storage.cc
@@ -17,6 +17,7 @@
 #include "third_party/blink/renderer/core/fetch/response.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/modules/cache_storage/cache_storage_error.h"
+#include "third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 
@@ -210,6 +211,18 @@
 CacheStorage::CacheStorage(ExecutionContext* context,
                            GlobalFetch::ScopedFetcher* fetcher)
     : scoped_fetcher_(fetcher) {
+  // Service workers may already have a CacheStoragePtr provided as an
+  // optimization.
+  if (context->IsServiceWorkerGlobalScope()) {
+    auto* service_worker = ToServiceWorkerGlobalScope(context);
+    mojom::blink::CacheStoragePtrInfo info = service_worker->TakeCacheStorage();
+    if (info) {
+      cache_storage_ptr_ = RevocableInterfacePtr<mojom::blink::CacheStorage>(
+          std::move(info), context->GetInterfaceInvalidator());
+      return;
+    }
+  }
+
   context->GetInterfaceProvider()->GetInterface(
       MakeRequest(&cache_storage_ptr_, context->GetInterfaceInvalidator()));
 }
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index 4367b3b2..5f2d75c 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -77,13 +77,17 @@
     std::unique_ptr<WebServiceWorkerInstalledScriptsManager>
         installed_scripts_manager,
     mojo::ScopedMessagePipeHandle content_settings_handle,
+    mojo::ScopedMessagePipeHandle cache_storage,
     mojo::ScopedMessagePipeHandle interface_provider) {
   return std::make_unique<WebEmbeddedWorkerImpl>(
       std::move(client), std::move(installed_scripts_manager),
       std::make_unique<ServiceWorkerContentSettingsProxy>(
           // Chrome doesn't use interface versioning.
+          // TODO(falken): Is that comment about versioning correct?
           mojom::blink::WorkerContentSettingsProxyPtrInfo(
               std::move(content_settings_handle), 0u)),
+      mojom::blink::CacheStoragePtrInfo(std::move(cache_storage),
+                                        mojom::blink::CacheStorage::Version_),
       service_manager::mojom::blink::InterfaceProviderPtrInfo(
           std::move(interface_provider),
           service_manager::mojom::blink::InterfaceProvider::Version_));
@@ -94,6 +98,7 @@
     std::unique_ptr<WebServiceWorkerInstalledScriptsManager>
         installed_scripts_manager,
     std::unique_ptr<ServiceWorkerContentSettingsProxy> content_settings_client,
+    mojom::blink::CacheStoragePtrInfo cache_storage_info,
     service_manager::mojom::blink::InterfaceProviderPtrInfo
         interface_provider_info)
     : worker_context_client_(std::move(client)),
@@ -101,6 +106,7 @@
       worker_inspector_proxy_(WorkerInspectorProxy::Create()),
       pause_after_download_state_(kDontPauseAfterDownload),
       waiting_for_debugger_state_(kNotWaitingForDebugger),
+      cache_storage_info_(std::move(cache_storage_info)),
       interface_provider_info_(std::move(interface_provider_info)) {
   if (installed_scripts_manager) {
     installed_scripts_manager_ =
@@ -408,7 +414,7 @@
   worker_thread_ = std::make_unique<ServiceWorkerThread>(
       ThreadableLoadingContext::Create(*document),
       ServiceWorkerGlobalScopeProxy::Create(*this, *worker_context_client_),
-      std::move(installed_scripts_manager_));
+      std::move(installed_scripts_manager_), std::move(cache_storage_info_));
 
   // We have a dummy document here for loading but it doesn't really represent
   // the document/frame of associated document(s) for this worker. Here we
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
index e4ee059..1111abb 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
@@ -34,6 +34,7 @@
 #include <memory>
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
+#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
 #include "third_party/blink/public/web/web_embedded_worker.h"
 #include "third_party/blink/public/web/web_embedded_worker_start_data.h"
 #include "third_party/blink/renderer/core/exported/worker_shadow_page.h"
@@ -61,6 +62,7 @@
       std::unique_ptr<WebServiceWorkerContextClient>,
       std::unique_ptr<WebServiceWorkerInstalledScriptsManager>,
       std::unique_ptr<ServiceWorkerContentSettingsProxy>,
+      mojom::blink::CacheStoragePtrInfo,
       service_manager::mojom::blink::InterfaceProviderPtrInfo);
   ~WebEmbeddedWorkerImpl() override;
 
@@ -129,6 +131,8 @@
   // to the same worker.
   base::UnguessableToken devtools_worker_token_;
 
+  mojom::blink::CacheStoragePtrInfo cache_storage_info_;
+
   service_manager::mojom::blink::InterfaceProviderPtrInfo
       interface_provider_info_;
 };
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.cc b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.cc
index 44b0410..faf1659 100644
--- a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.cc
@@ -75,6 +75,7 @@
 ServiceWorkerGlobalScope* ServiceWorkerGlobalScope::Create(
     ServiceWorkerThread* thread,
     std::unique_ptr<GlobalScopeCreationParams> creation_params,
+    mojom::blink::CacheStoragePtrInfo cache_storage_info,
     base::TimeTicks time_origin) {
   // If the script is being loaded via script streaming, the script is not yet
   // loaded.
@@ -88,14 +89,17 @@
     DCHECK(creation_params->origin_trial_tokens->IsEmpty());
   }
   return new ServiceWorkerGlobalScope(std::move(creation_params), thread,
+                                      std::move(cache_storage_info),
                                       time_origin);
 }
 
 ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(
     std::unique_ptr<GlobalScopeCreationParams> creation_params,
     ServiceWorkerThread* thread,
+    mojom::blink::CacheStoragePtrInfo cache_storage_info,
     base::TimeTicks time_origin)
-    : WorkerGlobalScope(std::move(creation_params), thread, time_origin) {}
+    : WorkerGlobalScope(std::move(creation_params), thread, time_origin),
+      cache_storage_info_(std::move(cache_storage_info)) {}
 
 ServiceWorkerGlobalScope::~ServiceWorkerGlobalScope() = default;
 
@@ -388,4 +392,8 @@
   }
 }
 
+mojom::blink::CacheStoragePtrInfo ServiceWorkerGlobalScope::TakeCacheStorage() {
+  return std::move(cache_storage_info_);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.h b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.h
index 4b9e84ad..cde529f 100644
--- a/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_global_scope.h
@@ -31,6 +31,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICEWORKERS_SERVICE_WORKER_GLOBAL_SCOPE_H_
 
 #include <memory>
+#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/serviceworker/web_service_worker_registration.h"
 #include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
@@ -60,6 +61,7 @@
   static ServiceWorkerGlobalScope* Create(
       ServiceWorkerThread*,
       std::unique_ptr<GlobalScopeCreationParams>,
+      mojom::blink::CacheStoragePtrInfo,
       base::TimeTicks time_origin);
 
   ~ServiceWorkerGlobalScope() override;
@@ -117,6 +119,8 @@
   void CountCacheStorageInstalledScript(uint64_t script_size,
                                         uint64_t script_metadata_size);
 
+  mojom::blink::CacheStoragePtrInfo TakeCacheStorage();
+
   DEFINE_ATTRIBUTE_EVENT_LISTENER(install);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(activate);
   DEFINE_ATTRIBUTE_EVENT_LISTENER(fetch);
@@ -134,6 +138,7 @@
  private:
   ServiceWorkerGlobalScope(std::unique_ptr<GlobalScopeCreationParams>,
                            ServiceWorkerThread*,
+                           mojom::blink::CacheStoragePtrInfo,
                            base::TimeTicks time_origin);
   void importScripts(const Vector<String>& urls, ExceptionState&) override;
   SingleCachedMetadataHandler* CreateWorkerScriptCachedMetadataHandler(
@@ -158,6 +163,11 @@
 
   bool evaluate_script_ready_ = false;
   base::OnceClosure evaluate_script_;
+
+  // May be provided in the constructor as an optimization so InterfaceProvider
+  // doesn't need to be used. Taken at the initial call to
+  // ServiceWorkerGlobalScope#caches.
+  mojom::blink::CacheStoragePtrInfo cache_storage_info_;
 };
 
 DEFINE_TYPE_CASTS(ServiceWorkerGlobalScope,
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_thread.cc b/third_party/blink/renderer/modules/serviceworkers/service_worker_thread.cc
index e8b9c738..92444694f 100644
--- a/third_party/blink/renderer/modules/serviceworkers/service_worker_thread.cc
+++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_thread.cc
@@ -44,12 +44,14 @@
     ThreadableLoadingContext* loading_context,
     ServiceWorkerGlobalScopeProxy* global_scope_proxy,
     std::unique_ptr<ServiceWorkerInstalledScriptsManager>
-        installed_scripts_manager)
+        installed_scripts_manager,
+    mojom::blink::CacheStoragePtrInfo cache_storage_info)
     : WorkerThread(loading_context, *global_scope_proxy),
       global_scope_proxy_(global_scope_proxy),
       worker_backing_thread_(WorkerBackingThread::Create(
           WebThreadCreationParams(GetThreadType()))),
-      installed_scripts_manager_(std::move(installed_scripts_manager)) {}
+      installed_scripts_manager_(std::move(installed_scripts_manager)),
+      cache_storage_info_(std::move(cache_storage_info)) {}
 
 ServiceWorkerThread::~ServiceWorkerThread() {
   global_scope_proxy_->Detach();
@@ -71,6 +73,7 @@
 WorkerOrWorkletGlobalScope* ServiceWorkerThread::CreateWorkerGlobalScope(
     std::unique_ptr<GlobalScopeCreationParams> creation_params) {
   return ServiceWorkerGlobalScope::Create(this, std::move(creation_params),
+                                          std::move(cache_storage_info_),
                                           time_origin_);
 }
 
diff --git a/third_party/blink/renderer/modules/serviceworkers/service_worker_thread.h b/third_party/blink/renderer/modules/serviceworkers/service_worker_thread.h
index 8ac5a94..8838c787 100644
--- a/third_party/blink/renderer/modules/serviceworkers/service_worker_thread.h
+++ b/third_party/blink/renderer/modules/serviceworkers/service_worker_thread.h
@@ -31,6 +31,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICEWORKERS_SERVICE_WORKER_THREAD_H_
 
 #include <memory>
+#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom-blink.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
@@ -49,7 +50,8 @@
   // Persistent.
   ServiceWorkerThread(ThreadableLoadingContext*,
                       ServiceWorkerGlobalScopeProxy*,
-                      std::unique_ptr<ServiceWorkerInstalledScriptsManager>);
+                      std::unique_ptr<ServiceWorkerInstalledScriptsManager>,
+                      mojom::blink::CacheStoragePtrInfo cache_storage_info);
   ~ServiceWorkerThread() override;
 
   WorkerBackingThread& GetWorkerBackingThread() override {
@@ -71,6 +73,7 @@
   std::unique_ptr<WorkerBackingThread> worker_backing_thread_;
   std::unique_ptr<ServiceWorkerInstalledScriptsManager>
       installed_scripts_manager_;
+  mojom::blink::CacheStoragePtrInfo cache_storage_info_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/serviceworkers/web_embedded_worker_impl_test.cc b/third_party/blink/renderer/modules/serviceworkers/web_embedded_worker_impl_test.cc
index 07a62251..bd1a89d 100644
--- a/third_party/blink/renderer/modules/serviceworkers/web_embedded_worker_impl_test.cc
+++ b/third_party/blink/renderer/modules/serviceworkers/web_embedded_worker_impl_test.cc
@@ -126,7 +126,8 @@
     mock_installed_scripts_manager_ = installed_scripts_manager.get();
     worker_ = WebEmbeddedWorker::Create(
         std::move(client), std::move(installed_scripts_manager),
-        mojo::ScopedMessagePipeHandle(), mojo::ScopedMessagePipeHandle());
+        mojo::ScopedMessagePipeHandle(), mojo::ScopedMessagePipeHandle(),
+        mojo::ScopedMessagePipeHandle());
 
     WebURL script_url = URLTestHelpers::ToKURL("https://www.example.com/sw.js");
     WebURLResponse response;
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index e0a5e5f..4fc58b3 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -2051,6 +2051,15 @@
   }
 }
 
+test("blink_fuzzer_unittests") {
+  deps = [
+    "//third_party/blink/renderer/platform:test_support",
+  ]
+  sources = [
+    "testing/run_all_tests.cc",
+  ]
+}
+
 # This source set is used for fuzzers that need an environment similar to unit
 # tests.
 jumbo_source_set("blink_fuzzer_test_support") {
@@ -2200,6 +2209,7 @@
     "graphics/canvas_color_params_test.cc",
     "graphics/canvas_resource_test.cc",
     "graphics/color_correction_test_utils.cc",
+    "graphics/compositor_mutator_impl_test.cc",
     "graphics/deferred_image_decoder_test.cc",
     "graphics/gpu/drawing_buffer_software_rendering_test.cc",
     "graphics/graphics_layer_test.cc",
diff --git a/third_party/blink/renderer/platform/animation/compositor_animation.cc b/third_party/blink/renderer/platform/animation/compositor_animation.cc
index c7e57b9..79a0b4c 100644
--- a/third_party/blink/renderer/platform/animation/compositor_animation.cc
+++ b/third_party/blink/renderer/platform/animation/compositor_animation.cc
@@ -20,12 +20,12 @@
 
 std::unique_ptr<CompositorAnimation>
 CompositorAnimation::CreateWorkletAnimation(
+    cc::WorkletAnimationId worklet_animation_id,
     const String& name,
     std::unique_ptr<CompositorScrollTimeline> scroll_timeline,
     std::unique_ptr<cc::AnimationOptions> options) {
   return std::make_unique<CompositorAnimation>(cc::WorkletAnimation::Create(
-      cc::AnimationIdProvider::NextAnimationId(),
-      std::string(name.Ascii().data(), name.length()),
+      worklet_animation_id, std::string(name.Ascii().data(), name.length()),
       std::move(scroll_timeline), std::move(options)));
 }
 
diff --git a/third_party/blink/renderer/platform/animation/compositor_animation.h b/third_party/blink/renderer/platform/animation/compositor_animation.h
index 779f6dd..1746ef4 100644
--- a/third_party/blink/renderer/platform/animation/compositor_animation.h
+++ b/third_party/blink/renderer/platform/animation/compositor_animation.h
@@ -34,6 +34,7 @@
  public:
   static std::unique_ptr<CompositorAnimation> Create();
   static std::unique_ptr<CompositorAnimation> CreateWorkletAnimation(
+      cc::WorkletAnimationId,
       const String& name,
       std::unique_ptr<CompositorScrollTimeline>,
       std::unique_ptr<cc::AnimationOptions>);
diff --git a/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h b/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
index 81ae140..edb940c3 100644
--- a/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
+++ b/third_party/blink/renderer/platform/bindings/dom_wrapper_world.h
@@ -39,6 +39,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "v8/include/v8.h"
 
@@ -46,6 +47,7 @@
 
 class DOMDataStore;
 class DOMObjectHolderBase;
+class ScriptWrappable;
 
 // This class represent a collection of DOM wrappers for a specific world. This
 // is identified by a world id that is a per-thread global identifier (see
diff --git a/third_party/blink/renderer/platform/bindings/script_state.cc b/third_party/blink/renderer/platform/bindings/script_state.cc
index 9463657..88b2dac 100644
--- a/third_party/blink/renderer/platform/bindings/script_state.cc
+++ b/third_party/blink/renderer/platform/bindings/script_state.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/instance_counters.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/bindings/script_state.h b/third_party/blink/renderer/platform/bindings/script_state.h
index 87187ff..dccda20 100644
--- a/third_party/blink/renderer/platform/bindings/script_state.h
+++ b/third_party/blink/renderer/platform/bindings/script_state.h
@@ -7,8 +7,9 @@
 
 #include <memory>
 
+#include "gin/public/context_holder.h"
+#include "gin/public/gin_embedders.h"
 #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
-#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "v8/include/v8.h"
@@ -17,6 +18,7 @@
 
 class DOMWrapperWorld;
 class ScriptValue;
+class V8PerContextData;
 
 // ScriptState is an abstraction class that holds all information about script
 // exectuion (e.g., v8::Isolate, v8::Context, DOMWrapperWorld, ExecutionContext
@@ -163,6 +165,10 @@
   // disposePerContextData() once you no longer need V8PerContextData.
   // Otherwise, the v8::Context will leak.
   std::unique_ptr<V8PerContextData> per_context_data_;
+
+  static constexpr int kV8ContextPerContextDataIndex = static_cast<int>(
+      gin::kPerContextDataStartIndex +  // NOLINT(readability/enum_casing)
+      gin::kEmbedderBlink);             // NOLINT(readability/enum_casing)
 };
 
 // ScriptStateProtectingContext keeps the context associated with the
diff --git a/third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.cc b/third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.cc
index 39c7b4c..5a2f20c 100644
--- a/third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.cc
+++ b/third_party/blink/renderer/platform/bindings/v8_dom_activity_logger.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 #include "third_party/blink/renderer/platform/bindings/v8_binding.h"
+#include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_context_data.h b/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
index 9ecf12d..e75d8bf 100644
--- a/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
+++ b/third_party/blink/renderer/platform/bindings/v8_per_context_data.h
@@ -53,12 +53,6 @@
 class V8DOMActivityLogger;
 class V8PerContextData;
 
-enum V8ContextEmbedderDataField {
-  kV8ContextPerContextDataIndex = static_cast<int>(
-      gin::kPerContextDataStartIndex +  // NOLINT(readability/enum_casing)
-      gin::kEmbedderBlink),             // NOLINT(readability/enum_casing)
-};
-
 // Used to hold data that is associated with a single v8::Context object, and
 // has a 1:1 relationship with v8::Context.
 class PLATFORM_EXPORT V8PerContextData final {
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
index 5b22a05..6f207a20 100644
--- a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
+++ b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h"
+#include "third_party/blink/renderer/platform/bindings/v8_global_value_map.h"
 #include "third_party/blink/renderer/platform/bindings/wrapper_type_info.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
diff --git a/third_party/blink/renderer/platform/graphics/compositor_animator.h b/third_party/blink/renderer/platform/graphics/compositor_animator.h
index f23806bf..5c5bbf9 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_animator.h
+++ b/third_party/blink/renderer/platform/graphics/compositor_animator.h
@@ -13,9 +13,12 @@
 
 class PLATFORM_EXPORT CompositorAnimator : public GarbageCollectedMixin {
  public:
+  virtual ~CompositorAnimator() = default;
+
+  virtual int GetScopeId() const = 0;
   // Runs the animation frame callback.
-  virtual std::unique_ptr<CompositorMutatorOutputState> Mutate(
-      const CompositorMutatorInputState&) = 0;
+  virtual std::unique_ptr<AnimationWorkletOutput> Mutate(
+      std::unique_ptr<AnimationWorkletInput>) = 0;
   void Trace(blink::Visitor* visitor) override {}
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/compositor_animators_state.h b/third_party/blink/renderer/platform/graphics/compositor_animators_state.h
index 549a1ae..42e1b7f 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_animators_state.h
+++ b/third_party/blink/renderer/platform/graphics/compositor_animators_state.h
@@ -9,9 +9,12 @@
 
 namespace blink {
 
+using AnimationWorkletInput = cc::AnimationWorkletInput;
+using AnimationWorkletOutput = cc::AnimationWorkletOutput;
 using CompositorMutatorInputState = cc::MutatorInputState;
 
 using CompositorMutatorOutputState = cc::MutatorOutputState;
+using WorkletAnimationId = cc::WorkletAnimationId;
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h b/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h
index 77e0819d..827aba8 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h
+++ b/third_party/blink/renderer/platform/graphics/compositor_mutator_client.h
@@ -18,7 +18,7 @@
   explicit CompositorMutatorClient(std::unique_ptr<CompositorMutatorImpl>);
   ~CompositorMutatorClient() override;
 
-  void SetMutationUpdate(std::unique_ptr<cc::MutatorOutputState>);
+  virtual void SetMutationUpdate(std::unique_ptr<cc::MutatorOutputState>);
 
   // cc::LayerTreeMutator
   void SetClient(cc::LayerTreeMutatorClient*) override;
diff --git a/third_party/blink/renderer/platform/graphics/compositor_mutator_impl.cc b/third_party/blink/renderer/platform/graphics/compositor_mutator_impl.cc
index cc73c3c..0609f3d3 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_mutator_impl.cc
+++ b/third_party/blink/renderer/platform/graphics/compositor_mutator_impl.cc
@@ -59,8 +59,13 @@
           [](const CompositorAnimators* animators,
              std::unique_ptr<CompositorMutatorInputState> state,
              std::unique_ptr<AutoSignal> completion, Outputs* output) {
-            for (CompositorAnimator* animator : *animators)
-              output->push_back(animator->Mutate(*state));
+
+            for (CompositorAnimator* animator : *animators) {
+              std::unique_ptr<AnimationWorkletInput> worklet_input =
+                  state->TakeWorkletState(animator->GetScopeId());
+              if (worklet_input)
+                output->push_back(animator->Mutate(std::move(worklet_input)));
+            }
           },
           CrossThreadUnretained(&animators_), WTF::Passed(std::move(state)),
           WTF::Passed(std::make_unique<AutoSignal>(&done)),
diff --git a/third_party/blink/renderer/platform/graphics/compositor_mutator_impl_test.cc b/third_party/blink/renderer/platform/graphics/compositor_mutator_impl_test.cc
new file mode 100644
index 0000000..fb1d1d7
--- /dev/null
+++ b/third_party/blink/renderer/platform/graphics/compositor_mutator_impl_test.cc
@@ -0,0 +1,152 @@
+// 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/platform/graphics/compositor_mutator_impl.h"
+
+#include "base/single_thread_task_runner.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_thread.h"
+#include "third_party/blink/public/platform/web_thread_type.h"
+#include "third_party/blink/renderer/platform/graphics/compositor_animator.h"
+#include "third_party/blink/renderer/platform/graphics/compositor_mutator_client.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
+
+#include <memory>
+
+using ::testing::_;
+using ::testing::Mock;
+using ::testing::StrictMock;
+using ::testing::Return;
+using ::testing::Truly;
+
+// This test uses actual threads since mutator logic requires it. This means we
+// have dependency on Blink platform to create threads.
+
+namespace blink {
+namespace {
+
+std::unique_ptr<WebThread> CreateThread(const char* name) {
+  return Platform::Current()->CreateThread(
+      WebThreadCreationParams(WebThreadType::kTestThread)
+          .SetThreadNameForTest(name));
+}
+
+class MockCompositorAnimator
+    : public GarbageCollectedFinalized<MockCompositorAnimator>,
+      public CompositorAnimator {
+  USING_GARBAGE_COLLECTED_MIXIN(MockCompositorAnimator);
+
+ public:
+  MockCompositorAnimator(
+      scoped_refptr<base::SingleThreadTaskRunner> expected_runner)
+      : expected_runner_(expected_runner) {}
+
+  ~MockCompositorAnimator() override {}
+
+  std::unique_ptr<AnimationWorkletOutput> Mutate(
+      std::unique_ptr<AnimationWorkletInput> input) override {
+    return MutateRef(*input);
+  }
+
+  MOCK_CONST_METHOD0(GetScopeId, int());
+  MOCK_METHOD1(
+      MutateRef,
+      std::unique_ptr<AnimationWorkletOutput>(const AnimationWorkletInput&));
+
+  scoped_refptr<base::SingleThreadTaskRunner> expected_runner_;
+};
+
+class MockCompositorMutatorClient : public CompositorMutatorClient {
+ public:
+  MockCompositorMutatorClient(std::unique_ptr<CompositorMutatorImpl> mutator)
+      : CompositorMutatorClient(std::move(mutator)) {}
+  ~MockCompositorMutatorClient() override {}
+  // gmock cannot mock methods with move-only args so we forward it to ourself.
+  void SetMutationUpdate(
+      std::unique_ptr<cc::MutatorOutputState> output_state) override {
+    SetMutationUpdateRef(output_state.get());
+  }
+
+  MOCK_METHOD1(SetMutationUpdateRef,
+               void(cc::MutatorOutputState* output_state));
+};
+
+class CompositorMutatorImplTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    auto mutator = std::make_unique<CompositorMutatorImpl>();
+    mutator_ = mutator.get();
+    client_ =
+        std::make_unique<::testing::StrictMock<MockCompositorMutatorClient>>(
+            std::move(mutator));
+  }
+
+  void TearDown() override { mutator_ = nullptr; }
+
+  std::unique_ptr<::testing::StrictMock<MockCompositorMutatorClient>> client_;
+  CompositorMutatorImpl* mutator_;
+};
+
+bool OnlyIncludesAnimation1(const AnimationWorkletInput& in) {
+  return in.added_and_updated_animations.size() == 1 &&
+         in.added_and_updated_animations[0].worklet_animation_id.animation_id ==
+             1;
+}
+
+TEST_F(CompositorMutatorImplTest,
+       RegisteredAnimatorShouldOnlyReceiveInputForItself) {
+  std::unique_ptr<WebThread> first_thread = CreateThread("FirstThread");
+  MockCompositorAnimator* first_animator =
+      new ::testing::StrictMock<MockCompositorAnimator>(
+          first_thread->GetTaskRunner());
+
+  mutator_->RegisterCompositorAnimator(first_animator,
+                                       first_thread->GetTaskRunner());
+
+  EXPECT_CALL(*first_animator, GetScopeId()).Times(1).WillOnce(Return(11));
+  EXPECT_CALL(*first_animator, MutateRef(Truly(OnlyIncludesAnimation1)))
+      .Times(1);
+  EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(1);
+
+  AnimationWorkletInput::AddAndUpdateState state1{
+      {11, 1}, "test1", 5000, nullptr};
+
+  AnimationWorkletInput::AddAndUpdateState state2{
+      {22, 2}, "test2", 5000, nullptr};
+
+  auto input = std::make_unique<CompositorMutatorInputState>();
+  input->Add(std::move(state1));
+  input->Add(std::move(state2));
+
+  mutator_->Mutate(std::move(input));
+}
+
+TEST_F(CompositorMutatorImplTest, AnimatorShouldNotBeMutatedWhenNoInput) {
+  std::unique_ptr<WebThread> first_thread = CreateThread("FirstThread");
+  MockCompositorAnimator* first_animator =
+      new ::testing::StrictMock<MockCompositorAnimator>(
+          first_thread->GetTaskRunner());
+
+  mutator_->RegisterCompositorAnimator(first_animator,
+                                       first_thread->GetTaskRunner());
+
+  EXPECT_CALL(*first_animator, GetScopeId()).Times(1).WillOnce(Return(11));
+  EXPECT_CALL(*first_animator, MutateRef(_)).Times(0);
+  EXPECT_CALL(*client_, SetMutationUpdateRef(_)).Times(0);
+
+  AnimationWorkletInput::AddAndUpdateState state2{
+      {22, 2}, "test2", 5000, nullptr};
+
+  auto input = std::make_unique<CompositorMutatorInputState>();
+  input->Add(std::move(state2));
+
+  mutator_->Mutate(std::move(input));
+}
+
+}  // namespace
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc
index 2487c4e5..652088b 100644
--- a/third_party/blink/renderer/platform/heap/thread_state.cc
+++ b/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -527,9 +527,16 @@
 
   if ((gc_type == BlinkGC::kV8MajorGC && ShouldForceMemoryPressureGC()) ||
       ShouldScheduleV8FollowupGC()) {
-    VLOG(2) << "[state:" << this << "] "
-            << "ScheduleV8FollowupGCIfNeeded: Scheduled precise GC";
-    SchedulePreciseGC();
+    if (RuntimeEnabledFeatures::HeapIncrementalMarkingEnabled()) {
+      VLOG(2) << "[state:" << this << "] "
+              << "ScheduleV8FollowupGCIfNeeded: Scheduled incremental v8 "
+                 "followup GC";
+      ScheduleIncrementalGC(BlinkGC::GCReason::kIncrementalV8FollowupGC);
+    } else {
+      VLOG(2) << "[state:" << this << "] "
+              << "ScheduleV8FollowupGCIfNeeded: Scheduled precise GC";
+      SchedulePreciseGC();
+    }
     return;
   }
   if (gc_type == BlinkGC::kV8MajorGC && ShouldScheduleIdleGC()) {
diff --git a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
index 1969cff4..961f89d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.cc
@@ -6,11 +6,11 @@
 
 #include "base/macros.h"
 #include "third_party/blink/public/common/client_hints/client_hints.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 #include "third_party/blink/renderer/platform/network/http_parsers.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 
 namespace blink {
 
@@ -98,42 +98,25 @@
   }
 }
 
-// static
-void ClientHintsPreferences::UpdatePersistentHintsFromHeaders(
-    const ResourceResponse& response,
-    Context* context,
-    WebEnabledClientHints& enabled_hints,
-    TimeDelta* persist_duration) {
-  *persist_duration = base::TimeDelta();
-
-  if (response.WasCached())
+void ClientHintsPreferences::UpdateFromAcceptClientHintsLifetimeHeader(
+    const String& header_value,
+    const KURL& url,
+    Context* context) {
+  if (header_value.IsEmpty())
     return;
 
-  String accept_ch_header_value =
-      response.HttpHeaderField(HTTPNames::Accept_CH);
-  String accept_ch_lifetime_header_value =
-      response.HttpHeaderField(HTTPNames::Accept_CH_Lifetime);
-
-  if (accept_ch_header_value.IsEmpty() ||
-      accept_ch_lifetime_header_value.IsEmpty()) {
-    return;
-  }
-
-  const KURL url = response.Url();
+  // Client hints should be allowed only on secure URLs.
   if (!IsClientHintsAllowed(url))
     return;
 
   bool conversion_ok = false;
-  int64_t persist_duration_seconds =
-      accept_ch_lifetime_header_value.ToInt64Strict(&conversion_ok);
+  int64_t persist_duration_seconds = header_value.ToInt64Strict(&conversion_ok);
   if (!conversion_ok || persist_duration_seconds <= 0)
     return;
 
-  *persist_duration = TimeDelta::FromSeconds(persist_duration_seconds);
+  persist_duration_ = TimeDelta::FromSeconds(persist_duration_seconds);
   if (context)
     context->CountPersistentClientHintHeaders();
-
-  ParseAcceptChHeader(accept_ch_header_value, enabled_hints);
 }
 
 // static
@@ -143,4 +126,12 @@
           SecurityOrigin::Create(url)->IsLocalhost());
 }
 
+WebEnabledClientHints ClientHintsPreferences::GetWebEnabledClientHints() const {
+  return enabled_hints_;
+}
+
+base::TimeDelta ClientHintsPreferences::GetPersistDuration() const {
+  return persist_duration_;
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h
index 6900745..270f8bfd 100644
--- a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h
+++ b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h
@@ -14,7 +14,6 @@
 namespace blink {
 
 class KURL;
-class ResourceResponse;
 
 // TODO (tbansal): Remove PLATFORM_EXPORT, and pass WebClientHintsType
 // everywhere.
@@ -50,26 +49,25 @@
     enabled_hints_.SetIsEnabled(type, true);
   }
 
-  // Parses the client hints headers, and populates |enabled_hints| with the
-  // client hint preferences that should be persisted for |persist_duration|.
-  // |persist_duration| should be non-null.
-  // If there are no client hints that need to be persisted,
-  // |persist_duration| is not set, otherwise it is set to the duration for
-  // which the client hint preferences should be persisted.
-  // UpdatePersistentHintsFromHeaders may be called for all responses
-  // received (including subresources). |context| may be null.
-  static void UpdatePersistentHintsFromHeaders(
-      const ResourceResponse&,
-      Context*,
-      WebEnabledClientHints& enabled_hints,
-      TimeDelta* persist_duration);
+  // Parses the accept-ch-lifetime header, and populates |this| with the client
+  // hints persistence duration. |url| is the URL of the resource whose response
+  // included the |header_value|. |context| may be null. If client hints are not
+  // allowed for |url|, then |this| would not be updated.
+  void UpdateFromAcceptClientHintsLifetimeHeader(const String& header_value,
+                                                 const KURL& url,
+                                                 Context* context);
 
   // Returns true if client hints are allowed for the provided KURL. Client
   // hints are allowed only on HTTP URLs that belong to secure contexts.
   static bool IsClientHintsAllowed(const KURL&);
 
+  WebEnabledClientHints GetWebEnabledClientHints() const;
+
+  base::TimeDelta GetPersistDuration() const;
+
  private:
   WebEnabledClientHints enabled_hints_;
+  base::TimeDelta persist_duration_;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc
index 2eccbff..67dc2fa 100644
--- a/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/client_hints_preferences_test.cc
@@ -82,6 +82,58 @@
   }
 }
 
+// Verify that the set of enabled client hints is updated every time Update*()
+// methods are called.
+TEST_F(ClientHintsPreferencesTest, SecureEnabledTypesAreUpdated) {
+  ClientHintsPreferences preferences;
+  const KURL kurl(String::FromUTF8("https://www.google.com/"));
+  preferences.UpdateFromAcceptClientHintsHeader("rtt, downlink", kurl, nullptr);
+
+  EXPECT_EQ(base::TimeDelta(), preferences.GetPersistDuration());
+  EXPECT_FALSE(
+      preferences.ShouldSend(mojom::WebClientHintsType::kResourceWidth));
+  EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kDpr));
+  EXPECT_FALSE(
+      preferences.ShouldSend(mojom::WebClientHintsType::kViewportWidth));
+  EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kRtt));
+  EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kDownlink));
+  EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kEct));
+
+  // Calling UpdateFromAcceptClientHintsHeader with empty header should have
+  // no impact on client hint preferences.
+  preferences.UpdateFromAcceptClientHintsHeader("", kurl, nullptr);
+  EXPECT_EQ(base::TimeDelta(), preferences.GetPersistDuration());
+  EXPECT_FALSE(
+      preferences.ShouldSend(mojom::WebClientHintsType::kResourceWidth));
+  EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kRtt));
+  EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kDownlink));
+  EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kEct));
+
+  // Calling UpdateFromAcceptClientHintsHeader with an invalid header should
+  // have no impact on client hint preferences.
+  preferences.UpdateFromAcceptClientHintsHeader("foobar", kurl, nullptr);
+  EXPECT_EQ(base::TimeDelta(), preferences.GetPersistDuration());
+  EXPECT_FALSE(
+      preferences.ShouldSend(mojom::WebClientHintsType::kResourceWidth));
+  EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kRtt));
+  EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kDownlink));
+  EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kEct));
+
+  // Calling UpdateFromAcceptClientHintsHeader with "width" header should
+  // have no impact on already enabled client hint preferences.
+  preferences.UpdateFromAcceptClientHintsHeader("width", kurl, nullptr);
+  EXPECT_EQ(base::TimeDelta(), preferences.GetPersistDuration());
+  EXPECT_TRUE(
+      preferences.ShouldSend(mojom::WebClientHintsType::kResourceWidth));
+  EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kRtt));
+  EXPECT_TRUE(preferences.ShouldSend(mojom::WebClientHintsType::kDownlink));
+  EXPECT_FALSE(preferences.ShouldSend(mojom::WebClientHintsType::kEct));
+
+  preferences.UpdateFromAcceptClientHintsLifetimeHeader("1000", kurl, nullptr);
+  EXPECT_EQ(base::TimeDelta::FromSeconds(1000),
+            preferences.GetPersistDuration());
+}
+
 TEST_F(ClientHintsPreferencesTest, Insecure) {
   for (const auto& use_secure_url : {false, true}) {
     ClientHintsPreferences preferences;
@@ -94,60 +146,83 @@
   }
 }
 
-TEST_F(ClientHintsPreferencesTest, PersistentHints) {
+// Verify that the client hints header and the lifetime header is parsed
+// correctly.
+TEST_F(ClientHintsPreferencesTest, ParseHeaders) {
   struct TestCase {
     const char* accept_ch_header_value;
     const char* accept_lifetime_header_value;
     int64_t expect_persist_duration_seconds;
+    bool expect_device_memory;
+    bool expect_width;
+    bool expect_dpr;
+    bool expect_viewport_width;
+    bool expect_rtt;
+    bool expect_downlink;
+    bool expect_ect;
   } test_cases[] = {
-      {"width, dpr, viewportWidth", "", 0},
-      {"width, dpr, viewportWidth", "-1000", 0},
-      {"width, dpr, viewportWidth", "1000s", 0},
-      {"width, dpr, viewportWidth", "1000.5", 0},
-      {"width, dpr, rtt, downlink, ect", "1000", 1000},
+      {"width, dpr, viewportWidth", "", 0, false, true, true, false, false,
+       false, false},
+      {"width, dpr, viewportWidth", "-1000", 0, false, true, true, false, false,
+       false, false},
+      {"width, dpr, viewportWidth", "1000s", 0, false, true, true, false, false,
+       false, false},
+      {"width, dpr, viewportWidth", "1000.5", 0, false, true, true, false,
+       false, false, false},
+      {"width, dpr, rtt, downlink, ect", "1000", 1000, false, true, true, false,
+       true, true, true},
+      {"device-memory", "-1000", 0, true, false, false, false, false, false,
+       false},
+      {"dpr rtt", "1000", 1000, false, false, false, false, false, false,
+       false},
   };
 
   for (const auto& test : test_cases) {
-    WebEnabledClientHints enabled_types;
-    TimeDelta persist_duration;
+    ClientHintsPreferences preferences;
+    WebEnabledClientHints enabled_types =
+        preferences.GetWebEnabledClientHints();
+    EXPECT_FALSE(
+        enabled_types.IsEnabled(mojom::WebClientHintsType::kDeviceMemory));
+    EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kDpr));
+    EXPECT_FALSE(
+        enabled_types.IsEnabled(mojom::WebClientHintsType::kResourceWidth));
+    EXPECT_FALSE(
+        enabled_types.IsEnabled(mojom::WebClientHintsType::kViewportWidth));
+    EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kRtt));
+    EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kDownlink));
+    EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kEct));
+    TimeDelta persist_duration = preferences.GetPersistDuration();
+    EXPECT_EQ(base::TimeDelta(), persist_duration);
 
     const KURL kurl(String::FromUTF8("https://www.google.com/"));
+    preferences.UpdateFromAcceptClientHintsHeader(test.accept_ch_header_value,
+                                                  kurl, nullptr);
+    preferences.UpdateFromAcceptClientHintsLifetimeHeader(
+        test.accept_lifetime_header_value, kurl, nullptr);
 
-    ResourceResponse response(kurl);
-    response.SetHTTPHeaderField(HTTPNames::Accept_CH,
-                                test.accept_ch_header_value);
-    response.SetHTTPHeaderField(HTTPNames::Accept_CH_Lifetime,
-                                test.accept_lifetime_header_value);
+    enabled_types = preferences.GetWebEnabledClientHints();
+    persist_duration = preferences.GetPersistDuration();
 
-    ClientHintsPreferences::UpdatePersistentHintsFromHeaders(
-        response, nullptr, enabled_types, &persist_duration);
     EXPECT_EQ(test.expect_persist_duration_seconds,
               persist_duration.InSeconds());
-    if (test.expect_persist_duration_seconds > 0) {
-      EXPECT_FALSE(
-          enabled_types.IsEnabled(mojom::WebClientHintsType::kDeviceMemory));
-      EXPECT_TRUE(enabled_types.IsEnabled(mojom::WebClientHintsType::kDpr));
-      EXPECT_TRUE(
-          enabled_types.IsEnabled(mojom::WebClientHintsType::kResourceWidth));
-      EXPECT_FALSE(
-          enabled_types.IsEnabled(mojom::WebClientHintsType::kViewportWidth));
-      EXPECT_TRUE(enabled_types.IsEnabled(mojom::WebClientHintsType::kRtt));
-      EXPECT_TRUE(
-          enabled_types.IsEnabled(mojom::WebClientHintsType::kDownlink));
-      EXPECT_TRUE(enabled_types.IsEnabled(mojom::WebClientHintsType::kEct));
-    } else {
-      EXPECT_FALSE(
-          enabled_types.IsEnabled(mojom::WebClientHintsType::kDeviceMemory));
-      EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kDpr));
-      EXPECT_FALSE(
-          enabled_types.IsEnabled(mojom::WebClientHintsType::kResourceWidth));
-      EXPECT_FALSE(
-          enabled_types.IsEnabled(mojom::WebClientHintsType::kViewportWidth));
-      EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kRtt));
-      EXPECT_FALSE(
-          enabled_types.IsEnabled(mojom::WebClientHintsType::kDownlink));
-      EXPECT_FALSE(enabled_types.IsEnabled(mojom::WebClientHintsType::kEct));
-    }
+
+    EXPECT_EQ(
+        test.expect_device_memory,
+        enabled_types.IsEnabled(mojom::WebClientHintsType::kDeviceMemory));
+    EXPECT_EQ(test.expect_dpr,
+              enabled_types.IsEnabled(mojom::WebClientHintsType::kDpr));
+    EXPECT_EQ(
+        test.expect_width,
+        enabled_types.IsEnabled(mojom::WebClientHintsType::kResourceWidth));
+    EXPECT_EQ(
+        test.expect_viewport_width,
+        enabled_types.IsEnabled(mojom::WebClientHintsType::kViewportWidth));
+    EXPECT_EQ(test.expect_rtt,
+              enabled_types.IsEnabled(mojom::WebClientHintsType::kRtt));
+    EXPECT_EQ(test.expect_downlink,
+              enabled_types.IsEnabled(mojom::WebClientHintsType::kDownlink));
+    EXPECT_EQ(test.expect_ect,
+              enabled_types.IsEnabled(mojom::WebClientHintsType::kEct));
   }
 }
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 998e3c6..0c9d89a0 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -286,6 +286,10 @@
       status: "experimental",
     },
     {
+      name: "CSSLogical",
+      status: "experimental",
+    },
+    {
       name: "CSSMaskSourceType",
       status: "experimental",
     },
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn
index 617858dc..6c27d0c 100644
--- a/third_party/blink/renderer/platform/scheduler/BUILD.gn
+++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -8,28 +8,6 @@
 
 blink_platform_sources("scheduler") {
   sources = [
-    "base/graceful_queue_shutdown_helper.cc",
-    "base/graceful_queue_shutdown_helper.h",
-    "base/real_time_domain.cc",
-    "base/real_time_domain.h",
-    "base/sequence_manager_forward.h",
-    "base/sequence_manager_impl.cc",
-    "base/sequence_manager_impl.h",
-    "base/task_queue.cc",
-    "base/task_queue_forward.h",
-    "base/task_queue_impl.cc",
-    "base/task_queue_impl_forward.h",
-    "base/task_queue_selector.cc",
-    "base/task_queue_selector.h",
-    "base/task_queue_selector_logic.h",
-    "base/thread_controller_impl.cc",
-    "base/thread_controller_impl.h",
-    "base/time_domain.cc",
-    "base/time_domain_forward.h",
-    "base/work_queue.cc",
-    "base/work_queue.h",
-    "base/work_queue_sets.cc",
-    "base/work_queue_sets.h",
     "child/features.h",
     "child/pollable_thread_safe_flag.cc",
     "child/pollable_thread_safe_flag.h",
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h
deleted file mode 100644
index e7aa21c..0000000
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_SEQUENCE_MANAGER_FORWARD_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_SEQUENCE_MANAGER_FORWARD_H_
-
-// TODO(kraynov): Remove this header after the move.
-
-// Must be included first.
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-#define HACKDEF_INCLUDED_FROM_BLINK
-// It also includes task_queue_impl.h which has PLATFORM_EXPORT macros.
-#include "base/task/sequence_manager/sequence_manager.h"
-#undef HACKDEF_INCLUDED_FROM_BLINK
-
-namespace base {
-namespace sequence_manager {
-
-// Create SequenceManager using MessageLoop on the current thread.
-// implementation is located in sequence_manager_impl.cc.
-// TODO(kraynov): Move to SequenceManager class.
-// TODO(scheduler-dev): Rename to TakeOverCurrentThread when we'll stop using
-// MessageLoop and will actually take over a thread.
-PLATFORM_EXPORT std::unique_ptr<SequenceManager>
-CreateSequenceManagerOnCurrentThread();
-
-}  // namespace sequence_manager
-}  // namespace base
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_SEQUENCE_MANAGER_FORWARD_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl_unittest.cc
index b160bf8..a39e6d77 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
 
 #include <stddef.h>
 #include <memory>
@@ -16,6 +16,11 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/sequence_manager/real_time_domain.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/task_queue_selector.h"
+#include "base/task/sequence_manager/work_queue.h"
+#include "base/task/sequence_manager/work_queue_sets.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/test/test_simple_task_runner.h"
@@ -24,17 +29,11 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/blame_context.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/platform/scheduler/base/real_time_domain.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/mock_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_count_uses_time_source.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_task_time_observer.h"
-#include "third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h"
 
 using testing::AnyNumber;
 using testing::Contains;
diff --git a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_perftest.cc b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_perftest.cc
index 70bd824..ed72105 100644
--- a/third_party/blink/renderer/platform/scheduler/base/sequence_manager_perftest.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/sequence_manager_perftest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
+#include "base/task/sequence_manager/sequence_manager.h"
 
 #include <stddef.h>
 #include <memory>
@@ -12,12 +12,12 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/perf/perf_test.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/mock_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h"
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h b/third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h
deleted file mode 100644
index a37f961..0000000
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_FORWARD_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_FORWARD_H_
-
-// Currently the implementation is located in Blink because scheduler/base move
-// is in progress https://crbug.com/783309.
-// TODO(kraynov): Remove this header after the move.
-
-// Must be included first.
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-#define HACKDEF_INCLUDED_FROM_BLINK
-#include "base/task/sequence_manager/task_queue.h"
-#undef HACKDEF_INCLUDED_FROM_BLINK
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_FORWARD_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h b/third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h
deleted file mode 100644
index 11b975f..0000000
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_IMPL_FORWARD_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_IMPL_FORWARD_H_
-
-// Currently the implementation is located in Blink because scheduler/base move
-// is in progress https://crbug.com/783309.
-// TODO(kraynov): Remove this header after the move.
-
-// Must be included first.
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-#define HACKDEF_INCLUDED_FROM_BLINK
-#include "base/task/sequence_manager/task_queue_impl.h"
-#undef HACKDEF_INCLUDED_FROM_BLINK
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TASK_QUEUE_IMPL_FORWARD_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/task_queue_selector_unittest.cc b/third_party/blink/renderer/platform/scheduler/base/task_queue_selector_unittest.cc
index b7cb6f1..4b9ccd1 100644
--- a/third_party/blink/renderer/platform/scheduler/base/task_queue_selector_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/task_queue_selector_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h"
+#include "base/task/sequence_manager/task_queue_selector.h"
 
 #include <stddef.h>
 
@@ -12,13 +12,13 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/pending_task.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/work_queue.h"
+#include "base/task/sequence_manager/work_queue_sets.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/mock_time_domain.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h"
 
 using testing::_;
 
diff --git a/third_party/blink/renderer/platform/scheduler/base/test/mock_time_domain.h b/third_party/blink/renderer/platform/scheduler/base/test/mock_time_domain.h
index c395b6c3a..3d3faf48 100644
--- a/third_party/blink/renderer/platform/scheduler/base/test/mock_time_domain.h
+++ b/third_party/blink/renderer/platform/scheduler/base/test/mock_time_domain.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TEST_MOCK_TIME_DOMAIN_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TEST_MOCK_TIME_DOMAIN_H_
 
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
+#include "base/task/sequence_manager/time_domain.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.cc b/third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.cc
index 832a950..e34c27e 100644
--- a/third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 
-#include "third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.h"
+#include "base/task/sequence_manager/thread_controller_impl.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h b/third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h
index 460911a..4befcca 100644
--- a/third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h
+++ b/third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h
@@ -6,8 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TEST_SEQUENCE_MANAGER_FOR_TEST_H_
 
 #include "base/single_thread_task_runner.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
 #include "base/time/tick_clock.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h"
 
 namespace base {
 class MessageLoop;
diff --git a/third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.cc b/third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.cc
index 5a02791..2db5f5b8 100644
--- a/third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h"
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h b/third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h
index e8c05d6..706372a 100644
--- a/third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TEST_TEST_TASK_QUEUE_H_
 
 #include "base/memory/weak_ptr.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
+#include "base/task/sequence_manager/task_queue.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h b/third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h
deleted file mode 100644
index 6b012ab6..0000000
--- a/third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TIME_DOMAIN_FORWARD_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TIME_DOMAIN_FORWARD_H_
-
-// Currently the implementation is located in Blink because scheduler/base move
-// is in progress https://crbug.com/783309.
-// TODO(kraynov): Remove this header after the move.
-
-// Must be included first.
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-#define HACKDEF_INCLUDED_FROM_BLINK
-#include "base/task/sequence_manager/time_domain.h"
-#undef HACKDEF_INCLUDED_FROM_BLINK
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_BASE_TIME_DOMAIN_FORWARD_H_
diff --git a/third_party/blink/renderer/platform/scheduler/base/time_domain_unittest.cc b/third_party/blink/renderer/platform/scheduler/base/time_domain_unittest.cc
index 476485e..951314f 100644
--- a/third_party/blink/renderer/platform/scheduler/base/time_domain_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/time_domain_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
+#include "base/task/sequence_manager/time_domain.h"
 
 #include <memory>
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/task/sequence_manager/sequence_manager_impl.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/work_queue.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
 
 using testing::_;
 using testing::AnyNumber;
diff --git a/third_party/blink/renderer/platform/scheduler/base/work_queue_sets_unittest.cc b/third_party/blink/renderer/platform/scheduler/base/work_queue_sets_unittest.cc
index 62e321a1..d2dc9a1 100644
--- a/third_party/blink/renderer/platform/scheduler/base/work_queue_sets_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/work_queue_sets_unittest.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h"
+#include "base/task/sequence_manager/work_queue_sets.h"
 
 #include <stddef.h>
 
 #include "base/memory/ptr_util.h"
+#include "base/task/sequence_manager/work_queue.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/base/work_queue_unittest.cc b/third_party/blink/renderer/platform/scheduler/base/work_queue_unittest.cc
index aba858de..b984f84 100644
--- a/third_party/blink/renderer/platform/scheduler/base/work_queue_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/base/work_queue_unittest.cc
@@ -2,16 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue.h"
+#include "base/task/sequence_manager/work_queue.h"
 
 #include <stddef.h>
 #include <memory>
 
 #include "base/bind.h"
+#include "base/task/sequence_manager/real_time_domain.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/work_queue_sets.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/renderer/platform/scheduler/base/real_time_domain.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/work_queue_sets.h"
 
 namespace base {
 namespace sequence_manager {
diff --git a/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.cc b/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.cc
index 391c521..8e672dc 100644
--- a/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.cc
+++ b/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.cc
@@ -8,7 +8,7 @@
 
 #include "base/bind.h"
 #include "base/location.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
+#include "base/task/sequence_manager/task_queue.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
index 9619174f..7c9a23d 100644
--- a/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
@@ -9,9 +9,9 @@
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/time/default_tick_clock.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h"
diff --git a/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper_unittest.cc
index 611efb0..fbcd2e0 100644
--- a/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper_unittest.cc
@@ -5,10 +5,10 @@
 #include "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
 
 #include "base/task/sequence_manager/lazy_now.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "components/viz/test/ordered_simple_task_runner.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
diff --git a/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc b/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
index eb7d203..6929547 100644
--- a/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
@@ -4,12 +4,12 @@
 
 #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
 
+#include "base/task/sequence_manager/sequence_manager.h"
+#include "base/task/sequence_manager/task_queue.h"
+#include "base/task/sequence_manager/time_domain.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc
index f8310c7..f2034b0 100644
--- a/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/idle_helper_unittest.cc
@@ -11,14 +11,14 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task/sequence_manager/sequence_manager.h"
+#include "base/task/sequence_manager/task_queue.h"
+#include "base/task/sequence_manager/time_domain.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "components/viz/test/ordered_simple_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.h b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.h
index 42e7ca8..13485052 100644
--- a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.h
@@ -6,10 +6,10 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_METRICS_HELPER_H_
 
 #include "base/optional.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/time/time.h"
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/util/task_duration_metric_reporter.h"
 
 namespace base {
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
index cef362a9..b1d90e7 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
@@ -6,10 +6,10 @@
 
 #include <utility>
 
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
index 81963783..29a46162 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h
@@ -10,11 +10,10 @@
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/task/sequence_manager/sequence_manager.h"
 #include "base/time/tick_clock.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_selector.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
index b029f55..c510e3e7 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper_unittest.cc
@@ -9,10 +9,10 @@
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/sequence_manager/lazy_now.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/test/scoped_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc
index 66706e84..75aee0e 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool_unittest.cc
@@ -10,11 +10,11 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "components/viz/test/ordered_simple_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h"
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
index 8498c2f25..42269fa 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
@@ -12,10 +12,10 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/task/sequence_manager/task_queue.h"
+#include "base/task/sequence_manager/time_domain.h"
 #include "base/threading/thread_checker.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/common/cancelable_closure_holder.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h"
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc
index 037ea85..f19fe359 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler_unittest.cc
@@ -11,12 +11,12 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/task/sequence_manager/sequence_manager.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "components/viz/test/ordered_simple_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/throttled_time_domain.h b/third_party/blink/renderer/platform/scheduler/common/throttling/throttled_time_domain.h
index 8d7bb3e..889a491 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/throttled_time_domain.h
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/throttled_time_domain.h
@@ -6,8 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_THROTTLING_THROTTLED_TIME_DOMAIN_H_
 
 #include "base/macros.h"
+#include "base/task/sequence_manager/time_domain.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h b/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h
index 09526dc..3a3dbec 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h
@@ -7,9 +7,9 @@
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/task/sequence_manager/time_domain.h"
 #include "base/time/time_override.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/time_domain_forward.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
index ba2c84e2..47efdd6 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain_unittest.cc
@@ -6,10 +6,10 @@
 
 #include <memory>
 #include "base/run_loop.h"
+#include "base/task/sequence_manager/sequence_manager.h"
 #include "base/test/test_mock_time_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_task_time_observer.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
index 4afc6ef..5252738 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -11,9 +11,9 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/trace_event/trace_event.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_visibility_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h b/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h
index 46768b9b..1f72d60 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h
@@ -7,10 +7,10 @@
 
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/time/tick_clock.h"
 #include "cc/base/rolling_time_delta_history.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
index af16e93..a978f394 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator_unittest.cc
@@ -7,11 +7,11 @@
 #include <memory>
 
 #include "base/memory/scoped_refptr.h"
+#include "base/task/sequence_manager/sequence_manager.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/test/scoped_task_environment.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/sequence_manager_for_test.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_task_queue.h"
 #include "third_party/blink/renderer/platform/scheduler/base/test/test_task_time_observer.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 9cf061d..28e6c37 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
@@ -29,7 +30,6 @@
 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/blink_resource_coordinator_base.h"
 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/child/features.h"
 #include "third_party/blink/renderer/platform/scheduler/child/process_state.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 4dc01318..58a5430 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -19,12 +19,12 @@
 #include "base/metrics/single_sample_metrics.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/task/sequence_manager/task_time_observer.h"
 #include "base/trace_event/trace_log.h"
 #include "build/build_config.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.h"
 #include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
index 8791700..7bec9d7 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
index 50cb991..1bf14a0 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -5,8 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_MAIN_THREAD_TASK_QUEUE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_MAIN_THREAD_TASK_QUEUE_H_
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
+#include "base/task/sequence_manager/task_queue.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 
@@ -196,6 +196,7 @@
  protected:
   void SetFrameSchedulerForTest(FrameSchedulerImpl* frame_scheduler);
 
+  // TODO(kraynov): Consider options to remove TaskQueueImpl reference here.
   MainThreadTaskQueue(
       std::unique_ptr<base::sequence_manager::internal::TaskQueueImpl> impl,
       const Spec& spec,
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
index 7b6f8703..8357b92 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
@@ -13,9 +13,9 @@
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/optional.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/time/time.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_visibility_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h b/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h
index 903d7eb..6caf61e594 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.h
@@ -5,8 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_PRIORITIZE_COMPOSITING_AFTER_INPUT_EXPERIMENT_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_MAIN_THREAD_PRIORITIZE_COMPOSITING_AFTER_INPUT_EXPERIMENT_H_
 
+#include "base/task/sequence_manager/task_queue.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
index 634099d..90a1affe 100644
--- a/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
@@ -7,8 +7,8 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc b/third_party/blink/renderer/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
index 6cdfe33..09dfa78 100644
--- a/third_party/blink/renderer/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
@@ -5,7 +5,7 @@
 #include "third_party/blink/renderer/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h"
 
 #include "base/location.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/test/lazy_thread_controller_for_test.h b/third_party/blink/renderer/platform/scheduler/test/lazy_thread_controller_for_test.h
index 325baf6..0ff6b6d 100644
--- a/third_party/blink/renderer/platform/scheduler/test/lazy_thread_controller_for_test.h
+++ b/third_party/blink/renderer/platform/scheduler/test/lazy_thread_controller_for_test.h
@@ -7,8 +7,8 @@
 
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task/sequence_manager/thread_controller_impl.h"
 #include "base/threading/platform_thread.h"
-#include "third_party/blink/renderer/platform/scheduler/base/thread_controller_impl.h"
 
 // TODO(kraynov): Move to //base/task/sequence_manager/test to avoid
 // cross-component exposure of internal ThreadControllerImpl.
diff --git a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
index fc4855e..456bd41c 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
@@ -9,10 +9,10 @@
 
 #include "base/callback.h"
 #include "base/message_loop/message_loop.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/child/features.h"
 #include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
diff --git a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
index 2c88e6f..dcc5a4e1 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
@@ -8,11 +8,11 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "third_party/blink/public/platform/scheduler/single_thread_idle_task_runner.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
diff --git a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc
index 99a9524..8cf71824 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h"
 
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
+#include "base/task/sequence_manager/task_queue_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
index b247336c..1ca0468 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
@@ -5,8 +5,8 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_WORKER_NON_MAIN_THREAD_TASK_QUEUE_H_
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_WORKER_NON_MAIN_THREAD_TASK_QUEUE_H_
 
+#include "base/task/sequence_manager/task_queue.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 
 namespace blink {
 namespace scheduler {
@@ -16,6 +16,7 @@
 class PLATFORM_EXPORT NonMainThreadTaskQueue
     : public base::sequence_manager::TaskQueue {
  public:
+  // TODO(kraynov): Consider options to remove TaskQueueImpl reference here.
   NonMainThreadTaskQueue(
       std::unique_ptr<base::sequence_manager::internal::TaskQueueImpl> impl,
       const Spec& spec,
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
index 927b590..d9625367 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
@@ -10,12 +10,12 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/task/sequence_manager/sequence_manager.h"
+#include "base/task/sequence_manager/task_queue.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "third_party/blink/renderer/platform/histogram.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/child/features.h"
 #include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
diff --git a/third_party/blink/renderer/platform/testing/testing_platform_support.cc b/third_party/blink/renderer/platform/testing/testing_platform_support.cc
index 9e98ff0..5fac72f6 100644
--- a/third_party/blink/renderer/platform/testing/testing_platform_support.cc
+++ b/third_party/blink/renderer/platform/testing/testing_platform_support.cc
@@ -49,7 +49,6 @@
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 #include "third_party/blink/renderer/platform/network/mime/mock_mime_registry.h"
-#include "third_party/blink/renderer/platform/scheduler/base/sequence_manager_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
 #include "third_party/blink/renderer/platform/wtf/wtf.h"
diff --git a/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc b/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
index a2b3d722..809330e 100644
--- a/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
+++ b/third_party/blink/renderer/platform/text/text_break_iterator_icu.cc
@@ -870,30 +870,6 @@
   return rule_status != UBRK_WORD_NONE;
 }
 
-static TextBreakIterator* SetUpIteratorWithRules(const char* break_rules,
-                                                 const UChar* string,
-                                                 int length) {
-  if (!string)
-    return nullptr;
-
-  static TextBreakIterator* iterator = nullptr;
-  if (!iterator) {
-    UParseError parse_status;
-    UErrorCode open_status = U_ZERO_ERROR;
-    // break_rules is ASCII. Pick the most efficient UnicodeString ctor.
-    iterator = new icu::RuleBasedBreakIterator(
-        icu::UnicodeString(break_rules, -1, US_INV), parse_status, open_status);
-    DCHECK(U_SUCCESS(open_status))
-        << "ICU could not open a break iterator: " << u_errorName(open_status)
-        << " (" << open_status << ")";
-    if (!iterator)
-      return nullptr;
-  }
-
-  SetText16(iterator, string, length);
-  return iterator;
-}
-
 TextBreakIterator* CursorMovementIterator(const UChar* string, int length) {
   // This rule set is based on character-break iterator rules of ICU 4.0
   // <http://source.icu-project.org/repos/icu/icu/tags/release-4-0/source/data/brkitr/char.txt>.
@@ -984,7 +960,28 @@
       "!!safe_reverse;"
       "!!safe_forward;";
 
-  return SetUpIteratorWithRules(kRules, string, length);
+  if (!string)
+    return nullptr;
+
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(
+      ThreadSpecific<std::unique_ptr<icu::RuleBasedBreakIterator>>,
+      thread_specific, ());
+
+  std::unique_ptr<icu::RuleBasedBreakIterator>& iterator = *thread_specific;
+
+  if (!iterator) {
+    UParseError parse_status;
+    UErrorCode open_status = U_ZERO_ERROR;
+    // break_rules is ASCII. Pick the most efficient UnicodeString ctor.
+    iterator = std::make_unique<icu::RuleBasedBreakIterator>(
+        icu::UnicodeString(kRules, -1, US_INV), parse_status, open_status);
+    DCHECK(U_SUCCESS(open_status))
+        << "ICU could not open a break iterator: " << u_errorName(open_status)
+        << " (" << open_status << ")";
+  }
+
+  SetText16(iterator.get(), string, length);
+  return iterator.get();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/timer_test.cc b/third_party/blink/renderer/platform/timer_test.cc
index 7ff47af..8ede271 100644
--- a/third_party/blink/renderer/platform/timer_test.cc
+++ b/third_party/blink/renderer/platform/timer_test.cc
@@ -12,7 +12,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_thread.h"
-#include "third_party/blink/renderer/platform/scheduler/base/task_queue_impl_forward.h"
 #include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
diff --git a/chrome/third_party/chromevox/BUILD.gn b/third_party/chromevox/BUILD.gn
similarity index 100%
rename from chrome/third_party/chromevox/BUILD.gn
rename to third_party/chromevox/BUILD.gn
diff --git a/chrome/third_party/chromevox/LICENSE b/third_party/chromevox/LICENSE
similarity index 100%
rename from chrome/third_party/chromevox/LICENSE
rename to third_party/chromevox/LICENSE
diff --git a/chrome/third_party/chromevox/OWNERS b/third_party/chromevox/OWNERS
similarity index 100%
rename from chrome/third_party/chromevox/OWNERS
rename to third_party/chromevox/OWNERS
diff --git a/chrome/third_party/chromevox/README.chromium b/third_party/chromevox/README.chromium
similarity index 95%
rename from chrome/third_party/chromevox/README.chromium
rename to third_party/chromevox/README.chromium
index dc97bcb..8702dc1 100644
--- a/chrome/third_party/chromevox/README.chromium
+++ b/third_party/chromevox/README.chromium
@@ -3,6 +3,7 @@
 InfoURL: http://www.chromevox.com/
 Version: 1.31.4
 License: Apache 2.0
+Security Critical: Yes
 
 Description:
 ChromeVox is the screen reader for Chrome OS.  This directory contains pars of
diff --git a/chrome/third_party/chromevox/chromevox/background/chrome_shared2.css b/third_party/chromevox/chromevox/background/chrome_shared2.css
similarity index 100%
rename from chrome/third_party/chromevox/chromevox/background/chrome_shared2.css
rename to third_party/chromevox/chromevox/background/chrome_shared2.css
diff --git a/chrome/third_party/chromevox/chromevox/background/options.css b/third_party/chromevox/chromevox/background/options.css
similarity index 100%
rename from chrome/third_party/chromevox/chromevox/background/options.css
rename to third_party/chromevox/chromevox/background/options.css
diff --git a/chrome/third_party/chromevox/chromevox/background/options_widgets.css b/third_party/chromevox/chromevox/background/options_widgets.css
similarity index 100%
rename from chrome/third_party/chromevox/chromevox/background/options_widgets.css
rename to third_party/chromevox/chromevox/background/options_widgets.css
diff --git a/chrome/third_party/chromevox/chromevox/injected/mathjax.js b/third_party/chromevox/chromevox/injected/mathjax.js
similarity index 100%
rename from chrome/third_party/chromevox/chromevox/injected/mathjax.js
rename to third_party/chromevox/chromevox/injected/mathjax.js
diff --git a/chrome/third_party/chromevox/chromevox/injected/mathjax_external_util.js b/third_party/chromevox/chromevox/injected/mathjax_external_util.js
similarity index 100%
rename from chrome/third_party/chromevox/chromevox/injected/mathjax_external_util.js
rename to third_party/chromevox/chromevox/injected/mathjax_external_util.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/LICENSE b/third_party/chromevox/third_party/closure-library/LICENSE
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/LICENSE
rename to third_party/chromevox/third_party/closure-library/LICENSE
diff --git a/chrome/third_party/chromevox/third_party/closure-library/README.chromium b/third_party/chromevox/third_party/closure-library/README.chromium
similarity index 97%
rename from chrome/third_party/chromevox/third_party/closure-library/README.chromium
rename to third_party/chromevox/third_party/closure-library/README.chromium
index f1fb9e0..aa37cc52 100644
--- a/chrome/third_party/chromevox/third_party/closure-library/README.chromium
+++ b/third_party/chromevox/third_party/closure-library/README.chromium
@@ -3,6 +3,7 @@
 Version: 5a4878ece3dd35230a21d745411ab0985cf99e15
 InfoURL: http://developers.google.com/closure/library
 License: Apache 2.0
+Security Critical: Yes
 
 Description:
 Closure Library is a powerful, low level JavaScript library designed
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/depstree.py b/third_party/chromevox/third_party/closure-library/closure/bin/build/depstree.py
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/depstree.py
rename to third_party/chromevox/third_party/closure-library/closure/bin/build/depstree.py
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/source.py b/third_party/chromevox/third_party/closure-library/closure/bin/build/source.py
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/source.py
rename to third_party/chromevox/third_party/closure-library/closure/bin/build/source.py
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/treescan.py b/third_party/chromevox/third_party/closure-library/closure/bin/build/treescan.py
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/bin/build/treescan.py
rename to third_party/chromevox/third_party/closure-library/closure/bin/build/treescan.py
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/asserts/asserts.js b/third_party/chromevox/third_party/closure-library/closure/goog/asserts/asserts.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/asserts/asserts.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/asserts/asserts.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/base.js b/third_party/chromevox/third_party/closure-library/closure/goog/base.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/base.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/base.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/debug/error.js b/third_party/chromevox/third_party/closure-library/closure/goog/debug/error.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/debug/error.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/debug/error.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/dom/nodetype.js b/third_party/chromevox/third_party/closure-library/closure/goog/dom/nodetype.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/dom/nodetype.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/dom/nodetype.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/i18n/messageformat.js b/third_party/chromevox/third_party/closure-library/closure/goog/i18n/messageformat.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/i18n/messageformat.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/i18n/messageformat.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/i18n/ordinalrules.js b/third_party/chromevox/third_party/closure-library/closure/goog/i18n/ordinalrules.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/i18n/ordinalrules.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/i18n/ordinalrules.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/i18n/pluralrules.js b/third_party/chromevox/third_party/closure-library/closure/goog/i18n/pluralrules.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/i18n/pluralrules.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/i18n/pluralrules.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/object/object.js b/third_party/chromevox/third_party/closure-library/closure/goog/object/object.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/object/object.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/object/object.js
diff --git a/chrome/third_party/chromevox/third_party/closure-library/closure/goog/string/string.js b/third_party/chromevox/third_party/closure-library/closure/goog/string/string.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/closure-library/closure/goog/string/string.js
rename to third_party/chromevox/third_party/closure-library/closure/goog/string/string.js
diff --git a/chrome/third_party/chromevox/third_party/sre/LICENSE b/third_party/chromevox/third_party/sre/LICENSE
similarity index 100%
rename from chrome/third_party/chromevox/third_party/sre/LICENSE
rename to third_party/chromevox/third_party/sre/LICENSE
diff --git a/chrome/third_party/chromevox/third_party/sre/METADATA b/third_party/chromevox/third_party/sre/METADATA
similarity index 100%
rename from chrome/third_party/chromevox/third_party/sre/METADATA
rename to third_party/chromevox/third_party/sre/METADATA
diff --git a/chrome/third_party/chromevox/third_party/sre/OWNERS b/third_party/chromevox/third_party/sre/OWNERS
similarity index 100%
rename from chrome/third_party/chromevox/third_party/sre/OWNERS
rename to third_party/chromevox/third_party/sre/OWNERS
diff --git a/chrome/third_party/chromevox/third_party/sre/sre_browser.js b/third_party/chromevox/third_party/sre/sre_browser.js
similarity index 100%
rename from chrome/third_party/chromevox/third_party/sre/sre_browser.js
rename to third_party/chromevox/third_party/sre/sre_browser.js
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn
index 89491023..c8bd9c6 100644
--- a/third_party/harfbuzz-ng/BUILD.gn
+++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -46,7 +46,6 @@
 
     sources = [
       "src/src/hb-atomic-private.hh",
-      "src/src/hb-blob-private.hh",
       "src/src/hb-blob.cc",
       "src/src/hb-blob.h",
       "src/src/hb-buffer-deserialize-json.hh",
@@ -158,7 +157,6 @@
       "src/src/hb-shaper-list.hh",
       "src/src/hb-shaper-private.hh",
       "src/src/hb-shaper.cc",
-      "src/src/hb-static.cc",
       "src/src/hb-string-array.hh",
       "src/src/hb-subset-glyf.hh",
       "src/src/hb-subset-plan.h",
@@ -178,7 +176,6 @@
       "HAVE_ICU",
       "HAVE_ICU_BUILTIN",
       "HAVE_INTEL_ATOMIC_PRIMITIVES",
-      "HB_NO_MMAP",
     ]
 
     if (is_component_build) {
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 777219af..98165ba 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,9 +1,9 @@
 Name: harfbuzz-ng
 Short Name: harfbuzz-ng
 URL: http://harfbuzz.org
-Version: 1.8.2
-Date: 20180703
-Revision: 2cb075fe26201f3e370fccfff6c1bc242b5acc79
+Version: 1.7.6
+Date: 20180319
+Revision: 957e7756634a4fdf1654041e20e883cf964ecac9
 Security Critical: yes
 License: MIT
 License File: src/COPYING
@@ -31,26 +31,16 @@
     dump-khmer-data.cc
     dump-myanmar-data.cc
     dump-use-data.cc
-    hb-aat-fmtx-table.hh
-    hb-aat-gcid-table.hh
     hb-aat-layout-ankr-table.hh
-    hb-aat-layout-bsln-table.hh
     hb-aat-layout-common-private.hh
-    hb-aat-layout-feat-table.hh
     hb-aat-layout-kerx-table.hh
     hb-aat-layout-morx-table.hh
     hb-aat-layout-private.hh
     hb-aat-layout-trak-table.hh
     hb-aat-layout.cc
-    hb-aat-ltag-table.hh
     hb-directwrite.cc
     hb-directwrite.h
     hb-fallback-shape.cc
-    hb-map-private.hh
-    hb-map.cc
-    hb-map.h
-    hb-ot-color-sbix-table.hh
-    hb-ot-color-svg-table.hh
     hb-ot-color.cc
     hb-subset-glyf.cc
     hb-subset-input.cc
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py
index f8d61c7d..076a9639 100644
--- a/tools/binary_size/libsupersize/html_report.py
+++ b/tools/binary_size/libsupersize/html_report.py
@@ -241,9 +241,10 @@
   small_symbols = {}
   small_file_node = None
   if min_symbol_size > 0:
+    component_index = components.GetOrAdd('')
     small_file_node = {
       _COMPACT_FILE_PATH_KEY: _NAME_SMALL_SYMBOL_BUCKET,
-      _COMPACT_FILE_COMPONENT_INDEX_KEY: components.GetOrAdd(''),
+      _COMPACT_FILE_COMPONENT_INDEX_KEY: component_index,
       _COMPACT_FILE_SYMBOLS_KEY: [],
     }
     file_nodes[_NAME_SMALL_SYMBOL_BUCKET] = small_file_node
diff --git a/tools/binary_size/libsupersize/template_tree_view/index.html b/tools/binary_size/libsupersize/template_tree_view/index.html
index 60cb0d5..48479243 100644
--- a/tools/binary_size/libsupersize/template_tree_view/index.html
+++ b/tools/binary_size/libsupersize/template_tree_view/index.html
@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html lang='en'>
+<html lang="en">
 <!--
  Copyright 2018 The Chromium Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
@@ -17,9 +17,9 @@
             display: grid;
             grid-template-columns: auto 0;
             grid-template-rows: 64px 1fr;
-            grid-template-areas: 'appbar options' 'symbols options';
+            grid-template-areas: "appbar options" "symbols options";
             color: #3c4043;
-            font-family: 'Roboto', sans-serif;
+            font-family: "Roboto", sans-serif;
         }
 
         .appbar {
@@ -46,7 +46,7 @@
 
         .headline {
             margin: 0;
-            font-family: 'Google Sans', Arial, sans-serif;
+            font-family: "Google Sans", Arial, sans-serif;
             font-weight: normal;
             color: #202124;
             font-size: 22px;
@@ -59,7 +59,7 @@
         }
 
         .subhead {
-            font-family: 'Google Sans', Arial, sans-serif;
+            font-family: "Google Sans", Arial, sans-serif;
             font-weight: 500;
             font-size: 14px;
             color: #3c4043;
@@ -83,7 +83,7 @@
             border-bottom: 1px solid #dadce0;
         }
 
-        [role='group'] {
+        [role="group"] {
             padding-left: 13px;
             border-left: 1px solid #dadce0;
             margin-left: 10px;
@@ -107,7 +107,7 @@
             background: #f1f3f4;
         }
         .node::before {
-            content: '';
+            content: "";
             display: inline-block;
             margin: 10px;
             width: 0;
@@ -122,7 +122,7 @@
             border-color: transparent transparent transparent currentColor;
             transition: transform .1s ease-out;
         }
-        [aria-expanded='true']>.node::before {
+        [aria-expanded="true"]>.node::before {
             transform: rotate(90deg);
         }
 
@@ -202,17 +202,35 @@
             <label class="checkbox-label" for="methodcount">Show dex method count rather than size</label>
         </p>
 
+        <h2 class="subhead">Group symbols by</h2>
+        <p class="radio-wrapper">
+            <input type="radio" id="sourcepath" name="group_by" value="source_path" checked>
+            <label class="radio-label" for="sourcepath">Source path</label>
+            <input type="radio" id="component" name="group_by" value="component">
+            <label class="radio-label" for="component">Component</label>
+        </p>
+
         <p style="text-align:right">
             <button class="filled-button" type="submit">Update</button>
         </p>
     </form>
-    <div class='symbols'>
-        <div hidden id='icons'>
-            <svg class='icon foldericon' height='24' width='24' fill='#5f6368'>
+    <div class="symbols">
+        <div hidden id="icons">
+            <svg class="icon foldericon" height="24" width="24" fill="#5f6368">
                 <title>Directory</title>
                 <path d="M9.17,6l2,2H20v10L4,18V6H9.17 M10,4H4C2.9,4,2.01,4.9,2.01,6L2,18c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2V8c0-1.1-0.9-2-2-2
                             h-8L10,4L10,4z" />
             </svg>
+            <svg class='icon componenticon' height='24' width='24' fill='#5f6368'>
+                <title>Component</title>
+                <path d="M9,13.75c-2.34,0-7,1.17-7,3.5V19h14v-1.75C16,14.92,11.34,13.75,9,13.75z M4.34,17c0.84-0.58,2.87-1.25,4.66-1.25
+                         s3.82,0.67,4.66,1.25H4.34z"/>
+                <path d="M9,12c1.93,0,3.5-1.57,3.5-3.5C12.5,6.57,10.93,5,9,5S5.5,6.57,5.5,8.5C5.5,10.43,7.07,12,9,12z M9,7
+                         c0.83,0,1.5,0.67,1.5,1.5S9.83,10,9,10S7.5,9.33,7.5,8.5S8.17,7,9,7z"/>
+                <path d="M16.04,13.81C17.2,14.65,18,15.77,18,17.25V19h4v-1.75C22,15.23,18.5,14.08,16.04,13.81z"/>
+                <path d="M15,12c1.93,0,3.5-1.57,3.5-3.5C18.5,6.57,16.93,5,15,5c-0.54,0-1.04,0.13-1.5,0.35c0.63,0.89,1,1.98,1,3.15
+                         s-0.37,2.26-1,3.15C13.96,11.87,14.46,12,15,12z"/>
+            </svg>
             <svg class="icon fileicon" height="24" width="24" fill="#5f6368">
                 <title>File</title>
                 <path d="M14,2H6C4.9,2,4.01,2.9,4.01,4L4,20c0,1.1,0.89,2,1.99,2H18c1.1,0,2-0.9,2-2V8L14,2z M6,20V4h7v5h5v11
@@ -272,30 +290,29 @@
                 />
             </svg>
         </div>
-
         <template id="treefolder">
             <li role="treeitem" aria-expanded="false">
-                <a class="node" href="#">
+                <a class="node" href="#" tabindex="-1">
                     <span class="symbol-name"></span>
                     <span class="size"></span>
                 </a>
-                <ul role="group" hidden></ul>
+                <ul role="group"></ul>
             </li>
         </template>
         <template id="treeitem">
             <li role="treeitem">
-                <span class="node">
+                <span class="node" tabindex="-1">
                     <span class="symbol-name"></span>
                     <span class="size"></span>
                 </span>
             </li>
         </template>
-        <main class='tree-container'>
-            <header class='tree-header'>
-                <span class='subtitle'>Name</span>
-                <span class='subtitle'>{{size_header}}</span>
+        <main class="tree-container">
+            <header class="tree-header">
+                <span class="subtitle">Name</span>
+                <span class="subtitle" id="size-header" data-value="{{size_header}}">{{size_header}}</span>
             </header>
-            <ul id='symboltree' class='tree' role='tree' aria-labelledby='headline'></ul>
+            <ul id="symboltree" class="tree" role="tree" aria-labelledby="headline"></ul>
         </main>
     </div>
 </body>
diff --git a/tools/binary_size/libsupersize/template_tree_view/options.css b/tools/binary_size/libsupersize/template_tree_view/options.css
index 4b9af281..6bbfc0b0 100644
--- a/tools/binary_size/libsupersize/template_tree_view/options.css
+++ b/tools/binary_size/libsupersize/template_tree_view/options.css
@@ -101,6 +101,7 @@
   background: rgba(0, 0, 0, 0.04);
 }
 select {
+  -webkit-appearance: none;
   font: inherit;
   background: transparent;
   border: 0;
@@ -120,17 +121,31 @@
   color: #5f6368;
   border-bottom: 1px solid currentColor;
 }
-select:focus+.select-label {
+.select-label::after {
+  content: '';
+  position: absolute;
+  top: calc(50% - 5px);
+  right: 4px;
+  margin: 5px 7px 5px 8px;
+  border-style: solid;
+  border-width: 5px 5px 0 5px;
+  border-color: currentColor transparent transparent transparent;
+  transition: transform 0.2s ease-out;
+}
+select:focus + .select-label {
   color: #1a73e8;
   bottom: -2px;
   border-width: 2px;
 }
+select:focus + .select-label::after {
+  transform: rotate(180deg);
+}
 
-/** <input type='checkbox'> elements */
-input[type='checkbox'] {
+/** <input type='checkbox' or 'radio'> elements */
+input[type='checkbox'], input[type='radio'] {
   display: none;
 }
-.checkbox-label {
+.checkbox-label, .radio-label {
   display: block;
   position: relative;
   padding-left: 34px;
@@ -138,19 +153,20 @@
   cursor: pointer;
   font-size: 14px;
 }
-.checkbox-label::before, .checkbox-label::after {
+.checkbox-label::before, .checkbox-label::after,
+.radio-label::before, .radio-label::after {
   position: absolute;
   content: '';
   border: 2px solid currentColor;
 }
-.checkbox-label::before {
+.checkbox-label::before, .radio-label::before {
   width: 14px;
   height: 14px;
   border-radius: 2px;
   left: 0;
 }
 .checkbox-label::after {
-  display: none;
+  opacity: 0;
   width: 4px;
   height: 9px;
   left: 6px;
@@ -159,26 +175,41 @@
   border-left-width: 0;
   transform: rotate(45deg);
 }
-input[type='checkbox']:checked + .checkbox-label {
+.radio-label::before {
+  border-radius: 50%;
+}
+.radio-label::after {
+  opacity: 0;
+  width: 4px;
+  height: 4px;
+  left: 5px;
+  top: 5px;
+  background: currentColor;
+  border-radius: 50%;
+}
+input[type='checkbox']:checked + .checkbox-label,
+input[type='radio']:checked + .radio-label {
   color: #1a73e8;
 }
-input[type='checkbox']:checked + .checkbox-label::after {
-  display: block;
+input[type='checkbox']:checked + .checkbox-label::after,
+input[type='radio']:checked + .radio-label::after {
+  opacity: 1;
 }
-input[type='checkbox']:disabled + .checkbox-label {
+input[type='checkbox']:disabled + .checkbox-label,
+input[type='radio']:disabled + .radio-label {
   color: #80868b;
 }
 
 /** Tweaks for smaller screen sizes */
 @media (max-width: 700px) {
   .show-options {
-      grid-template-columns: auto 0;
+    grid-template-columns: auto 0;
   }
   .show-options .scrim {
-      display: block;
+    display: block;
   }
   .appbar,
   .symbols {
-      padding: 0 16px;
+    padding: 0 16px;
   }
 }
diff --git a/tools/binary_size/libsupersize/template_tree_view/state.js b/tools/binary_size/libsupersize/template_tree_view/state.js
index 6c29c655..0de25a62 100644
--- a/tools/binary_size/libsupersize/template_tree_view/state.js
+++ b/tools/binary_size/libsupersize/template_tree_view/state.js
@@ -28,11 +28,11 @@
    * Removes all the existing children of `parent` and inserts
    * `newChild` in their place
    * @param {Node} parent
-   * @param {Node} newChild
+   * @param {Node | null} newChild
    */
   replace(parent, newChild) {
     while (parent.firstChild) parent.removeChild(parent.firstChild);
-    parent.appendChild(newChild);
+    if (newChild != null) parent.appendChild(newChild);
   },
 };
 
@@ -42,7 +42,7 @@
    * can be manipulated by this object. Keys in the query match with
    * input names.
    */
-  const _filterParams = new URLSearchParams(location.search.slice(1));
+  let _filterParams = new URLSearchParams(location.search.slice(1));
 
   const state = {
     /**
@@ -102,6 +102,15 @@
      */
     set(name, value) {
       _filterParams.set(name, value);
+      state.setAll(_filterParams);
+    },
+    /**
+     * Replaces the current state with a new list of values. Afterwards
+     * display the new state in the URL by replacing the current history entry.
+     * @param {Iterable<[string, string]>} entries Iterator of key-value pairs
+     */
+    setAll(entries) {
+      _filterParams = new URLSearchParams(entries);
       history.replaceState(null, null, '?' + _filterParams.toString());
     },
   };
@@ -111,10 +120,14 @@
     if (input.name) {
       const value = _filterParams.get(input.name);
       if (value) {
-        if (input.type === 'checkbox') {
-          input.checked = value === input.value;
-        } else {
-          input.value = value;
+        switch (input.type) {
+          case 'checkbox':
+          case 'radio':
+            input.checked = value === input.value;
+            break;
+          default:
+            input.value = value;
+            break;
         }
       }
     }
@@ -153,11 +166,21 @@
     document.body.classList.add('show-options');
   }
 
-  // Disable some fields when method_count is set
-  if (state.has('method_count')) {
-    document.getElementById('size-header').textContent = 'Methods';
-    form.byteunit.setAttribute('disabled', '');
+  /**
+   * Disable some fields when method_count is set
+   */
+  function setMethodCountModeUI() {
+    const sizeHeader = document.getElementById('size-header');
+    if (form.method_count.checked) {
+      sizeHeader.textContent = 'Methods';
+      form.byteunit.setAttribute('disabled', '');
+    } else {
+      sizeHeader.textContent = sizeHeader.dataset.value;
+      form.byteunit.removeAttribute('disabled', '');
+    }
   }
+  setMethodCountModeUI();
+  form.method_count.addEventListener('change', setMethodCountModeUI);
 }
 
 /** Utilities for working with the state */
diff --git a/tools/binary_size/libsupersize/template_tree_view/tree-worker.js b/tools/binary_size/libsupersize/template_tree_view/tree-worker.js
index 9ebe2ce..94bc4986 100644
--- a/tools/binary_size/libsupersize/template_tree_view/tree-worker.js
+++ b/tools/binary_size/libsupersize/template_tree_view/tree-worker.js
@@ -61,6 +61,7 @@
 
 const _NO_NAME = '(No path)';
 const _DIRECTORY_TYPE = 'D';
+const _COMPONENT_TYPE = 'C';
 const _FILE_TYPE = 'F';
 
 /**
@@ -71,8 +72,9 @@
  * @param {string} sep Path seperator, such as '/'.
  */
 function basename(path, sep) {
-  const idx = path.lastIndexOf(sep);
-  return path.substring(idx + 1);
+  const sepIndex = path.lastIndexOf(sep);
+  const pathIndex = path.lastIndexOf('/');
+  return path.substring(Math.max(sepIndex, pathIndex) + 1);
 }
 
 /**
@@ -82,33 +84,9 @@
  * @param {string} sep Path seperator, such as '/'.
  */
 function dirname(path, sep) {
-  const idx = path.lastIndexOf(sep);
-  return path.substring(0, idx);
-}
-
-/**
- * Collapse "java"->"com"->"google" into "java/com/google". Nodes will only be
- * collapsed if they are the same type, most commonly by merging directories.
- * @param {TreeNode} node Node to potentially collapse. Will be modified by
- * this function.
- * @param {string} sep Path seperator, such as '/'.
- */
-function combineSingleChildNodes(node, sep) {
-  if (node.children.length > 0) {
-    const [child] = node.children;
-    // If there is only 1 child and its the same type, merge it in.
-    if (node.children.length === 1 && node.type === child.type) {
-      // size & type should be the same, so don't bother copying them.
-      node.shortName += sep + '\u200b' + child.shortName;
-      node.idPath = child.idPath;
-      node.children = child.children;
-      // Search children of this node.
-      combineSingleChildNodes(node, sep);
-    } else {
-      // Search children of this node.
-      node.children.forEach(child => combineSingleChildNodes(child, sep));
-    }
-  }
+  const sepIndex = path.lastIndexOf(sep);
+  const pathIndex = path.lastIndexOf('/');
+  return path.substring(0, Math.max(sepIndex, pathIndex));
 }
 
 /**
@@ -178,15 +156,23 @@
  * @param {(symbol: TreeNode) => boolean} options.filterTest Called to see if
  * a symbol should be included. If a symbol fails the test, it will not be
  * attached to the tree.
- * @param {string} options.sep Path seperator used to find parent names.
- * @param {boolean} options.methodCountMode If true, return number of dex
+ * @param {string} [options.sep] Path seperator used to find parent names.
+ * @param {boolean} [options.methodCountMode] If true, return number of dex
  * methods instead of size.
  * @returns {TreeNode} Root node of the new tree
  */
 function makeTree(options) {
-  const {symbols, sep, methodCountMode, getPath, filterTest} = options;
+  const {
+    symbols,
+    getPath,
+    filterTest,
+    sep = '/',
+    methodCountMode = false,
+  } = options;
+  if (!getPath) throw new TypeError('Missing getPath');
+
   const rootNode = createNode(
-    {idPath: '/', shortName: '/', type: _DIRECTORY_TYPE},
+    {idPath: sep, shortName: sep, type: _DIRECTORY_TYPE},
     sep
   );
 
@@ -213,8 +199,13 @@
       // get parent from cache if it exists, otherwise create it
       parentNode = parents.get(parentPath);
       if (parentNode == null) {
+        const useAltType =
+          node.idPath.lastIndexOf(sep) > node.idPath.lastIndexOf('/');
         parentNode = createNode(
-          {idPath: parentPath, type: _DIRECTORY_TYPE},
+          {
+            idPath: parentPath,
+            type: useAltType ? _COMPONENT_TYPE : _DIRECTORY_TYPE,
+          },
           sep
         );
         parents.set(parentPath, parentNode);
@@ -231,9 +222,13 @@
   // its parent directory node, or create it if missing.
   for (const fileNode of symbols) {
     // make path for this
+    const filePath = fileNode[_KEYS.SOURCE_PATH];
     const idPath = getPath(fileNode);
     // make node for this
-    const node = createNode({idPath, type: _FILE_TYPE}, sep);
+    const node = createNode(
+      {idPath, shortName: basename(filePath, sep), type: _FILE_TYPE},
+      sep
+    );
     // build child nodes for this file's symbols and attach to self
     for (const symbol of fileNode[_KEYS.FILE_SYMBOLS]) {
       const size = methodCountMode ? 1 : symbol[_KEYS.SIZE];
@@ -258,8 +253,6 @@
     getOrMakeParentNode(directory);
   }
 
-  // Collapse nodes such as "java"->"com"->"google" into "java/com/google".
-  combineSingleChildNodes(rootNode, sep);
   // Sort the tree so that larger items are higher.
   sortTree(rootNode);
 
@@ -279,7 +272,7 @@
   const {tree, options} = JSON.parse(event.data);
 
   const params = new URLSearchParams(options);
-  const sep = params.get('sep') || '/';
+  const groupBy = params.get('group_by') || 'source_path';
   const methodCountMode = params.has('method_count');
   let typeFilter;
   if (methodCountMode) typeFilter = new Set('m');
@@ -288,11 +281,25 @@
     typeFilter = new Set(types.length === 0 ? 'bdrtv*xmpPo' : types);
   }
 
+  const getPathMap = {
+    component(fileEntry) {
+      const component = tree.components[fileEntry[_KEYS.COMPONENT_INDEX]];
+      const path = getPathMap.source_path(fileEntry);
+      return (component || '(No component)') + '>' + path;
+    },
+    source_path(fileEntry) {
+      return fileEntry[_KEYS.SOURCE_PATH];
+    },
+  };
+  const sepMap = {
+    component: '>',
+  };
+
   const rootNode = makeTree({
     symbols: tree.file_nodes,
-    sep,
+    sep: sepMap[groupBy],
     methodCountMode,
-    getPath: s => s[_KEYS.SOURCE_PATH],
+    getPath: getPathMap[groupBy],
     filterTest: s => typeFilter.has(s.type),
   });
 
diff --git a/tools/binary_size/libsupersize/template_tree_view/ui.js b/tools/binary_size/libsupersize/template_tree_view/ui.js
index bbf82ea..ca3a122d 100644
--- a/tools/binary_size/libsupersize/template_tree_view/ui.js
+++ b/tools/binary_size/libsupersize/template_tree_view/ui.js
@@ -30,6 +30,7 @@
    */
   const _SYMBOL_ICONS = {
     D: _icons.querySelector('.foldericon'),
+    C: _icons.querySelector('.componenticon'),
     F: _icons.querySelector('.fileicon'),
     b: _icons.querySelector('.bssicon'),
     d: _icons.querySelector('.dataicon'),
@@ -48,6 +49,11 @@
   const _leafTemplate = document.getElementById('treeitem');
   const _treeTemplate = document.getElementById('treefolder');
 
+  const _symbolTree = document.getElementById('symboltree');
+
+  /** HTMLCollection of all nodes. Updates itself automatically. */
+  const _liveNodeList = document.getElementsByClassName('node');
+
   /**
    * @type {WeakMap<HTMLElement, Readonly<TreeNode>>}
    * Associates UI nodes with the corresponding tree data object
@@ -113,6 +119,24 @@
   }
 
   /**
+   * Sets focus to a new tree element while updating the element that last had
+   * focus. The tabindex property is used to avoid needing to tab through every
+   * single tree item in the page to reach other areas.
+   * @param {number | HTMLElement} el Index of tree node in `_liveNodeList`
+   */
+  function _focusTreeElement(el) {
+    const lastFocused = document.activeElement;
+    if (_uiNodeData.has(lastFocused)) {
+      lastFocused.tabIndex = -1;
+    }
+    const element = typeof el === 'number' ? _liveNodeList[el] : el;
+    if (element != null) {
+      element.tabIndex = 0;
+      element.focus();
+    }
+  }
+
+  /**
    * Click event handler to expand or close the child group of a tree.
    * @param {Event} event
    */
@@ -126,17 +150,120 @@
     const isExpanded = element.getAttribute('aria-expanded') === 'true';
     if (isExpanded) {
       element.setAttribute('aria-expanded', 'false');
-      group.setAttribute('hidden', '');
+      dom.replace(group, null);
     } else {
-      if (group.children.length === 0) {
-        const data = _uiNodeData.get(link);
-        group.appendChild(
-          dom.createFragment(data.children.map(child => newTreeElement(child)))
-        );
+      const data = _uiNodeData.get(link);
+      const newElements = data.children.map(child => newTreeElement(child));
+      if (newElements.length === 1) {
+        // Open the inner element if it only has a single child.
+        // Ensures nodes like "java"->"com"->"google" are opened all at once.
+        newElements[0].querySelector('.node').click();
       }
 
+      group.appendChild(dom.createFragment(newElements));
       element.setAttribute('aria-expanded', 'true');
-      group.removeAttribute('hidden');
+    }
+  }
+
+  /**
+   * Keydown event handler to move focus for the given element
+   * @param {KeyboardEvent} event
+   */
+  function _handleKeyNavigation(event) {
+    const link = event.target;
+    const focusIndex = Array.prototype.indexOf.call(_liveNodeList, link);
+
+    /** Focus the tree element immediately following this one */
+    function _focusNext() {
+      if (focusIndex > -1 && focusIndex < _liveNodeList.length - 1) {
+        event.preventDefault();
+        _focusTreeElement(focusIndex + 1);
+      }
+    }
+
+    /** Open or close the tree element */
+    function _toggle() {
+      event.preventDefault();
+      link.click();
+    }
+
+    /** Focus the tree element at `index` if it starts with `char` */
+    function _focusIfStartsWith(char, index) {
+      const data = _uiNodeData.get(_liveNodeList[index]);
+      if (data.shortName.startsWith(char)) {
+        event.preventDefault();
+        _focusTreeElement(index);
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    switch (event.key) {
+      // Space should act like clicking or pressing enter & toggle the tree.
+      case ' ':
+        _toggle();
+        break;
+      // Move to previous focusable node
+      case 'ArrowUp':
+        if (focusIndex > 0) {
+          event.preventDefault();
+          _focusTreeElement(focusIndex - 1);
+        }
+        break;
+      // Move to next focusable node
+      case 'ArrowDown':
+        _focusNext();
+        break;
+      // If closed tree, open tree. Otherwise, move to first child.
+      case 'ArrowRight':
+        if (_uiNodeData.get(link).children.length !== 0) {
+          const isExpanded =
+            link.parentElement.getAttribute('aria-expanded') === 'true';
+          if (isExpanded) {
+            _focusNext();
+          } else {
+            _toggle();
+          }
+        }
+        break;
+      // If opened tree, close tree. Otherwise, move to parent.
+      case 'ArrowLeft':
+        {
+          const isExpanded =
+            link.parentElement.getAttribute('aria-expanded') === 'true';
+          if (isExpanded) {
+            _toggle();
+          } else {
+            const groupList = link.parentElement.parentElement;
+            if (groupList.getAttribute('role') === 'group') {
+              event.preventDefault();
+              _focusTreeElement(groupList.previousElementSibling);
+            }
+          }
+        }
+        break;
+      // Focus first node
+      case 'Home':
+        event.preventDefault();
+        _focusTreeElement(0);
+        break;
+      // Focus last node on screen
+      case 'End':
+        event.preventDefault();
+        _focusTreeElement(_liveNodeList.length - 1);
+        break;
+      // If a letter was pressed, find a node starting with that character.
+      default:
+        if (event.key.length === 1 && event.key.match(/\S/)) {
+          for (let i = focusIndex + 1; i < _liveNodeList.length; i++) {
+            if (_focusIfStartsWith(event.key, i)) return;
+          }
+          for (let i = 0; i < focusIndex; i++) {
+            if (_focusIfStartsWith(event.key, i)) return;
+          }
+        }
+        break;
     }
   }
 
@@ -190,7 +317,10 @@
     }
   });
 
+  _symbolTree.addEventListener('keydown', _handleKeyNavigation);
+
   self.newTreeElement = newTreeElement;
+  self._symbolTree = _symbolTree;
 }
 
 {
@@ -208,10 +338,12 @@
    */
   worker.onmessage = ({data}) => {
     const root = newTreeElement(data);
+    const node = root.querySelector('.node');
     // Expand the root UI node
-    root.querySelector('.node').click();
+    node.click();
+    node.tabIndex = 0;
 
-    dom.replace(document.getElementById('symboltree'), root);
+    dom.replace(_symbolTree, root);
   };
 
   /**
@@ -226,5 +358,11 @@
     );
   }
 
+  form.addEventListener('submit', event => {
+    event.preventDefault();
+    state.setAll(new FormData(event.currentTarget));
+    loadTree(tree_data);
+  })
+
   self.loadTree = loadTree;
 }
diff --git a/tools/clang/scripts/generate_compdb.py b/tools/clang/scripts/generate_compdb.py
index 146916a..7378093 100755
--- a/tools/clang/scripts/generate_compdb.py
+++ b/tools/clang/scripts/generate_compdb.py
@@ -40,7 +40,7 @@
 
   compdb_text = json.dumps(
       compile_db.ProcessCompileDatabaseIfNeeded(
-          compile_db.GenerateWithNinja(args.p, args.targets))
+          compile_db.GenerateWithNinja(args.p, args.targets)))
   if args.o is None:
     print(compdb_text)
   else:
diff --git a/tools/luci-go/.gitignore b/tools/luci-go/.gitignore
index 99085c5..06e95105 100644
--- a/tools/luci-go/.gitignore
+++ b/tools/luci-go/.gitignore
@@ -1,5 +1,3 @@
-/isolate
-/isolate.exe
 /linux64/isolate
 /mac64/isolate
 /win64/isolate.exe
diff --git a/tools/luci-go/OWNERS b/tools/luci-go/OWNERS
index 8b03e48b..3bcc77d 100644
--- a/tools/luci-go/OWNERS
+++ b/tools/luci-go/OWNERS
@@ -1,3 +1,5 @@
+djd@chromium.org
 maruel@chromium.org
 tandrii@chromium.org
+tansell@chromium.org
 vadimsh@chromium.org
diff --git a/tools/luci-go/README.md b/tools/luci-go/README.md
index 5cb0ddf..f53bec17 100644
--- a/tools/luci-go/README.md
+++ b/tools/luci-go/README.md
@@ -2,4 +2,9 @@
 
 Contains executable built out of
 https://chromium.googlesource.com/infra/luci/luci-go/+/master/client/cmd
-Mapped through CIPD.
+
+The binaries are retrieved from the following builders:
+
+- mac64: http://build.chromium.org/p/chromium.infra/builders/infra-continuous-mac-10.10-64/
+- linux64: http://build.chromium.org/p/chromium.infra/builders/infra-continuous-precise-64/
+- win64: http://build.chromium.org/p/chromium.infra/builders/infra-continuous-win-64/
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 5f0b7f8..1e4b3b2 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -27851,6 +27851,7 @@
   <int value="-973509424" label="NewTabPageIcons:disabled"/>
   <int value="-972737445" label="ArcUseAuthEndpoint:disabled"/>
   <int value="-972425050" label="gesture-editing"/>
+  <int value="-970067535" label="BackgroundTaskComponentUpdate:disabled"/>
   <int value="-969332901" label="stop-non-timers-in-background:disabled"/>
   <int value="-968010468" label="SharedArrayBuffer:disabled"/>
   <int value="-966290456" label="WebAuthenticationCtap2:enabled"/>
@@ -28389,6 +28390,7 @@
   <int value="255375615" label="stop-non-timers-in-background:enabled"/>
   <int value="259021228" label="OffMainThreadFetch:disabled"/>
   <int value="262382944" label="GuestViewCrossProcessFrames:disabled"/>
+  <int value="265830810" label="BackgroundTaskComponentUpdate:enabled"/>
   <int value="266322815" label="ChromeModernDesign:disabled"/>
   <int value="266702296" label="disable-plugin-power-saver"/>
   <int value="268535107"
@@ -30249,6 +30251,18 @@
   <int value="615" label="border-block-end"/>
   <int value="616" label="border-inline-start"/>
   <int value="617" label="border-inline-end"/>
+  <int value="618" label="margin-block"/>
+  <int value="619" label="margin-inline"/>
+  <int value="620" label="padding-block"/>
+  <int value="621" label="padding-inline"/>
+  <int value="622" label="border-block-color"/>
+  <int value="623" label="border-block-style"/>
+  <int value="624" label="border-block-width"/>
+  <int value="625" label="border-inline-color"/>
+  <int value="626" label="border-inline-style"/>
+  <int value="627" label="border-inline-width"/>
+  <int value="628" label="border-block"/>
+  <int value="629" label="border-inline"/>
 </enum>
 
 <enum name="MappedEditingCommands">
@@ -47541,6 +47555,7 @@
   <int value="-400619253" label="mus_demo"/>
   <int value="-254080081" label="cdm"/>
   <int value="-2816355" label="profile_import"/>
+  <int value="69152809" label="font_service"/>
   <int value="357224138" label="user_id"/>
   <int value="498331100" label="preferences"/>
   <int value="573935755" label="removable_storage_writer"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1514768..cd62164 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -85501,26 +85501,6 @@
   </summary>
 </histogram>
 
-<histogram name="Scheduling.BeginMainFrameIntervalCritical2"
-    units="microseconds">
-  <owner>brianderson@chromium.org</owner>
-  <summary>
-    This is the time delta between back-to-back BeginMainFrames completions on
-    the compositor side when the on_critical_path flag is set, regardless of
-    whether they abort (have no updates) or commit (have updates).
-
-    The interval is only recorded when the BeginMainFrames are running
-    continuously; sepcifically when another BeginMainFrame is requested by the
-    next BeginImplFrame after a) an abort or b) activation.
-
-    Warning: This metric may include reports from clients with low-resolution
-    clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
-    will cause this metric to have an abnormal distribution. When considering
-    revising this histogram, see UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES for the
-    solution.
-  </summary>
-</histogram>
-
 <histogram name="Scheduling.BeginMainFrameIntervalNotCritical"
     units="microseconds">
   <obsolete>
@@ -85661,6 +85641,29 @@
   </summary>
 </histogram>
 
+<histogram name="Scheduling.Browser.BeginMainFrameIntervalCritical2"
+    units="microseconds">
+  <obsolete>
+    Deprecated in 06/2018, M69, due to too much noise in the collected data.
+  </obsolete>
+  <owner>brianderson@chromium.org</owner>
+  <summary>
+    This is the time delta between back-to-back BeginMainFrames completions on
+    the compositor side when the on_critical_path flag is set, regardless of
+    whether they abort (have no updates) or commit (have updates).
+
+    The interval is only recorded when the BeginMainFrames are running
+    continuously; sepcifically when another BeginMainFrame is requested by the
+    next BeginImplFrame after a) an abort or b) activation.
+
+    Warning: This metric may include reports from clients with low-resolution
+    clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
+    will cause this metric to have an abnormal distribution. When considering
+    revising this histogram, see UMA_HISTOGRAM_CUSTOM_HIGH_RESOLUTION_TIMES for
+    the solution.
+  </summary>
+</histogram>
+
 <histogram name="Scheduling.Browser.BeginMainFrameStartToCommit"
     units="microseconds">
   <obsolete>
@@ -85993,6 +85996,26 @@
   </summary>
 </histogram>
 
+<histogram name="Scheduling.Renderer.BeginMainFrameIntervalCritical2"
+    units="microseconds">
+  <owner>brianderson@chromium.org</owner>
+  <summary>
+    This is the time delta between back-to-back BeginMainFrames completions on
+    the compositor side when the on_critical_path flag is set, regardless of
+    whether they abort (have no updates) or commit (have updates).
+
+    The interval is only recorded when the BeginMainFrames are running
+    continuously; sepcifically when another BeginMainFrame is requested by the
+    next BeginImplFrame after a) an abort or b) activation.
+
+    Warning: This metric may include reports from clients with low-resolution
+    clocks (i.e. on Windows, ref. |TimeTicks::IsHighResolution()|). Such reports
+    will cause this metric to have an abnormal distribution. When considering
+    revising this histogram, see UMA_HISTOGRAM_CUSTOM_HIGH_RESOLUTION_TIMES for
+    the solution.
+  </summary>
+</histogram>
+
 <histogram name="Scheduling.Renderer.DrawInterval2" units="microseconds">
   <owner>brianderson@chromium.org</owner>
   <summary>
@@ -114857,7 +114880,6 @@
   <suffix name="Renderer"/>
   <affected-histogram name="Scheduling.ActivateDuration2"/>
   <affected-histogram name="Scheduling.BeginImplFrameLatency2"/>
-  <affected-histogram name="Scheduling.BeginMainFrameIntervalCritical2"/>
   <affected-histogram name="Scheduling.BeginMainFrameIntervalNotCritical2"/>
   <affected-histogram name="Scheduling.BeginMainFrameQueueDurationCritical2"/>
   <affected-histogram
diff --git a/tools/perf/benchmarks/startup_mobile.py b/tools/perf/benchmarks/startup_mobile.py
index 2912cf1..ea41431 100644
--- a/tools/perf/benchmarks/startup_mobile.py
+++ b/tools/perf/benchmarks/startup_mobile.py
@@ -62,7 +62,12 @@
     assert isinstance(self.platform, android_platform.AndroidPlatform)
     self._finder_options.browser_options.browser_user_agent_type = 'mobile'
     self.platform.Initialize()
-    self.platform.network_controller.Open(wpr_modes.WPR_REPLAY)
+    assert finder_options.browser_options.wpr_mode != wpr_modes.WPR_RECORD, (
+        'Recording WPR archives is not supported for this benchmark.')
+    wpr_mode = wpr_modes.WPR_REPLAY
+    if finder_options.use_live_sites:
+      wpr_mode = wpr_modes.WPR_OFF
+    self.platform.network_controller.Open(wpr_mode)
     self._story_set = story_set
 
   @property
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index c2e2f82..0d39a20 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -42,6 +42,7 @@
 crbug.com/574483 [ Android_Svelte ] blink_perf.paint/* [ Skip ]
 crbug.com/799540 [ Nexus_5 ] blink_perf.paint/* [ Skip ]
 crbug.com/799540 [ Nexus_7 ] blink_perf.paint/* [ Skip ]
+crbug.com/859979 [ Android_Webview ] blink_perf.paint/paint-offset-changes.html [ Skip ]
 
 # Benchmark: blink_perf.parser
 crbug.com/796115 [ Android_One ] blink_perf.parser/html5-full-render.html [ Skip ]
@@ -85,6 +86,19 @@
 [ Nexus_5X ] loading.mobile/Hongkiat [ Skip ]
 [ Nexus_5X ] loading.mobile/Dramaq [ Skip ]
 [ Nexus_7 ] loading.mobile/Facebook [ Skip ]
+[ All ] loading.mobile/Bradesco_3g [ Skip ]
+[ All ] loading.mobile/Dailymotion_3g [ Skip ]
+[ All ] loading.mobile/Dawn_3g [ Skip ]
+[ All ] loading.mobile/FlipKart_cold_3g [ Skip ]
+[ All ] loading.mobile/G1_3g [ Skip ]
+[ All ] loading.mobile/GSShop_3g [ Skip ]
+[ All ] loading.mobile/GoogleIndia_3g [ Skip ]
+[ All ] loading.mobile/KapanLagi_3g [ Skip ]
+[ All ] loading.mobile/Kaskus_3g [ Skip ]
+[ All ] loading.mobile/LocalMoxie_3g [ Skip ]
+[ All ] loading.mobile/Thairath_3g [ Skip ]
+[ All ] loading.mobile/TheStar_3g [ Skip ]
+[ All ] loading.mobile/YahooNews_3g [ Skip ]
 
 # Benchmark: memory.long_running_idle_gmail_tbmv2
 crbug.com/611167 [ Android_Svelte ] memory.long_running_idle_gmail_tbmv2/* [ Skip ]
@@ -306,6 +320,9 @@
 # Benchmark: media.desktop
 crbug.com/859660 [ All ] media.desktop/video.html?src=tulip2.vp9.webm_Regular-3G [ Skip ]
 
+# Benchmark: media.mobile
+crbug.com/859175 [ Android ] media.mobile/video.html?src=tulip2.vp9.webm_Regular-3G [ Skip ]
+
 # Benchmark: v8.browsing_desktop
 crbug.com/773084 [ Mac ] v8.browsing_desktop/browse:tools:maps [ Skip ]
 crbug.com/788796 [ Linux ] v8.browsing_desktop/browse:media:imgur [ Skip ]
diff --git a/tools/perf/page_sets/system_health/system_health_stories.py b/tools/perf/page_sets/system_health/system_health_stories.py
index b1eea779..1d087fb 100644
--- a/tools/perf/page_sets/system_health/system_health_stories.py
+++ b/tools/perf/page_sets/system_health/system_health_stories.py
@@ -25,7 +25,7 @@
 
     assert platform in platforms.ALL_PLATFORMS
 
-    for story_class in _IterAllSystemHealthStoryClasses():
+    for story_class in IterAllSystemHealthStoryClasses():
       if (story_class.ABSTRACT_STORY or
           platform not in story_class.SUPPORTED_PLATFORMS or
           case and not story_class.NAME.startswith(case + ':')):
@@ -67,7 +67,12 @@
         'mobile', take_memory_measurement=False)
 
 
-def _IterAllSystemHealthStoryClasses():
+def IterAllSystemHealthStoryClasses():
+  """Generator for system health stories.
+
+  Yields:
+    All appropriate SystemHealthStory subclasses defining stories.
+  """
   start_dir = os.path.dirname(os.path.abspath(__file__))
   # Sort the classes by their names so that their order is stable and
   # deterministic.
diff --git a/tools/traffic_annotation/scripts/traffic_annotation_auditor_tests.py b/tools/traffic_annotation/scripts/traffic_annotation_auditor_tests.py
index 2901c94b..c1345d5a 100755
--- a/tools/traffic_annotation/scripts/traffic_annotation_auditor_tests.py
+++ b/tools/traffic_annotation/scripts/traffic_annotation_auditor_tests.py
@@ -91,10 +91,13 @@
     _, stderr_text, return_code = self.tools.RunAuditor(
         args + ["--annotations-file=%s" % temp_filename])
 
-    # TODO(https://crbug.com/844014): Remove after debugging.
-    print("Return Code: %i" % return_code)
-    print("File Exists: %i" % os.path.exists(temp_filename))
     if os.path.exists(temp_filename):
+      # When tests are run on all files (without filtering), there might be some
+      # compile errors in irrelevant files on Windows that can be ignored.
+      if (return_code and "--no-filtering" in args and
+          sys.platform.startswith(('win', 'cygwin'))):
+        print("Ignoring return code: %i" % return_code)
+        return_code = 0
       annotations = None if return_code else open(temp_filename).read()
       os.remove(temp_filename)
     else:
diff --git a/ui/file_manager/externs/command_handler_deps.js b/ui/file_manager/externs/command_handler_deps.js
index e8342c1..a3647b4 100644
--- a/ui/file_manager/externs/command_handler_deps.js
+++ b/ui/file_manager/externs/command_handler_deps.js
@@ -6,7 +6,7 @@
  * Interface on which |CommandHandler| depends.
  * @interface
  */
-function CommandHandlerDeps(){};
+function CommandHandlerDeps() {}
 
 /**
  * @type {ActionsController}
@@ -94,7 +94,7 @@
 CommandHandlerDeps.prototype.volumeManager;
 
 /**
- * @return {DirectoryEntry|FakeEntry}
+ * @return {DirectoryEntry|FakeEntry|FilesAppEntry}
  */
 CommandHandlerDeps.prototype.getCurrentDirectoryEntry = function() {};
 
diff --git a/ui/file_manager/externs/volume_info_list.js b/ui/file_manager/externs/volume_info_list.js
index d8d25d7..da5715f 100644
--- a/ui/file_manager/externs/volume_info_list.js
+++ b/ui/file_manager/externs/volume_info_list.js
@@ -47,7 +47,8 @@
 
 /**
  * Searches the information of the volume that contains the passed entry.
- * @param {!Entry|!FakeEntry} entry Entry on the volume to be found.
+ * @param {!Entry|!FakeEntry|!FilesAppEntry} entry Entry on the volume to be
+ *     found.
  * @return {VolumeInfo} The volume's information, or null if not found.
  */
 VolumeInfoList.prototype.findByEntry = function(entry) {};
diff --git a/ui/file_manager/externs/volume_manager.js b/ui/file_manager/externs/volume_manager.js
index b0fda5d..ba92628 100644
--- a/ui/file_manager/externs/volume_manager.js
+++ b/ui/file_manager/externs/volume_manager.js
@@ -7,7 +7,7 @@
  * @interface
  * @extends {VolumeManagerCommon.VolumeInfoProvider}
  */
-function VolumeManager() {};
+function VolumeManager() {}
 
 /**
  * The list of VolumeInfo instances for each mounted volume.
@@ -59,8 +59,8 @@
 /**
  * Obtains location information from an entry.
  *
- * @param {!Entry|!FakeEntry} entry File or directory entry. It can be a fake
- *     entry.
+ * @param {!Entry|!FakeEntry|!FilesAppEntry} entry File or directory entry. It
+ *     can be a fake entry.
  * @return {EntryLocation} Location information.
  */
 VolumeManager.prototype.getLocationInfo = function(entry) {};
diff --git a/ui/file_manager/file_manager/background/js/BUILD.gn b/ui/file_manager/file_manager/background/js/BUILD.gn
index 0e09ce54..6b2d8b3 100644
--- a/ui/file_manager/file_manager/background/js/BUILD.gn
+++ b/ui/file_manager/file_manager/background/js/BUILD.gn
@@ -87,6 +87,7 @@
     ":launcher_search",
     ":media_import_handler",
     ":progress_center",
+    "../../common/js:files_app_entry_types",
     "../../common/js:metrics",
     "../../common/js:util",
     "../../common/js:volume_manager_common",
diff --git a/ui/file_manager/file_manager/background/js/background_common_scripts.js b/ui/file_manager/file_manager/background/js/background_common_scripts.js
index 3a14a116..f791184 100644
--- a/ui/file_manager/file_manager/background/js/background_common_scripts.js
+++ b/ui/file_manager/file_manager/background/js/background_common_scripts.js
@@ -15,6 +15,7 @@
 // <include src="../../common/js/metrics_base.js">
 // <include src="../../common/js/metrics_events.js">
 // <include src="../../common/js/metrics.js">
+// <include src="../../common/js/files_app_entry_types.js">
 // <include src="../../common/js/util.js">
 // <include src="../../common/js/volume_manager_common.js">
 // <include src="app_window_wrapper.js">
diff --git a/ui/file_manager/file_manager/background/js/mock_volume_manager.js b/ui/file_manager/file_manager/background/js/mock_volume_manager.js
index e757e7a..f4283bd 100644
--- a/ui/file_manager/file_manager/background/js/mock_volume_manager.js
+++ b/ui/file_manager/file_manager/background/js/mock_volume_manager.js
@@ -59,7 +59,8 @@
 /**
  * Returns the corresponding VolumeInfo.
  *
- * @param {!Entry|!FakeEntry} entry FileEntry pointing anywhere on a volume.
+ * @param {!Entry|!FakeEntry|!FilesAppEntry} entry FileEntry pointing anywhere
+ *     on a volume.
  * @return {VolumeInfo} Corresponding VolumeInfo.
  */
 MockVolumeManager.prototype.getVolumeInfo = function(entry) {
@@ -70,7 +71,7 @@
  * Obtains location information from an entry.
  * Current implementation can handle only fake entries.
  *
- * @param {!Entry|!FakeEntry} entry A fake entry.
+ * @param {!Entry|!FakeEntry|!FilesAppEntry} entry A fake entry.
  * @return {EntryLocation} Location information.
  */
 MockVolumeManager.prototype.getLocationInfo = function(entry) {
diff --git a/ui/file_manager/file_manager/common/js/BUILD.gn b/ui/file_manager/file_manager/common/js/BUILD.gn
index d696ced..72d68243 100644
--- a/ui/file_manager/file_manager/common/js/BUILD.gn
+++ b/ui/file_manager/file_manager/common/js/BUILD.gn
@@ -10,6 +10,7 @@
     ":closure_compile_externs",
     ":error_util",
     ":file_type",
+    ":files_app_entry_types",
     ":importer_common",
     ":lru_cache",
     ":metrics",
@@ -46,6 +47,9 @@
 js_library("error_util") {
 }
 
+js_library("files_app_entry_types") {
+}
+
 js_library("file_type") {
 }
 
@@ -87,6 +91,7 @@
 
 js_library("util") {
   deps = [
+    ":files_app_entry_types",
     ":volume_manager_common",
     "//ui/webui/resources/js:load_time_data",
     "//ui/webui/resources/js:util",
diff --git a/ui/file_manager/file_manager/common/js/files_app_entry_types.js b/ui/file_manager/file_manager/common/js/files_app_entry_types.js
new file mode 100644
index 0000000..8785ceb0
--- /dev/null
+++ b/ui/file_manager/file_manager/common/js/files_app_entry_types.js
@@ -0,0 +1,395 @@
+// 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.
+
+/**
+ * @fileoverview Entry-like types for Files app UI.
+ * This file defines the interface |FilesAppEntry| and some specialized
+ * implementations of it.
+ *
+ * These entries are intended to behave like the browser native FileSystemEntry
+ * (aka Entry) and FileSystemDirectoryEntry (aka DirectoryEntry), providing an
+ * unified API for Files app UI components. UI components should be able to
+ * display any implementation of FilesAppEntry.
+ * The main intention of those types is to be able to provide alternative
+ * implementations and from other sources for "entries", as well as be able to
+ * extend the native "entry" types.
+ *
+ * Native Entry:
+ * https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry
+ * Native DirectoryEntry:
+ * https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryReader
+ */
+
+/**
+ * FilesAppEntry represents a single Entry (file, folder or root) in the Files
+ * app. Previously, we used the Entry type directly, but this limits the code to
+ * only work with native Entry type which can't be instantiated in JS.
+ * For now, Entry and FilesAppEntry should be used interchangeably.
+ * See also FilesAppDirEntry for a folder-like interface.
+ *
+ * TODO(lucmult): Replace uses of Entry with FilesAppEntry implementations.
+ *
+ * @interface
+ */
+class FilesAppEntry {
+  constructor() {
+    /**
+     * @public {!boolean} true if this entry represents a Directory-like entry,
+     * as in have sub-entries and implements {createReader} method.
+     * This attribute is defined on Entry.
+     */
+    this.isDirectory = false;
+
+    /**
+     * @public {!boolean} true if this entry represents a File-like entry.
+     * Implementations of FilesAppEntry are expected to have this as |true|.
+     * Whereas implementations of FilesAppDirEntry are expected to have this as
+     * |false|.
+     * This attribute is defined on Entry.
+     */
+    this.isFile = true;
+
+    /**
+     * @public {string} absolute path from the file system's root to the entry.
+     * It can also be thought of as a path which is relative to the root
+     * directory, prepended with a "/" character.
+     * This attribute is defined on Entry.
+     */
+    this.fullPath = '';
+
+    /**
+     * @public {string} the name of the entry (the final part of the path,
+     * after the last.
+     * This attribute is defined on Entry.
+     */
+    this.name = '';
+
+    /**
+     * @public {!string} the class name for this class. It's workaround for the
+     * fact that an instance created on foreground page and sent to background
+     * page can't be checked with "instanceof".
+     */
+    this.type_name = 'FilesAppEntry';
+  }
+
+  /**
+   * @param {function(Entry)|function(FilesAppEntry)} success callback.
+   * @param {function(Entry)|function(FilesAppEntry)} error callback.
+   * This method is defined on Entry.
+   */
+  getParent(success, error) {}
+
+  /**
+   * @return {!string} used to compare entries. It should return an unique
+   * identifier for such entry, usually prefixed with it's root type like:
+   * "fake-entry://unique/path/to/entry".
+   * This method is defined on Entry.
+   */
+  toURL() {}
+
+  /**
+   * Return metadata via |success| callback. Relevant metadata are
+   * "modificationTime" and "contentMimeType".
+   * @param {function(Object)} success callback to be called with the result
+   * metadata.
+   * @param {function(Object)} error callback to be called in case of error or
+   * ignored if no error happened.
+   */
+  getMetadata(success, error) {}
+
+  /**
+   * Returns true if this entry object has a native representation such as Entry
+   * or DirectoryEntry, this means it can interact with VolumeManager.
+   * @return {!boolean}
+   */
+  get isNativeType() {}
+}
+
+/**
+ * A reader compatible with DirectoryEntry.createReader (from Web Standards)
+ * that reads a static list of entries, provided at construction time.
+ * https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryReader
+ * It can be used by DirectoryEntry-like such as EntryList to return its
+ * children entries.
+ */
+class StaticReader {
+  /**
+   * @param {Array<Entry|FakeEntry|FilesAppEntry>} children: Array of Entry-like
+   * instances that will be returned/read by this reader.
+   */
+  constructor(children) {
+    this.children_ = children;
+  }
+
+  /**
+   * Reads array of entries via |success| callback.
+   *
+   * @param {function(Array<Entry|FilesAppEntry>)} success: A callback that will
+   * be called multiple times with the entries, last call will be called with an
+   * empty array indicating that no more entries available.
+   * @param {function(Array<Entry|FilesAppEntry>)} error: A callback that's
+   * never called, it's here to match the signature from the Web Standards.
+   */
+  readEntries(success, error) {
+    let children = this.children_;
+    // readEntries is suppose to return empty result when there are no more
+    // files to return, so we clear the children_ attribute for next call.
+    this.children_ = [];
+    // Triggers callback asynchronously.
+    setTimeout(children => success(children), 0, children);
+  }
+}
+
+/**
+ * Interface with minimal API shared among different types of FilesAppDirEntry
+ * and native DirectoryEntry. UI components should be able to display any
+ * implementation of FilesAppEntry.
+ *
+ * FilesAppDirEntry represents a DirectoryEntry-like (folder or root) in the
+ * Files app. It's a specialization of FilesAppEntry extending the behavior for
+ * folder, which is basically the method createReader.
+ * As in FilesAppEntry, FilesAppDirEntry should be interchangeable with Entry
+ * and DirectoryEntry.
+ *
+ * @interface
+ */
+class FilesAppDirEntry extends FilesAppEntry {
+  constructor() {
+    super();
+    /**
+     * @public {!boolean} true if this entry represents a Directory-like entry,
+     * as in have sub-entries and implements {createReader} method.
+     * Implementations of FilesAppEntry are expected to have this as |true|.
+     * This attribute is defined on Entry.
+     */
+    this.isDirectory = true;
+    this.type_name = 'FilesAppDirEntry';
+  }
+
+  /**
+   * @return {!StaticReader|!DirectoryReader} Returns a reader compatible with
+   * DirectoryEntry.createReader (from Web Standards) that reads the children of
+   * this instance.
+   * This method is defined on DirectoryEntry.
+   */
+  createReader() {}
+}
+
+/**
+ * EntryList, a DirectoryEntry-like object that contains entries. Initially used
+ * to implement "My Files" containing VolumeEntry for "Downloads", "Linux
+ * Files" and "Play Files".
+ *
+ * @implements FilesAppDirEntry
+ */
+class EntryList {
+  /**
+   * @param {string} label: Label to be used when displaying to user, it should
+   *    already translated.
+   * @param {VolumeManagerCommon.RootType} rootType root type.
+   *
+   */
+  constructor(label, rootType) {
+    /**
+     * @private {string} label: Label to be used when displaying to user, it
+     *      should be already translated. */
+    this.label_ = label;
+
+    /** @private {VolumeManagerCommon.RootType} rootType root type. */
+    this.rootType_ = rootType;
+
+    /**
+     * @private {!Array<!Entry|!FilesAppEntry|!FakeEntry>} children entries of
+     * this EntryList instance.
+     */
+    this.children_ = [];
+
+    this.isDirectory = true;
+    this.isFile = false;
+    this.type_name = 'EntryList';
+  }
+
+  get children() {
+    return this.children_;
+  }
+
+  get label() {
+    return this.label_;
+  }
+
+  get rootType() {
+    return this.rootType_;
+  }
+
+  get name() {
+    return this.label_;
+  }
+
+  /** @override */
+  get isNativeType() {
+    return false;
+  }
+
+  /** @override */
+  getMetadata(success, error) {
+    // Defaults modificationTime to current time just to have a valid value.
+    setTimeout(() => success({modificationTime: new Date()}));
+  }
+
+  /**
+   * @return {!string} used to compare entries.
+   * @override
+   */
+  toURL() {
+    return 'entry-list://' + this.rootType;
+  }
+
+  /**
+   * @param {function(Entry)|function(FilesAppEntry)} success callback, it
+   * returns itself since EntryList is intended to be used as root node and the
+   * Web Standard says to do so.
+   * @param {function(Entry)|function(FilesAppEntry)} error callback, not used
+   * for this implementation.
+   *
+   * @override
+   */
+  getParent(success, error) {
+    setTimeout(success, 0, this);
+  }
+
+  /**
+   * @param {!Entry|!FakeEntry|!FilesAppEntry} entry that should be added as
+   * child of this EntryList.
+   * This method is specific to EntryList instance.
+   */
+  addEntry(entry) {
+    this.children_.push(entry);
+  }
+
+  /**
+   * @return {!StaticReader} Returns a reader compatible with
+   * DirectoryEntry.createReader (from Web Standards) that reads the children of
+   * this EntryList instance.
+   * This method is defined on DirectoryEntry.
+   * @override
+   */
+  createReader() {
+    return new StaticReader(this.children_);
+  }
+}
+
+/**
+ * A DirectoryEntry-like which represents a Volume, based on VolumeInfo.
+ *
+ * It uses composition to behave like a DirectoryEntry and proxies some calls
+ * to its VolumeInfo instance.
+ *
+ * It's used to be able to add a volume as child of |EntryList| and make volume
+ * displayable on file list.
+ *
+ * @implements FilesAppDirEntry
+ */
+class VolumeEntry {
+  /**
+   * @param {!VolumeInfo} volumeInfo: VolumeInfo for this entry.
+   */
+  constructor(volumeInfo) {
+    /**
+     * @private {!VolumeInfo} holds a reference to VolumeInfo to delegate some
+     * method calls to it.
+     */
+    this.volumeInfo_ = volumeInfo;
+
+    /** @type {DirectoryEntry} from Volume's root. */
+    this.rootEntry_ = volumeInfo.displayRoot;
+    this.type_name = 'VolumeEntry';
+  }
+
+  /**
+   * @return {!VolumeInfo} for this entry. This method is only valid for
+   * VolumeEntry instances.
+   */
+  get volumeInfo() {
+    return this.volumeInfo_;
+  }
+  /**
+   * @return {DirectoryEntry} for this volume. This method is only valid for
+   * VolumeEntry instances.
+   */
+  get rootEntry() {
+    return this.rootEntry_;
+  }
+
+  /**
+   * @return {!FileSystem} FileSystem for this volume.
+   * This method is defined on Entry.
+   */
+  get filesystem() {
+    return this.rootEntry_.filesystem;
+  }
+
+  /**
+   * @return {!string} Full path for this volume.
+   * This method is defined on Entry.
+   * @override.
+   */
+  get fullPath() {
+    return this.rootEntry_.fullPath;
+  }
+  get isDirectory() {
+    return this.rootEntry_.isDirectory;
+  }
+  get isFile() {
+    return this.rootEntry_.isFile;
+  }
+
+  /**
+   * @return {!string} Name for this volume.
+   * @override.
+   */
+  get name() {
+    return this.volumeInfo_.label;
+  }
+
+  /**
+   * @return {string}
+   * @override
+   */
+  toURL() {
+    return this.rootEntry_.toURL();
+  }
+
+  /**
+   * @param {function(Entry)|function(FilesAppEntry)} success callback, it
+   * returns itself since EntryList is intended to be used as root node and the
+   * Web Standard says to do so.
+   * @param {function(Entry)|function(FilesAppEntry)} error callback, not used
+   * for this implementation.
+   *
+   * @override
+   */
+  getParent(success, error) {
+    setTimeout(success, 0, this);
+  }
+
+  /** @override */
+  getMetadata(success, error) {
+    this.rootEntry_.getMetadata(success, error);
+  }
+
+  /** @override */
+  get isNativeType() {
+    return true;
+  }
+
+  /**
+   * @return {!StaticReader|!DirectoryReader} Returns a reader from root entry,
+   * which is compatible with DirectoryEntry.createReader (from Web Standards).
+   * This method is defined on DirectoryEntry.
+   * @override
+   */
+  createReader() {
+    return this.rootEntry_.createReader();
+  }
+}
diff --git a/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.html b/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.html
new file mode 100644
index 0000000..fe96bde5
--- /dev/null
+++ b/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<!-- Copyright 2018 The Chromium Authors. All rights reserved.
+  -- Use of this source code is governed by a BSD-style license that can be
+  -- found in the LICENSE file.
+  -->
+<html>
+  <body>
+  <script src="../../common/js/unittest_util.js"></script>
+
+  <script src="files_app_entry_types.js"></script>
+  <script src="files_app_entry_types_unittest.js"></script>
+  </body>
+</html>
diff --git a/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.js b/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.js
new file mode 100644
index 0000000..24ab21f
--- /dev/null
+++ b/ui/file_manager/file_manager/common/js/files_app_entry_types_unittest.js
@@ -0,0 +1,223 @@
+// 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.
+
+'use strict';
+
+/**  Test constructor and default public attributes. */
+function testEntryList(testReportCallback) {
+  const entryList = new EntryList('My Files', 'my_files');
+  assertEquals('My Files', entryList.label);
+  assertEquals('entry-list://my_files', entryList.toURL());
+  assertEquals('my_files', entryList.rootType);
+  assertFalse(entryList.isNativeType);
+  assertEquals(0, entryList.children.length);
+  assertTrue(entryList.isDirectory);
+  assertFalse(entryList.isFile);
+
+  entryList.addEntry(new EntryList('Child Entry', 'child_entry'));
+  assertEquals(1, entryList.children.length);
+
+  const reader = entryList.createReader();
+  // How many times the reader callback |accumulateResults| has been called?
+  let callCounter = 0;
+  // How many times it was called with results?
+  let resultCouter = 0;
+  const accumulateResults = (readerResult) => {
+    // It's called with readerResult==[] a last time to indicate no more files.
+    callCounter++;
+    if (readerResult.length > 0) {
+      resultCouter++;
+      reader.readEntries(accumulateResults);
+    }
+  };
+
+  reader.readEntries(accumulateResults);
+  // readEntries runs asynchronously, so let's wait it to be called.
+  reportPromise(
+      waitUntil(() => {
+        // accumulateResults should be called 2x in normal conditions;
+        return callCounter >= 2;
+      }).then(() => {
+        // Now we can check the final result.
+        assertEquals(2, callCounter);
+        assertEquals(1, resultCouter);
+      }),
+      testReportCallback);
+}
+
+/** Tests method EntryList.getParent. */
+function testEntryListGetParent(testReportCallback) {
+  const entryList = new EntryList('My Files', 'my_files');
+  let callbackTriggered = false;
+  entryList.getParent(parentEntry => {
+    // EntryList should return itself since it's a root and that's what the web
+    // spec says.
+    callbackTriggered = true;
+    assertEquals(parentEntry, entryList);
+  });
+  reportPromise(waitUntil(() => callbackTriggered), testReportCallback);
+}
+
+/** Tests method EntryList.addEntry. */
+function testEntryListAddEntry() {
+  const entryList = new EntryList('My Files');
+  assertEquals(0, entryList.children.length);
+
+  const fakeRootEntry = createFakeDisplayRoot();
+  const fakeVolumeInfo = {
+    displayRoot: fakeRootEntry,
+    label: 'Fake Filesystem',
+  };
+  const childEntry = new VolumeEntry(fakeVolumeInfo);
+  entryList.addEntry(childEntry);
+  assertEquals(1, entryList.children.length);
+  assertEquals(childEntry, entryList.children[0]);
+}
+
+/** Tests method EntryList.getMetadata. */
+function testEntryListAddVolume(testReportCallback) {
+  const entryList = new EntryList('My Files');
+
+  let modificationTime = null;
+  entryList.getMetadata(metadata => {
+    modificationTime = metadata.modificationTime;
+  });
+
+  // getMetadata runs asynchronously, so let's wait it to be called.
+  reportPromise(
+      waitUntil(() => {
+        return modificationTime !== null;
+      }).then(() => {
+        // Now we can check the final result, it returns "now", so let's just
+        // check the type and 1 attribute here.
+        assertTrue(modificationTime instanceof Date);
+        assertTrue(!!modificationTime.getUTCFullYear());
+      }),
+      testReportCallback);
+}
+
+/** Tests StaticReader.readEntries. */
+function testStaticReader(testReportCallback) {
+  const reader = new StaticReader(['file1', 'file2']);
+  const testResults = [];
+  // How many times the reader callback |accumulateResults| has been called?
+  let callCounter = 0;
+  const accumulateResults = (readerResult) => {
+    callCounter++;
+    // merge on testResults.
+    readerResult.map(f => testResults.push(f));
+    if (readerResult.length > 0)
+      reader.readEntries(accumulateResults);
+  };
+
+  reader.readEntries(accumulateResults);
+  // readEntries runs asynchronously, so let's wait it to be called.
+  reportPromise(
+      waitUntil(() => {
+        // accumulateResults should be called 2x in normal conditions;
+        return callCounter >= 2;
+      }).then(() => {
+        // Now we can check the final result.
+        assertEquals(2, callCounter);
+        assertEquals(2, testResults.length);
+        assertEquals('file1', testResults[0]);
+        assertEquals('file2', testResults[1]);
+      }),
+      testReportCallback);
+}
+
+/**
+ * Returns an object that can be used as displayRoot on a FakeVolumeInfo.
+ * VolumeEntry delegates many attributes and methods to displayRoot.
+ */
+function createFakeDisplayRoot() {
+  const fakeRootEntry = {
+    filesystem: 'fake-filesystem://',
+    fullPath: '/fake/full/path',
+    isDirectory: true,
+    isFile: false,
+    name: 'fs-name',
+    toURL: () => {
+      return 'fake-filesystem://fake/full/path';
+    },
+    createReader: () => {
+      return 'FAKE READER';
+    },
+    getMetadata: (success, error) => {
+      // Returns static date as modificationTime for testing.
+      setTimeout(
+          () => success({modificationTime: new Date(Date.UTC(2018, 6, 27))}));
+    },
+  };
+  return fakeRootEntry;
+}
+
+/**
+ * Tests VolumeEntry constructor and default public attributes/getter/methods.
+ */
+function testVolumeEntry() {
+  const fakeRootEntry = createFakeDisplayRoot();
+  const fakeVolumeInfo = {
+    displayRoot: fakeRootEntry,
+    label: 'Fake Filesystem',
+  };
+
+  const volumeEntry = new VolumeEntry(fakeVolumeInfo);
+  assertEquals(fakeRootEntry, volumeEntry.rootEntry);
+  assertEquals('fake-filesystem://', volumeEntry.filesystem);
+  assertEquals('/fake/full/path', volumeEntry.fullPath);
+  assertEquals('fake-filesystem://fake/full/path', volumeEntry.toURL());
+  assertEquals('Fake Filesystem', volumeEntry.name);
+  assertEquals('FAKE READER', volumeEntry.createReader());
+  assertTrue(volumeEntry.isNativeType);
+  assertTrue(volumeEntry.isDirectory);
+  assertFalse(volumeEntry.isFile);
+}
+
+/** Tests VolumeEntry.getParent */
+function testVolumeEntryGetParent(testReportCallback) {
+  const fakeRootEntry = createFakeDisplayRoot();
+  const fakeVolumeInfo = {
+    displayRoot: fakeRootEntry,
+    label: 'Fake Filesystem',
+  };
+
+  const volumeEntry = new VolumeEntry(fakeVolumeInfo);
+  let callbackTriggered = false;
+  volumeEntry.getParent(parentEntry => {
+    callbackTriggered = true;
+    // VolumeEntry should return itself since it's a root and that's what the
+    // web spec says.
+    assertEquals(parentEntry, volumeEntry);
+  });
+  reportPromise(waitUntil(() => callbackTriggered), testReportCallback);
+}
+
+/**  Tests VolumeEntry.getMetadata */
+function testVolumeEntryGetMetadata(testReportCallback) {
+  const fakeRootEntry = createFakeDisplayRoot();
+  const fakeVolumeInfo = {
+    displayRoot: fakeRootEntry,
+    label: 'Fake Filesystem',
+  };
+  const volumeEntry = new VolumeEntry(fakeVolumeInfo);
+
+  let modificationTime = null;
+  volumeEntry.getMetadata(metadata => {
+    modificationTime = metadata.modificationTime;
+  });
+
+  // getMetadata runs asynchronously, so let's wait it to be called.
+  reportPromise(
+      waitUntil(() => {
+        return modificationTime !== null;
+      }).then(() => {
+        // Now we can check the final result.
+        assertEquals(2018, modificationTime.getUTCFullYear());
+        // Date() month is 0-based, so 6 == July. :-(
+        assertEquals(6, modificationTime.getUTCMonth());
+        assertEquals(27, modificationTime.getUTCDate());
+      }),
+      testReportCallback);
+}
diff --git a/ui/file_manager/file_manager/common/js/importer_common.js b/ui/file_manager/file_manager/common/js/importer_common.js
index 3fa33d10..bca92c9 100644
--- a/ui/file_manager/file_manager/common/js/importer_common.js
+++ b/ui/file_manager/file_manager/common/js/importer_common.js
@@ -183,7 +183,7 @@
  * Returns true if the entry represents a media directory for the purposes
  * of Cloud Import.
  *
- * @param {Entry|FakeEntry} entry
+ * @param {Entry|FakeEntry|FilesAppEntry} entry
  * @param {VolumeManagerCommon.VolumeInfoProvider} volumeInfoProvider
  * @return {boolean}
  */
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js
index 926915e3..1c22f899 100644
--- a/ui/file_manager/file_manager/common/js/util.js
+++ b/ui/file_manager/file_manager/common/js/util.js
@@ -649,16 +649,23 @@
 
 /**
  * Obtains whether an entry is fake or not.
- * @param {(!Entry|!FakeEntry)} entry Entry or a fake entry.
+ * @param {(!Entry|!FakeEntry|!FilesAppEntry)} entry Entry or a fake entry.
  * @return {boolean} True if the given entry is fake.
+ * @suppress {missingProperties} Closure compiler doesn't allow to call isNative
+ * on Entry which is native and thus doesn't define this property, however we
+ * handle undefined accordingly.
+ * TODO(lucmult): Remove @suppress once all entries are sub-type of
+ * FilesAppEntry.
  */
 util.isFakeEntry = function(entry) {
-  return !('getParent' in entry);
+  return (
+      entry.getParent === undefined ||
+      (entry.isNativeType !== undefined && !entry.isNativeType));
 };
 
 /**
  * Obtains whether an entry is the root directory of a Team Drive.
- * @param {(!Entry|!FakeEntry)|null} entry Entry or a fake entry.
+ * @param {(!Entry|!FakeEntry|!FilesAppEntry)|null} entry Entry or a fake entry.
  * @return {boolean} True if the given entry is root of a Team Drive.
  */
 util.isTeamDriveRoot = function(entry) {
@@ -684,7 +691,7 @@
 
 /**
  * Obtains whether an entry is descendant of the Team Drives directory.
- * @param {(!Entry|!FakeEntry)} entry Entry or a fake entry.
+ * @param {(!Entry|!FakeEntry|!FilesAppEntry)} entry Entry or a fake entry.
  * @return {boolean} True if the given entry is under Team Drives.
  */
 util.isTeamDriveEntry = function(entry) {
@@ -712,7 +719,7 @@
 
 /**
  * Returns true if the given entry is the root folder of recent files.
- * @param {(!Entry|!FakeEntry)} entry Entry or a fake entry.
+ * @param {(!Entry|!FakeEntry|!FilesAppEntry)} entry Entry or a fake entry.
  * @returns {boolean}
  */
 util.isRecentRoot = function(entry) {
@@ -772,8 +779,10 @@
 
 /**
  * Compares two entries.
- * @param {Entry|FakeEntry} entry1 The entry to be compared. Can be a fake.
- * @param {Entry|FakeEntry} entry2 The entry to be compared. Can be a fake.
+ * @param {Entry|FakeEntry|FilesAppEntry} entry1 The entry to be compared. Can
+ *     be a fake.
+ * @param {Entry|FakeEntry|FilesAppEntry} entry2 The entry to be compared. Can
+ *     be a fake.
  * @return {boolean} True if the both entry represents a same file or
  *     directory. Returns true if both entries are null.
  */
@@ -871,7 +880,8 @@
  * Checks if {@code entry} is an immediate child of {@code directory}.
  *
  * @param {Entry} entry The presumptive child.
- * @param {DirectoryEntry|FakeEntry} directory The presumptive parent.
+ * @param {DirectoryEntry|FakeEntry|FilesAppEntry} directory The presumptive
+ *     parent.
  * @return {!Promise<boolean>} Resolves with true if {@code directory} is
  *     parent of {@code entry}.
  */
@@ -902,6 +912,14 @@
 util.isDescendantEntry = function(ancestorEntry, childEntry) {
   if (!ancestorEntry.isDirectory)
     return false;
+  if (ancestorEntry instanceof EntryList) {
+    let entryList = /** @type {EntryList} */ (ancestorEntry);
+    return entryList.children.some(ancestorChild => {
+      let volumeEntry = ancestorChild.rootEntry;
+      return util.isSameEntry(volumeEntry, childEntry) ||
+          util.isDescendantEntry(volumeEntry, childEntry);
+    });
+  }
   if (!util.isSameFileSystem(ancestorEntry.filesystem, childEntry.filesystem))
     return false;
   if (util.isSameEntry(ancestorEntry, childEntry))
@@ -1118,6 +1136,8 @@
       return str('RECENT_ROOT_LABEL');
     case VolumeManagerCommon.RootType.CROSTINI:
       return str('LINUX_FILES_ROOT_LABEL');
+    case VolumeManagerCommon.RootType.MY_FILES:
+      return str('MY_FILES_ROOT_LABEL');
     case VolumeManagerCommon.RootType.MEDIA_VIEW:
       var mediaViewRootType =
           VolumeManagerCommon.getMediaViewRootTypeFromVolumeId(
diff --git a/ui/file_manager/file_manager/common/js/volume_manager_common.js b/ui/file_manager/file_manager/common/js/volume_manager_common.js
index b30563d3..1c32499 100644
--- a/ui/file_manager/file_manager/common/js/volume_manager_common.js
+++ b/ui/file_manager/file_manager/common/js/volume_manager_common.js
@@ -106,8 +106,11 @@
   // Root for crostini 'Linux Files'.
   CROSTINI: 'crostini',
 
-  // Root for android files,
+  // Root for android files.
   ANDROID_FILES: 'android_files',
+
+  // My Files root, which aggregates DOWNLOADS, ANDROID_FILES and CROSTINI.
+  MY_FILES: 'my_files',
 };
 Object.freeze(VolumeManagerCommon.RootType);
 
@@ -139,6 +142,7 @@
   VolumeManagerCommon.RootType.ADD_NEW_SERVICES_MENU,
   VolumeManagerCommon.RootType.CROSTINI,
   VolumeManagerCommon.RootType.ANDROID_FILES,
+  VolumeManagerCommon.RootType.MY_FILES,
 ];
 console.assert(
     Object.keys(VolumeManagerCommon.RootType).length ===
@@ -223,6 +227,7 @@
   MEDIA_VIEW: 'media_view',
   CROSTINI: 'crostini',
   ANDROID_FILES: 'android_files',
+  MY_FILES: 'my_files',
 };
 
 /**
@@ -284,6 +289,8 @@
       return VolumeManagerCommon.VolumeType.CROSTINI;
     case VolumeManagerCommon.RootType.ANDROID_FILES:
       return VolumeManagerCommon.VolumeType.ANDROID_FILES;
+    case VolumeManagerCommon.RootType.MY_FILES:
+      return VolumeManagerCommon.VolumeType.MY_FILES;
   }
   assertNotReached('Unknown root type: ' + rootType);
 };
@@ -306,8 +313,8 @@
 
 /**
  * Obtains a volume info containing the passed entry.
- * @param {!Entry|!FakeEntry} entry Entry on the volume to be returned.
- *     Can be fake.
+ * @param {!Entry|!FakeEntry|!FilesAppEntry} entry Entry on the volume to be
+ *     returned. Can be fake.
  * @return {?VolumeInfo} The VolumeInfo instance or null if not found.
  */
 VolumeManagerCommon.VolumeInfoProvider.prototype.getVolumeInfo;
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index a5df428..77f86318 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -407,6 +407,7 @@
 js_library("main") {
   deps = [
     ":file_manager",
+    "../../common/js:files_app_entry_types",
     "../../common/js:metrics",
     "../../common/js:util",
   ]
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js
index 2abae1f..632241f 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -41,13 +41,14 @@
 
 /**
  * @param {!Entry} entry
+ * @param {!MetadataModel} metadataModel
  * @param {!ActionModelUI} ui
  * @param {!VolumeManagerWrapper} volumeManager
  * @implements {Action}
  * @constructor
  * @struct
  */
-function DriveShareAction(entry, volumeManager, ui) {
+function DriveShareAction(entry, metadataModel, volumeManager, ui) {
   /**
    * @private {!Entry}
    * @const
@@ -55,6 +56,12 @@
   this.entry_ = entry;
 
   /**
+   * @private {!MetadataModel}
+   * @const
+   */
+  this.metadataModel_ = metadataModel;
+
+  /**
    * @private {!VolumeManagerWrapper}
    * @const
    */
@@ -69,14 +76,15 @@
 
 /**
  * @param {!Array<!Entry>} entries
+ * @param {!MetadataModel} metadataModel
  * @param {!ActionModelUI} ui
  * @param {!VolumeManagerWrapper} volumeManager
  * @return {DriveShareAction}
  */
-DriveShareAction.create = function(entries, volumeManager, ui) {
+DriveShareAction.create = function(entries, metadataModel, volumeManager, ui) {
   if (entries.length !== 1)
     return null;
-  return new DriveShareAction(entries[0], volumeManager, ui);
+  return new DriveShareAction(entries[0], metadataModel, volumeManager, ui);
 };
 
 /**
@@ -115,9 +123,12 @@
  * @override
  */
 DriveShareAction.prototype.canExecute = function() {
+  const metadata = this.metadataModel_.getCache([this.entry_], ['canShare']);
+  assert(metadata.length === 1);
+  const canShareItem = metadata[0].canShare !== false;
   return this.volumeManager_.getDriveConnectionState().type !==
       VolumeManagerCommon.DriveConnectionType.OFFLINE &&
-      !util.isTeamDriveRoot(this.entry_);
+      !util.isTeamDriveRoot(this.entry_) && canShareItem;
 };
 
 /**
@@ -720,7 +731,7 @@
       // For Drive, actions are constructed directly in the Files app code.
       case VolumeManagerCommon.VolumeType.DRIVE:
         var shareAction = DriveShareAction.create(
-            this.entries_, this.volumeManager_, this.ui_);
+            this.entries_, this.metadataModel_, this.volumeManager_, this.ui_);
         if (shareAction)
           actions[ActionsModel.CommonActionId.SHARE] = shareAction;
 
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
index f5b2126..9e2b64c 100644
--- a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
@@ -108,6 +108,9 @@
 
   var model = new ActionsModel(volumeManager, metadataModel, shortcutsModel,
       driveSyncHandler, ui, [driveFileSystem.entries['/test']]);
+  metadataModel.properties = {
+    canShare: true,
+  };
   var invalidated = 0;
   model.addEventListener('invalidated', function() {
     invalidated++;
@@ -266,6 +269,9 @@
   var model = new ActionsModel(
       volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui,
       [driveFileSystem.entries['/team_drives/ABC Team']]);
+  metadataModel.properties = {
+    canShare: true,
+  };
   return reportPromise(
       model.initialize().then(function() {
         var actions = model.getActions();
@@ -296,6 +302,9 @@
   var model = new ActionsModel(
       volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui,
       [driveFileSystem.entries['/team_drives/ABC Team/Folder 1']]);
+  metadataModel.properties = {
+    canShare: true,
+  };
   return reportPromise(
       model.initialize().then(function() {
         var actions = model.getActions();
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index ffe6e11..25f2175b 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -36,7 +36,7 @@
 
 /**
  * Scanner of the entries in a directory.
- * @param {DirectoryEntry} entry The directory to be read.
+ * @param {DirectoryEntry|FilesAppDirEntry} entry The directory to be read.
  * @constructor
  * @extends {ContentScanner}
  */
@@ -592,8 +592,8 @@
  * @param {FileListContext} context The file list context.
  * @param {boolean} isSearch True for search directory contents, otherwise
  *     false.
- * @param {DirectoryEntry|FakeEntry} directoryEntry The entry of the current
- *     directory.
+ * @param {DirectoryEntry|FakeEntry|FilesAppDirEntry} directoryEntry The entry
+ *     of the current directory.
  * @param {function():ContentScanner} scannerFactory The factory to create
  *     ContentScanner instance.
  * @constructor
@@ -731,7 +731,8 @@
 };
 
 /**
- * @return {DirectoryEntry|FakeEntry} A DirectoryEntry for current directory.
+ * @return {DirectoryEntry|FakeEntry|FilesAppDirEntry} A DirectoryEntry for
+ *     current directory.
  *     In case of search -- the top directory from which search is run.
  */
 DirectoryContents.prototype.getDirectoryEntry = function() {
@@ -989,7 +990,8 @@
  * Creates a DirectoryContents instance to show entries in a directory.
  *
  * @param {FileListContext} context File list context.
- * @param {DirectoryEntry} directoryEntry The current directory entry.
+ * @param {DirectoryEntry|FilesAppDirEntry} directoryEntry The current directory
+ *     entry.
  * @return {DirectoryContents} Created DirectoryContents instance.
  */
 DirectoryContents.createForDirectory = function(context, directoryEntry) {
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index 7c0dd4e..4bacce0 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -327,7 +327,7 @@
 };
 
 /**
- * @return {DirectoryEntry|FakeEntry} Current directory.
+ * @return {DirectoryEntry|FakeEntry|FilesAppDirEntry} Current directory.
  */
 DirectoryModel.prototype.getCurrentDirEntry = function() {
   return this.currentDirContents_.getDirectoryEntry();
@@ -1205,7 +1205,7 @@
  * Creates directory contents for the entry and query.
  *
  * @param {FileListContext} context File list context.
- * @param {!DirectoryEntry|!FakeEntry} entry Current directory.
+ * @param {!DirectoryEntry|!FakeEntry|!FilesAppEntry} entry Current directory.
  * @param {string=} opt_query Search query string.
  * @return {DirectoryContents} Directory contents.
  * @private
@@ -1226,6 +1226,10 @@
     return DirectoryContents.createForCrostiniMounter(
         context, /** @type {!FakeEntry} */ (entry));
   }
+  if (entry.rootType == VolumeManagerCommon.RootType.MY_FILES) {
+    return DirectoryContents.createForDirectory(
+        context, /** @type {!FilesAppDirEntry} */ (entry));
+  }
   if (query && canUseDriveSearch) {
     // Drive search.
     return DirectoryContents.createForDriveSearch(
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index d31c0f8c..14ee2f2 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -351,6 +351,14 @@
    * @private
    */
   this.initBackgroundPagePromise_ = null;
+
+  /**
+   * Flags async retrieved once at startup and can be used to switch behaviour
+   * on sync functions.
+   * @dict
+   * @private
+   */
+  this.commandLineFlags_ = {};
 }
 
 FileManager.prototype = /** @struct */ {
@@ -506,12 +514,16 @@
   FileManager.prototype.startInitSettings_ = function() {
     metrics.startInterval('Load.InitSettings');
     this.appStateController_ = new AppStateController(this.dialogType);
-    return new Promise(function(resolve) {
-      this.appStateController_.loadInitialViewOptions().then(function() {
-        metrics.recordInterval('Load.InitSettings');
-        resolve();
-      });
-    }.bind(this));
+    return Promise
+        .all([
+          this.appStateController_.loadInitialViewOptions(),
+          util.isNewNavigationEnabled(),
+        ])
+        .then(values => {
+          this.commandLineFlags_['new-files-app-navigation'] =
+              /** @type {boolean} */ (values[1]);
+          metrics.recordInterval('Load.InitSettings');
+        });
   };
 
   /**
@@ -797,20 +809,20 @@
     this.document_ = this.dialogDom_.ownerDocument;
 
     metrics.startInterval('Load.InitDocuments');
-    return Promise.all([
-      this.initBackgroundPagePromise_,
-      window.importElementsPromise
-    ]).then(function() {
-      metrics.recordInterval('Load.InitDocuments');
-      metrics.startInterval('Load.InitUI');
-      this.initEssentialUI_();
-      this.initAdditionalUI_();
-      return this.initSettingsPromise_;
-    }.bind(this)).then(function() {
-      this.initFileSystemUI_();
-      this.initUIFocus_();
-      metrics.recordInterval('Load.InitUI');
-    }.bind(this));
+    return Promise
+        .all([this.initBackgroundPagePromise_, window.importElementsPromise])
+        .then(function() {
+          metrics.recordInterval('Load.InitDocuments');
+          metrics.startInterval('Load.InitUI');
+          this.initEssentialUI_();
+          this.initAdditionalUI_();
+          return this.initSettingsPromise_;
+        }.bind(this))
+        .then(function() {
+          this.initFileSystemUI_();
+          this.initUIFocus_();
+          metrics.recordInterval('Load.InitUI');
+        }.bind(this));
   };
 
   /**
@@ -1207,7 +1219,8 @@
             new NavigationModelMenuItem(
                 str('ADD_NEW_SERVICES_BUTTON_LABEL'), '#add-new-services-menu',
                 'add-new-services') :
-            null);
+            null,
+        this.commandLineFlags_['new-files-app-navigation']);
     this.setupCrostini_();
     this.ui_.initDirectoryTree(directoryTree);
   };
@@ -1474,7 +1487,8 @@
 
   /**
    * Return DirectoryEntry of the current directory or null.
-   * @return {DirectoryEntry|FakeEntry} DirectoryEntry of the current directory.
+   * @return {DirectoryEntry|FakeEntry|FilesAppDirEntry} DirectoryEntry of the
+   *     current directory.
    *     Returns null if the directory model is not ready or the current
    *     directory is not set.
    */
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 5cc497fc..e93b872f 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -69,7 +69,7 @@
  *
  * @param {EventTarget} element Element which is the command event's target.
  * @param {DirectoryModel} directoryModel
- * @return {DirectoryEntry|FakeEntry} The extracted parent entry.
+ * @return {DirectoryEntry|FakeEntry|FilesAppEntry} The extracted parent entry.
  */
 CommandUtil.getParentEntry = function(element, directoryModel) {
   if (element instanceof DirectoryTree) {
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
index b408ff45..e4f8f74 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -1469,7 +1469,8 @@
 
 /**
  * @param {!ClipboardData} clipboardData Clipboard data object.
- * @param {DirectoryEntry|FakeEntry} destinationEntry Destination entry.
+ * @param {DirectoryEntry|FakeEntry|FilesAppEntry} destinationEntry Destination
+ *    entry.
  * @return {boolean} Returns true if items stored in {@code clipboardData} can
  *     be pasted to {@code destinationEntry}. Otherwise, returns false.
  * @private
@@ -1508,7 +1509,7 @@
 /**
  * Execute paste command.
  *
- * @param {DirectoryEntry|FakeEntry} destinationEntry
+ * @param {DirectoryEntry|FakeEntry|FilesAppEntry} destinationEntry
  * @return {boolean}  Returns true, the paste is success. Otherwise, returns
  *     false.
  */
@@ -1616,7 +1617,8 @@
  * @param {!Event} event Drag event.
  * @param {Object<string>} dragAndDropData drag & drop data from
  *     getDragAndDropGlobalData_().
- * @param {DirectoryEntry|FakeEntry} destinationEntry Destination entry.
+ * @param {DirectoryEntry|FakeEntry|FilesAppEntry} destinationEntry Destination
+ *     entry.
  * @return {DropEffectAndLabel} Returns the appropriate drop query type
  *     ('none', 'move' or copy') to the current modifiers status and the
  *     destination, as well as label message to describe why the operation is
diff --git a/ui/file_manager/file_manager/foreground/js/import_controller.js b/ui/file_manager/file_manager/foreground/js/import_controller.js
index bbdb42e..c935ab6 100644
--- a/ui/file_manager/file_manager/foreground/js/import_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/import_controller.js
@@ -1071,7 +1071,7 @@
 
 /**
  * Returns the directory entry for the current directory.
- * @return {DirectoryEntry|FakeEntry}
+ * @return {DirectoryEntry|FakeEntry|FilesAppEntry}
  */
 importer.ControllerEnvironment.prototype.getCurrentDirectory;
 
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index c0d05ed..6b99219 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -80,6 +80,7 @@
 //
 // <include src="../../common/js/async_util.js">
 // <include src="../../common/js/file_type.js">
+// <include src="../../common/js/files_app_entry_types.js">
 // <include src="../../common/js/volume_manager_common.js">
 // <include src="../../common/js/util.js">
 // <include src="../../common/js/progress_center_common.js">
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
index f0373a5..2b6ded53 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
@@ -136,6 +136,8 @@
       item.canRename = prop.canRename;
     if (prop.canAddChildren !== undefined || nameMap['canAddChildren'])
       item.canAddChildren = prop.canAddChildren;
+    if (prop.canShare !== undefined || nameMap['canShare'])
+      item.canShare = prop.canShare;
     results.push(item);
   }
   return results;
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
index 1530fdf..e8abfba8 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model.js
@@ -11,6 +11,7 @@
   MENU: 'menu',
   RECENT: 'recent',
   CROSTINI: 'crostini',
+  ENTRY_LIST: 'entry-list',
 };
 
 /**
@@ -139,11 +140,14 @@
  *     The list of folder shortcut.
  * @param {NavigationModelFakeItem} recentModelItem Recent folder.
  * @param {NavigationModelMenuItem} addNewServicesItem Add new services item.
+ * @param {boolean=} opt_useNewNavigation true if should use the new navigation
+ *     style, value should come from flag new-files-app-navigation.
  * @constructor
  * @extends {cr.EventTarget}
  */
 function NavigationListModel(
-    volumeManager, shortcutListModel, recentModelItem, addNewServicesItem) {
+    volumeManager, shortcutListModel, recentModelItem, addNewServicesItem,
+    opt_useNewNavigation) {
   cr.EventTarget.call(this);
 
   /**
@@ -219,6 +223,9 @@
     this.shortcutList_.push(entryToModelItem(shortcutEntry));
   }
 
+  // True if the flag new-files-app-navigation is enabled.
+  this.useNewNavigation_ = !!opt_useNewNavigation;
+
   // Reorder volumes, shortcuts, and optional items for initial display.
   this.reorderNavigationItems_();
 
@@ -352,6 +359,19 @@
 };
 
 /**
+ * Reorder navigation items when command line flag new-files-app-navigation is
+ * enabled it nests Downloads, Linux and Android files under "My Files"; when
+ * it's disabled it has a flat structure with Linux Files after Recent menu.
+ */
+NavigationListModel.prototype.reorderNavigationItems_ = function() {
+  if (this.useNewNavigation_) {
+    return this.orderAndNestItems_();
+  } else {
+    return this.flatNavigationItems_();
+  }
+};
+
+/**
  * Reorder navigation items in the following order:
  *  1. Volumes.
  *  2. If Downloads exists, then immediately after Downloads should be:
@@ -362,7 +382,7 @@
  *  4. Add new services if it exists.
  * @private
  */
-NavigationListModel.prototype.reorderNavigationItems_ = function() {
+NavigationListModel.prototype.flatNavigationItems_ = function() {
   // Check if Linux files already mounted.
   let linuxFilesMounted = false;
   for (let i = 0; i < this.volumeList_.length; i++) {
@@ -388,6 +408,128 @@
 };
 
 /**
+ * Reorder navigation items and nest some within "Downloads"
+ * which will be displayed as "My-Files". Desired order:
+ *  1. Recents.
+ *  2. Shortcuts.
+ *  3. "My-Files" (grouping), actually Downloads volume.
+ *    3.1. Downloads
+ *    3.2. Play files (android volume) (if enabled).
+ *    3.3. Linux files (crostini volume or fake item) (if enabled).
+ *  4. Other volumes (MTP, ARCHIVE, REMOVABLE).
+ *  5. Drive volumes.
+ *  6. Other FSP (File System Provider) (when mounted).
+ *  7. Add new services if (it exists).
+ * @private
+ */
+NavigationListModel.prototype.orderAndNestItems_ = function() {
+  const volumeIndexes = {};
+  const volumeList = this.volumeList_;
+
+  // Find the index of each volumeType from the array volumeList_,
+  // for volumes that can have multiple entries it saves as list
+  // of indexes, otherwise saves the index as int directly.
+  for (let i = 0; i < volumeList.length; i++) {
+    const volumeType = volumeList[i].volumeInfo.volumeType;
+    switch (volumeType) {
+      case VolumeManagerCommon.VolumeType.CROSTINI:
+      case VolumeManagerCommon.VolumeType.DOWNLOADS:
+      case VolumeManagerCommon.VolumeType.ANDROID_FILES:
+        volumeIndexes[volumeType] = i;
+        break;
+      case VolumeManagerCommon.VolumeType.REMOVABLE:
+      case VolumeManagerCommon.VolumeType.ARCHIVE:
+      case VolumeManagerCommon.VolumeType.MTP:
+      case VolumeManagerCommon.VolumeType.DRIVE:
+      case VolumeManagerCommon.VolumeType.PROVIDED:
+      case VolumeManagerCommon.VolumeType.MEDIA_VIEW:
+        if (!volumeIndexes[volumeType]) {
+          volumeIndexes[volumeType] = [i];
+        } else {
+          volumeIndexes[volumeType].push(i);
+        }
+        break;
+      default:
+        assertNotReached(`No explict order for VolumeType: "${volumeType}"`);
+        break;
+    }
+  }
+
+  /**
+   * @param {!VolumeManagerCommon.VolumeType} volumeType the desired volume type
+   * to be filtered from volumeList.
+   * @return {NavigationModelVolumeItem}
+   */
+  const getSingleVolume = function(volumeType) {
+    return volumeList[volumeIndexes[volumeType]];
+  };
+
+  /**
+   * @param {!VolumeManagerCommon.VolumeType} volumeType the desired volume type
+   * to be filtered from volumeList.
+   * @return Array<!NavigationModelVolumeItem>
+   */
+  const getVolumes = function(volumeType) {
+    const indexes = volumeIndexes[volumeType] || [];
+    return indexes.map(idx => volumeList[idx]);
+  };
+
+  // Items as per required order.
+  this.navigationItems_ = [];
+
+  if (this.recentModelItem_)
+    this.navigationItems_.push(this.recentModelItem_);
+  for (const shortcut of this.shortcutList_)
+    this.navigationItems_.push(shortcut);
+
+  const myFilesEntry = new EntryList(
+      str('MY_FILES_ROOT_LABEL'), VolumeManagerCommon.RootType.MY_FILES);
+  const myFilesModel = new NavigationModelFakeItem(
+      myFilesEntry.label, NavigationModelItemType.ENTRY_LIST, myFilesEntry);
+  const downloadsVolume =
+      getSingleVolume(VolumeManagerCommon.VolumeType.DOWNLOADS);
+  if (downloadsVolume)
+    myFilesEntry.addEntry(new VolumeEntry(downloadsVolume.volumeInfo));
+
+  this.navigationItems_.push(myFilesModel);
+
+  const androidVolume =
+      getSingleVolume(VolumeManagerCommon.VolumeType.ANDROID_FILES);
+  if (androidVolume)
+    myFilesEntry.addEntry(new VolumeEntry(androidVolume.volumeInfo));
+
+  const crostiniVolume =
+      getSingleVolume(VolumeManagerCommon.VolumeType.CROSTINI);
+  if (crostiniVolume) {
+    // Crostini is mounted so add it.
+    myFilesEntry.addEntry(new crostiniVolume.volumeInfo);
+  } else if (this.linuxFilesItem_) {
+    // Here it's just a fake item.
+    myFilesEntry.addEntry(this.linuxFilesItem_.entry);
+  }
+
+  // Join MEDIA_VIEW, MTP, ARCHIVE and REMOVABLE.
+  // TODO(lucmult) sort based on the index number to preserve original order.
+  const otherVolumes = [].concat(
+      getVolumes(VolumeManagerCommon.VolumeType.MEDIA_VIEW),
+      getVolumes(VolumeManagerCommon.VolumeType.REMOVABLE),
+      getVolumes(VolumeManagerCommon.VolumeType.ARCHIVE),
+      getVolumes(VolumeManagerCommon.VolumeType.MTP));
+
+  for (const volume of otherVolumes)
+    this.navigationItems_.push(volume);
+
+  for (const driveItem of getVolumes(VolumeManagerCommon.VolumeType.DRIVE))
+    this.navigationItems_.push(driveItem);
+
+  for (const provided of getVolumes(VolumeManagerCommon.VolumeType.PROVIDED))
+    this.navigationItems_.push(provided);
+
+  if (this.addNewServicesItem_)
+    this.navigationItems_.push(this.addNewServicesItem_);
+};
+
+/**
  * Returns the item at the given index.
  * @param {number} index The index of the entry to get.
  * @return {NavigationModelItem|undefined} The item at the given index.
diff --git a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
index b570a2bf8..647f7cf 100644
--- a/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/navigation_list_model_unittest.js
@@ -11,8 +11,18 @@
 // Set up string assets.
 loadTimeData.data = {
   DRIVE_DIRECTORY_LABEL: 'My Drive',
+  DRIVE_MY_DRIVE_LABEL: 'My Drive',
+  DRIVE_TEAM_DRIVES_LABEL: 'Team Drives',
+  DRIVE_OFFLINE_COLLECTION_LABEL: 'Offline',
+  DRIVE_SHARED_WITH_ME_COLLECTION_LABEL: 'Shared with me',
+  DRIVE_RECENT_COLLECTION_LABEL: 'Recents',
   DOWNLOADS_DIRECTORY_LABEL: 'Downloads',
   LINUX_FILES_ROOT_LABEL: 'Linux Files',
+  MY_FILES_ROOT_LABEL: 'My Files',
+  RECENT_ROOT_LABEL: 'Recent',
+  MEDIA_VIEW_IMAGES_ROOT_LABEL: 'Images',
+  MEDIA_VIEW_VIDEOS_ROOT_LABEL: 'Videos',
+  MEDIA_VIEW_AUDIO_ROOT_LABEL: 'Audio',
 };
 
 function setUp() {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
index 45ed768..058fa4b 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/ui/BUILD.gn
@@ -302,6 +302,7 @@
 js_library("location_line") {
   deps = [
     "..:volume_manager_wrapper",
+    "../../../common/js:files_app_entry_types",
     "../../../common/js:metrics",
     "../../../common/js:util",
     "../../../common/js:volume_manager_common",
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index 29d57bf..0f77164 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -145,6 +145,10 @@
   // prototype.
   var labelId = item.labelElement.id;
   item.__proto__ = DirectoryItem.prototype;
+  if (window.IN_TEST) {
+    item.setAttribute('dir-type', 'DirectoryItem');
+    item.setAttribute('entry-label', label);
+  }
   item.parentTree_ = tree;
   item.directoryModel_ = tree.directoryModel;
   item.fileFilter_ = tree.directoryModel.getFileFilter();
@@ -536,6 +540,8 @@
   var item = new DirectoryItem(label, tree);
   item.__proto__ = SubDirectoryItem.prototype;
 
+  if (window.IN_TEST)
+    item.setAttribute('dir-type', 'SubDirectoryItem');
   item.entry = dirEntry;
   item.delayExpansion = parentDirItem.delayExpansion;
 
@@ -595,6 +601,96 @@
       });
 };
 
+/**
+ * A directory of entries. Each element represents an entry.
+ *
+ * @param {VolumeManagerCommon.RootType} rootType The root type to record.
+ * @param {!NavigationModelFakeItem} modelItem NavigationModelItem of this
+ *     volume.
+ * @param {DirectoryTree} tree Current tree, which contains this item.
+ * @extends {DirectoryItem}
+ * @constructor
+ */
+function EntryListItem(rootType, modelItem, tree) {
+  var item = new DirectoryItem(modelItem.label, tree);
+  // Get the original label id defined by TreeItem, before overwriting
+  // prototype.
+  item.__proto__ = EntryListItem.prototype;
+  if (window.IN_TEST)
+    item.setAttribute('dir-type', 'EntryListItem');
+  item.entries_ = [];
+
+  item.rootType_ = rootType;
+  item.modelItem_ = modelItem;
+  item.dirEntry_ = modelItem.entry;
+  item.parentTree_ = tree;
+
+  var icon = queryRequiredElement('.icon', item);
+  icon.classList.add('item-icon');
+  item.setAttribute('root-type-icon', rootType);
+  return item;
+}
+
+EntryListItem.prototype = {
+  __proto__: DirectoryItem.prototype,
+
+  /**
+   * The DirectoryEntry corresponding to this DirectoryItem. This may be
+   * a dummy DirectoryEntry.
+   * @type {DirectoryEntry|Object}
+   */
+  get entry() {
+    return this.dirEntry_;
+  },
+
+  /**
+   * The element containing the label text and the icon.
+   * @type {!HTMLElement}
+   * @override
+   */
+  get labelElement() {
+    return this.firstElementChild.querySelector('.label');
+  },
+
+  /**
+   * @type {!NavigationModelVolumeItem}
+   */
+  get modelItem() {
+    return this.modelItem_;
+  }
+};
+
+/**
+ * Retrieves the subdirectories and update them on the tree. Runs synchronously,
+ *     since EntryList has its subdirectories already in memory.
+ * @param {boolean} recursive True if the update is recursively.
+ * @param {function()=} opt_successCallback Callback called on success.
+ * @param {function()=} opt_errorCallback Callback called on error.
+ */
+EntryListItem.prototype.updateSubDirectories = function(
+    recursive, opt_successCallback, opt_errorCallback) {
+  if (!this.entry) {
+    opt_errorCallback && opt_errorCallback();
+    return;
+  }
+  this.entries_ = [];
+  if (this.entry && this.entry.children) {
+    for (let childEntry of this.entry.children) {
+      if (childEntry instanceof VolumeEntry) {
+        // For VolumeEntry we wan't to display its root.
+        this.entries_.push(childEntry.rootEntry);
+      } else {
+        this.entries_.push(childEntry);
+      }
+    }
+  }
+  if (this.entries_.length > 0) {
+    this.expanded = true;
+  }
+  this.updateSubElementsFromList(recursive);
+  opt_successCallback && opt_successCallback();
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // VolumeItem
 
@@ -621,8 +717,10 @@
   item.delayExpansion = (item.volumeInfo.volumeType === 'provided');
 
   // Set helper attribute for testing.
-  if (window.IN_TEST)
+  if (window.IN_TEST) {
     item.setAttribute('volume-type-for-testing', item.volumeInfo_.volumeType);
+    item.setAttribute('dir-type', 'VolumeItem');
+  }
 
   item.setupIcon_(item.querySelector('.icon'), item.volumeInfo_);
 
@@ -797,6 +895,8 @@
   var item = new VolumeItem(modelItem, tree);
   item.__proto__ = DriveVolumeItem.prototype;
   item.classList.add('drive-volume');
+  if (window.IN_TEST)
+    item.setAttribute('dir-type', 'DriveVolumeItem');
   return item;
 }
 
@@ -960,6 +1060,8 @@
   var labelId = item.labelElement.id;
   item.__proto__ = ShortcutItem.prototype;
 
+  if (window.IN_TEST)
+    item.setAttribute('dir-type', 'ShortcutItem');
   item.parentTree_ = tree;
   item.dirEntry_ = modelItem.entry;
   item.modelItem_ = modelItem;
@@ -1093,6 +1195,10 @@
   // prototype.
   var labelId = item.labelElement.id;
   item.__proto__ = MenuItem.prototype;
+  if (window.IN_TEST) {
+    item.setAttribute('dir-type', 'MenuItem');
+    item.setAttribute('entry-label', modelItem.label);
+  }
 
   item.parentTree_ = tree;
   item.modelItem_ = modelItem;
@@ -1177,6 +1283,10 @@
   // prototype.
   var labelId = item.labelElement.id;
   item.__proto__ = FakeItem.prototype;
+  if (window.IN_TEST) {
+    item.setAttribute('dir-type', 'FakeItem');
+    item.setAttribute('entry-label', modelItem.label);
+  }
 
   item.rootType_ = rootType;
   item.parentTree_ = tree;
@@ -1185,6 +1295,7 @@
   item.innerHTML = TREE_ITEM_INNER_HTML;
   item.labelElement.id = labelId;
   item.label = modelItem.label;
+  item.directoryModel_ = tree.directoryModel;
 
   var icon = queryRequiredElement('.icon', item);
   icon.classList.add('item-icon');
@@ -1239,6 +1350,15 @@
   this.parentTree_.directoryModel.activateDirectoryEntry(this.entry);
 };
 
+/**
+ * FakeItem doesn't really have sub-directories, it's defined here only to have
+ * the same API of other Items on this file.
+ */
+FakeItem.prototype.updateSubDirectories = function(
+    recursive, opt_successCallback, opt_errorCallback) {
+  return opt_successCallback && opt_successCallback();
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // DirectoryTree
 
@@ -1336,6 +1456,53 @@
 cr.defineProperty(DirectoryTree, 'contextMenuForRootItems', cr.PropertyKind.JS);
 
 /**
+ * Creates a new DirectoryItem based on |modelItem|.
+ * @param {NavigationModelItem} modelItem, model that will determine the type of
+ *     DirectoryItem to be created.
+ * @param {!DirectoryTree} tree The tree to add the new DirectoryItem to.
+ * @return {!cr.ui.TreeItem} a newly created instance of a
+ *     DirectoryItem type.
+ */
+DirectoryTree.createDirectoryItem = function(modelItem, tree) {
+  switch (modelItem.type) {
+    case NavigationModelItemType.VOLUME:
+      const volumeModelItem =
+          /** @type {NavigationModelVolumeItem} */ (modelItem);
+      if (volumeModelItem.volumeInfo.volumeType ===
+          VolumeManagerCommon.VolumeType.DRIVE) {
+        return new DriveVolumeItem(volumeModelItem, tree);
+      } else {
+        return new VolumeItem(volumeModelItem, tree);
+      }
+      break;
+    case NavigationModelItemType.SHORTCUT:
+      return new ShortcutItem(
+          /** @type {!NavigationModelShortcutItem} */ (modelItem), tree);
+      break;
+    case NavigationModelItemType.MENU:
+      return new MenuItem(
+          /** @type {!NavigationModelMenuItem} */ (modelItem), tree);
+      break;
+    case NavigationModelItemType.RECENT:
+      return new FakeItem(
+          VolumeManagerCommon.RootType.RECENT,
+          /** @type {!NavigationModelFakeItem} */ (modelItem), tree);
+      break;
+    case NavigationModelItemType.CROSTINI:
+      return new FakeItem(
+          VolumeManagerCommon.RootType.CROSTINI,
+          /** @type {!NavigationModelFakeItem} */ (modelItem), tree);
+      break;
+    case NavigationModelItemType.ENTRY_LIST:
+      return new EntryListItem(
+          VolumeManagerCommon.RootType.MY_FILES,
+          /** @type {!NavigationModelFakeItem} */ (modelItem), tree);
+      break;
+  }
+  assertNotReached(`No DirectoryItem model: "${modelItem.type}"`);
+};
+
+/**
  * Updates and selects new directory.
  * @param {!DirectoryEntry} parentDirectory Parent directory of new directory.
  * @param {!DirectoryEntry} newDirectory
@@ -1409,33 +1576,10 @@
         this.items[itemIndex].updateSubDirectories(true);
     } else {
       var modelItem = this.dataModel.item(modelIndex);
-      switch (modelItem.type) {
-        case NavigationModelItemType.VOLUME:
-          if (modelItem.volumeInfo.volumeType ===
-              VolumeManagerCommon.VolumeType.DRIVE) {
-            this.addAt(new DriveVolumeItem(modelItem, this), itemIndex);
-          } else {
-            this.addAt(new VolumeItem(modelItem, this), itemIndex);
-          }
-          break;
-        case NavigationModelItemType.SHORTCUT:
-          this.addAt(new ShortcutItem(modelItem, this), itemIndex);
-          break;
-        case NavigationModelItemType.MENU:
-          this.addAt(new MenuItem(modelItem, this), itemIndex);
-          break;
-        case NavigationModelItemType.RECENT:
-          this.addAt(
-              new FakeItem(
-                  VolumeManagerCommon.RootType.RECENT, modelItem, this),
-              itemIndex);
-          break;
-        case NavigationModelItemType.CROSTINI:
-          this.addAt(
-              new FakeItem(
-                  VolumeManagerCommon.RootType.CROSTINI, modelItem, this),
-              itemIndex);
-          break;
+      if (modelItem) {
+        var item = DirectoryTree.createDirectoryItem(modelItem, this);
+        if (item)
+          this.addAt(item, itemIndex);
       }
     }
     itemIndex++;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/location_line.js b/ui/file_manager/file_manager/foreground/js/ui/location_line.js
index 9ca44ca..030562f 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/location_line.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/location_line.js
@@ -60,7 +60,7 @@
 
 /**
  * Get components for the path of entry.
- * @param {!Entry|!FakeEntry} entry An entry.
+ * @param {!Entry|!FakeEntry|!FilesAppEntry} entry An entry.
  * @return {!Array<!LocationLine.PathComponent>} Components.
  * @private
  */
diff --git a/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js b/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js
index c93f184..4a3696e 100644
--- a/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js
+++ b/ui/file_manager/file_manager/foreground/js/volume_manager_wrapper.js
@@ -300,7 +300,7 @@
 /**
  * Obtains location information from an entry.
  *
- * @param {(!Entry|!FakeEntry)} entry File or directory entry.
+ * @param {(!Entry|!FakeEntry|!FilesAppEntry)} entry File or directory entry.
  * @return {EntryLocation} Location information.
  */
 VolumeManagerWrapper.prototype.getLocationInfo = function(entry) {
diff --git a/ui/file_manager/integration_tests/file_manager/context_menu.js b/ui/file_manager/integration_tests/file_manager/context_menu.js
index afe91335..737fe44 100644
--- a/ui/file_manager/integration_tests/file_manager/context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/context_menu.js
@@ -15,6 +15,9 @@
  * TODO(sashab): Generate the entries used in these tests at runtime, by
  * creating entries with pre-set combinations of permissions and ensuring the
  * outcome is always as expected.
+ *
+ * TODO(sashab): Once Team Drives is enabled, add tests for team drive roots
+ * and entries as well.
  */
 
 /**
@@ -199,6 +202,44 @@
 };
 
 /**
+ * Tests that the Share menu item is enabled if a read-write entry is selected.
+ */
+testcase.checkShareEnabledForReadWriteFile = function() {
+  checkContextMenu('share', 'hello.txt', true);
+};
+
+/**
+ * Tests that the Share menu item is enabled if a read-only document is
+ * selected.
+ */
+testcase.checkShareEnabledForReadOnlyDocument = function() {
+  checkContextMenu('share', 'Read-Only Doc.gdoc', true);
+};
+
+/**
+ * Tests that the Share menu item is disabled if a strict read-only document is
+ * selected.
+ */
+testcase.checkShareDisabledForStrictReadOnlyDocument = function() {
+  checkContextMenu('share', 'Read-Only (Strict) Doc.gdoc', false);
+};
+
+/**
+ * Tests that the Share menu item is enabled if a read-only file is selected.
+ */
+testcase.checkShareEnabledForReadOnlyFile = function() {
+  checkContextMenu('share', 'Read-Only File.jpg', true);
+};
+
+/**
+ * Tests that the Share menu item is enabled if a read-only folder is
+ * selected.
+ */
+testcase.checkShareEnabledForReadOnlyFolder = function() {
+  checkContextMenu('share', 'Read-Only Folder', true);
+};
+
+/**
  * Tests that the Copy menu item is enabled if a read-write entry is selected.
  */
 testcase.checkCopyEnabledForReadWriteFile = function() {
diff --git a/ui/file_manager/integration_tests/file_manager/my_files.js b/ui/file_manager/integration_tests/file_manager/my_files.js
new file mode 100644
index 0000000..ccbe555
--- /dev/null
+++ b/ui/file_manager/integration_tests/file_manager/my_files.js
@@ -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.
+
+/**
+ * Tests if MyFiles is displayed when flag is true.
+ */
+testcase.showMyFiles = function() {
+  let appId;
+
+  const expectedElementLabels = [
+    'Recent: FakeItem',
+    'My Files: EntryListItem',
+    'Downloads: SubDirectoryItem',
+    'Linux Files: SubDirectoryItem',
+    'Google Drive: DriveVolumeItem',
+    'My Drive: SubDirectoryItem',
+    'Shared with me: SubDirectoryItem',
+    'Offline: SubDirectoryItem',
+    'Add new services: MenuItem',
+  ];
+
+  StepsRunner.run([
+    // Open Files app on local Downloads.
+    function() {
+      setupAndWaitUntilReady(
+          null, RootPath.DOWNLOADS, this.next, [ENTRIES.beautiful], []);
+    },
+    // Get the directory tree elements.
+    function(results) {
+      appId = results.windowId;
+      const dirTreeQuery = ['#directory-tree [dir-type]'];
+      remoteCall.callRemoteTestUtil('queryAllElements', appId, dirTreeQuery)
+          .then(this.next);
+    },
+    // Check tree elements for the correct order and label/element type.
+    function(elements) {
+      var visibleElements = [];
+      for (let element of elements) {
+        if (!element.hidden) {  // Ignore hidden elements.
+          visibleElements.push(
+              element.attributes['entry-label'] + ': ' +
+              element.attributes['dir-type']);
+        }
+      }
+      chrome.test.assertEq(expectedElementLabels, visibleElements);
+      this.next();
+    },
+    function() {
+      checkIfNoErrorsOccured(this.next);
+    },
+  ]);
+};
diff --git a/ui/file_manager/integration_tests/file_manager/open_audio_files.js b/ui/file_manager/integration_tests/file_manager/open_audio_files.js
index ad35014..2b46217 100644
--- a/ui/file_manager/integration_tests/file_manager/open_audio_files.js
+++ b/ui/file_manager/integration_tests/file_manager/open_audio_files.js
@@ -7,21 +7,6 @@
 (function() {
 
 /**
- * Returns an array of file entry row content, where the rows are the basic
- * file entry set for the given path, plus the given file |entries|.
- *
- * @param {string} path Directory path (Downloads or Drive).
- * @pram {Array<!TestEntryInfo>} entries Array of file TestEntryInfo.
- * @return {Array} File entry row content.
- */
-function getExpectedFileEntryRows(path, entries) {
-  const basicFileEntrySetForPath =
-      (path == RootPath.DRIVE) ? BASIC_DRIVE_ENTRY_SET : BASIC_LOCAL_ENTRY_SET;
-  return TestEntryInfo.getExpectedRows(basicFileEntrySetForPath)
-      .concat(TestEntryInfo.getExpectedRows(entries));
-}
-
-/**
  * Returns the title and artist text associated with the given audio track.
  *
  * @param {string} audioAppId The Audio Player window ID.
@@ -135,7 +120,7 @@
   const track = [ENTRIES.beautiful];
 
   StepsRunner.run([
-    // Open Files.App on Downloads, add an audio track to Downloads.
+    // Open Files.App on Downloads, add an audio file to Downloads.
     function() {
       setupAndWaitUntilReady(null, RootPath.DOWNLOADS, this.next, track, []);
     },
@@ -184,7 +169,7 @@
   const tracks = [ENTRIES.beautiful, ENTRIES.newlyAdded];
 
   StepsRunner.run([
-    // Open Files.App on Drive, add the audio tracks to Drive.
+    // Open Files.App on Drive, add the audio files to Drive.
     function() {
       setupAndWaitUntilReady(null, RootPath.DRIVE, this.next, [], tracks);
     },
@@ -255,7 +240,8 @@
 }
 
 /**
- * Tests if the audio player play the next file after the current file.
+ * Tests that the audio player auto-advances viz., auto-plays the next audio
+ * track when the current track ends.
  *
  * @param {string} path Directory path to be tested.
  */
@@ -263,24 +249,16 @@
   let appId;
   let audioAppId;
 
+  const tracks = [ENTRIES.beautiful, ENTRIES.newlyAdded];
+
   StepsRunner.run([
-    // Open Files.App on the given (volume) path.
+    // Open Files.App on |path|, add audio files to Downloads and Drive.
     function() {
-      setupAndWaitUntilReady(null, path, this.next);
-    },
-    // Add an additional audio file.
-    function(results) {
-      appId = results.windowId;
-      addEntries(['local', 'drive'], [ENTRIES.newlyAdded], this.next);
-    },
-    // Wait for the file list to change.
-    function(result) {
-      chrome.test.assertTrue(result);
-      const expected = getExpectedFileEntryRows(path, [ENTRIES.newlyAdded]);
-      remoteCall.waitForFiles(appId, expected).then(this.next);
+      setupAndWaitUntilReady(null, path, this.next, tracks, tracks);
     },
     // Open an audio file.
-    function() {
+    function(results) {
+      appId = results.windowId;
       remoteCall.callRemoteTestUtil(
           'openFile', appId, ['Beautiful Song.ogg'], this.next);
     },
@@ -295,9 +273,13 @@
       const playFile = audioPlayingQuery('Beautiful Song.ogg');
       audioPlayerApp.waitForElement(audioAppId, playFile).then(this.next);
     },
-    // Leap forward and check: the same file should still be playing.
+    // Leap forward in time.
     function() {
       audioTimeLeapForward(audioAppId);
+      this.next();
+    },
+    // Check: the same file should still be playing.
+    function() {
       const playFile = audioPlayingQuery('Beautiful Song.ogg');
       audioPlayerApp.waitForElement(audioAppId, playFile).then(this.next);
     },
@@ -321,10 +303,12 @@
   let appId;
   let audioAppId;
 
+  const track = [ENTRIES.beautiful];
+
   StepsRunner.run([
-    // Open Files.App on the given (volume) path.
+    // Open Files.App on |path|, add an audio file to Downloads and Drive.
     function() {
-      setupAndWaitUntilReady(null, path, this.next);
+      setupAndWaitUntilReady(null, path, this.next, track, track);
     },
     // Open an audio file.
     function(results) {
@@ -382,10 +366,12 @@
   let appId;
   let audioAppId;
 
+  const track = [ENTRIES.beautiful];
+
   StepsRunner.run([
-    // Open Files.App on the given (volume) path.
+    // Open Files.App on |path|, add an audio file to Downloads and Drive.
     function() {
-      setupAndWaitUntilReady(null, path, this.next);
+      setupAndWaitUntilReady(null, path, this.next, track, track);
     },
     // Open an audio file.
     function(results) {
@@ -435,10 +421,12 @@
   let appId;
   let audioAppId;
 
+  const track = [ENTRIES.beautiful];
+
   StepsRunner.run([
-    // Open Files.App on the given (volume) path.
+    // Open Files.App on |path|, add an audio file to Downloads and Drive.
     function() {
-      setupAndWaitUntilReady(null, path, this.next);
+      setupAndWaitUntilReady(null, path, this.next, track, track);
     },
     // Open an audio file.
     function(results) {
@@ -503,24 +491,16 @@
   let appId;
   let audioAppId;
 
+  const tracks = [ENTRIES.beautiful, ENTRIES.newlyAdded];
+
   StepsRunner.run([
-    // Open Files.App on the given (volume) path.
+    // Open Files.App on |path|, add audio files to Downloads and Drive.
     function() {
-      setupAndWaitUntilReady(null, path, this.next);
-    },
-    // Add an additional audio file.
-    function(results) {
-      appId = results.windowId;
-      addEntries(['local', 'drive'], [ENTRIES.newlyAdded], this.next);
-    },
-    // Wait for the file list to change.
-    function(result) {
-      chrome.test.assertTrue(result);
-      const expected = getExpectedFileEntryRows(path, [ENTRIES.newlyAdded]);
-      remoteCall.waitForFiles(appId, expected).then(this.next);
+      setupAndWaitUntilReady(null, path, this.next, tracks, tracks);
     },
     // Open an audio file.
-    function() {
+    function(results) {
+      appId = results.windowId;
       remoteCall.callRemoteTestUtil(
           'openFile', appId, ['newly added file.ogg'], this.next);
     },
@@ -583,24 +563,16 @@
   let appId;
   let audioAppId;
 
+  const tracks = [ENTRIES.beautiful, ENTRIES.newlyAdded];
+
   StepsRunner.run([
-    // Open Files.App on the given (volume) path.
+    // Open Files.App on |path|, add audio files to Downloads and Drive.
     function() {
-      setupAndWaitUntilReady(null, path, this.next);
-    },
-    // Add an additional audio file.
-    function(results) {
-      appId = results.windowId;
-      addEntries(['local', 'drive'], [ENTRIES.newlyAdded], this.next);
-    },
-    // Wait for the file list to change.
-    function(result) {
-      chrome.test.assertTrue(result);
-      const expected = getExpectedFileEntryRows(path, [ENTRIES.newlyAdded]);
-      remoteCall.waitForFiles(appId, expected).then(this.next);
+      setupAndWaitUntilReady(null, path, this.next, tracks, tracks);
     },
     // Open an audio file.
-    function() {
+    function(results) {
+      appId = results.windowId;
       remoteCall.callRemoteTestUtil(
           'openFile', appId, ['newly added file.ogg'], this.next);
     },
@@ -646,23 +618,16 @@
   let appId;
   let audioAppId;
 
+  const tracks = [ENTRIES.beautiful, ENTRIES.newlyAdded];
+
   StepsRunner.run([
-    // Open Files.App on the given (volume) path.
+    // Open Files.App on |path|, add audio files to Downloads and Drive.
     function() {
-      setupAndWaitUntilReady(null, path, this.next);
-    },
-    // Add an additional audio file.
-    function(results) {
-      appId = results.windowId;
-      addEntries(['local', 'drive'], [ENTRIES.newlyAdded], this.next);
-    },
-    // Wait for the file list to change.
-    function(result) {
-      const expected = getExpectedFileEntryRows(path, [ENTRIES.newlyAdded]);
-      remoteCall.waitForFiles(appId, expected).then(this.next);
+      setupAndWaitUntilReady(null, path, this.next, tracks, tracks);
     },
     // Open an audio file.
-    function() {
+    function(results) {
+      appId = results.windowId;
       remoteCall.callRemoteTestUtil(
           'openFile', appId, ['newly added file.ogg'], this.next);
     },
diff --git a/ui/file_manager/integration_tests/file_manager_test_manifest.json b/ui/file_manager/integration_tests/file_manager_test_manifest.json
index c2c38acc..f096302 100644
--- a/ui/file_manager/integration_tests/file_manager_test_manifest.json
+++ b/ui/file_manager/integration_tests/file_manager_test_manifest.json
@@ -27,6 +27,7 @@
       "file_manager/gear_menu.js",
       "file_manager/grid_view.js",
       "file_manager/keyboard_operations.js",
+      "file_manager/my_files.js",
       "file_manager/open_audio_files.js",
       "file_manager/open_image_files.js",
       "file_manager/open_video_files.js",
diff --git a/ui/file_manager/integration_tests/gallery/slide_mode.js b/ui/file_manager/integration_tests/gallery/slide_mode.js
index da2bc604..69dd9a3 100644
--- a/ui/file_manager/integration_tests/gallery/slide_mode.js
+++ b/ui/file_manager/integration_tests/gallery/slide_mode.js
@@ -149,7 +149,9 @@
   return launchedPromise
       .then(function(result) {
         appId = result.appId;
-        return gallery.waitForElement(appId, '.gallery[mode="slide"]');
+        // The buttons are disabled in the static gallery.html DOM, so wait for
+        // the image to be fully loaded before querying the button state.
+        return gallery.waitForSlideImage(appId, 640, 480, 'image3');
       })
       .then(function() {
         return gallery.callRemoteTestUtil(
diff --git a/ui/message_center/ui_controller.cc b/ui/message_center/ui_controller.cc
index 15722431..af66d5f 100644
--- a/ui/message_center/ui_controller.cc
+++ b/ui/message_center/ui_controller.cc
@@ -157,7 +157,8 @@
 }
 
 void UiController::OnMessageCenterChanged() {
-  if (message_center_visible_ && message_center_->NotificationCount() == 0) {
+  if (hide_on_last_notification_ && message_center_visible_ &&
+      message_center_->NotificationCount() == 0) {
     HideMessageCenterBubble();
     return;
   }
diff --git a/ui/message_center/ui_controller.h b/ui/message_center/ui_controller.h
index 5b489e0..b5443d0 100644
--- a/ui/message_center/ui_controller.h
+++ b/ui/message_center/ui_controller.h
@@ -54,6 +54,9 @@
   UiDelegate* delegate() { return delegate_; }
   const MessageCenter* message_center() const { return message_center_; }
   MessageCenter* message_center() { return message_center_; }
+  void set_hide_on_last_notification(bool hide_on_last_notification) {
+    hide_on_last_notification_ = hide_on_last_notification;
+  }
 
   // Overridden from MessageCenterObserver:
   void OnNotificationAdded(const std::string& notification_id) override;
@@ -80,6 +83,9 @@
   bool popups_visible_ = false;
   UiDelegate* delegate_;
 
+  // Set true to hide MessageCenterView when the last notification is dismissed.
+  bool hide_on_last_notification_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(UiController);
 };
 
diff --git a/ui/ozone/platform/headless/BUILD.gn b/ui/ozone/platform/headless/BUILD.gn
index 848391d0..500d15e6 100644
--- a/ui/ozone/platform/headless/BUILD.gn
+++ b/ui/ozone/platform/headless/BUILD.gn
@@ -10,6 +10,8 @@
     "client_native_pixmap_factory_headless.h",
     "gl_surface_osmesa_png.cc",
     "gl_surface_osmesa_png.h",
+    "headless_native_display_delegate.cc",
+    "headless_native_display_delegate.h",
     "headless_surface_factory.cc",
     "headless_surface_factory.h",
     "headless_window.cc",
diff --git a/ui/ozone/platform/headless/headless_native_display_delegate.cc b/ui/ozone/platform/headless/headless_native_display_delegate.cc
new file mode 100644
index 0000000..a4ca1d32
--- /dev/null
+++ b/ui/ozone/platform/headless/headless_native_display_delegate.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 "ui/ozone/platform/headless/headless_native_display_delegate.h"
+
+#include "ui/display/types/display_snapshot.h"
+#include "ui/display/types/native_display_observer.h"
+
+namespace ui {
+
+namespace {
+constexpr gfx::Size kDefaultWindowSize(800, 600);
+constexpr int default_refresh = 60;
+}  // namespace
+
+HeadlessNativeDisplayDelegate::HeadlessNativeDisplayDelegate() = default;
+
+HeadlessNativeDisplayDelegate::~HeadlessNativeDisplayDelegate() = default;
+
+void HeadlessNativeDisplayDelegate::Initialize() {
+  // This shouldn't be called twice.
+  DCHECK(!current_snapshot_);
+
+  if (next_display_id_ == std::numeric_limits<int64_t>::max()) {
+    LOG(FATAL) << "Exceeded display id limit";
+    return;
+  }
+
+  display::DisplaySnapshot::DisplayModeList modes;
+  std::unique_ptr<display::DisplayMode> display_mode =
+      std::make_unique<display::DisplayMode>(kDefaultWindowSize, false,
+                                             default_refresh);
+  modes.push_back(std::move(display_mode));
+  const display::DisplayMode* mode = modes.back().get();
+
+  current_snapshot_ = std::make_unique<display::DisplaySnapshot>(
+      next_display_id(), gfx::Point(0, 0), kDefaultWindowSize,
+      display::DisplayConnectionType::DISPLAY_CONNECTION_TYPE_NONE, false,
+      false, false, false, gfx::ColorSpace(), "", base::FilePath(),
+      std::move(modes), std::vector<uint8_t>(), mode, mode, 0, 0, gfx::Size());
+
+  for (display::NativeDisplayObserver& observer : observers_)
+    observer.OnConfigurationChanged();
+}
+
+void HeadlessNativeDisplayDelegate::TakeDisplayControl(
+    display::DisplayControlCallback callback) {
+  NOTREACHED();
+}
+
+void HeadlessNativeDisplayDelegate::RelinquishDisplayControl(
+    display::DisplayControlCallback callback) {
+  NOTREACHED();
+}
+
+void HeadlessNativeDisplayDelegate::GetDisplays(
+    display::GetDisplaysCallback callback) {
+  std::vector<display::DisplaySnapshot*> snapshot;
+  snapshot.push_back(current_snapshot_.get());
+  std::move(callback).Run(snapshot);
+}
+
+void HeadlessNativeDisplayDelegate::Configure(
+    const display::DisplaySnapshot& output,
+    const display::DisplayMode* mode,
+    const gfx::Point& origin,
+    display::ConfigureCallback callback) {
+  NOTIMPLEMENTED();
+
+  // It should call |callback| after configuration.
+  // Even if we don't have implementation, it calls |callback| to finish the
+  // logic.
+  std::move(callback).Run(true);
+}
+
+void HeadlessNativeDisplayDelegate::GetHDCPState(
+    const display::DisplaySnapshot& output,
+    display::GetHDCPStateCallback callback) {
+  NOTREACHED();
+}
+
+void HeadlessNativeDisplayDelegate::SetHDCPState(
+    const display::DisplaySnapshot& output,
+    display::HDCPState state,
+    display::SetHDCPStateCallback callback) {
+  NOTREACHED();
+}
+
+bool HeadlessNativeDisplayDelegate::SetColorMatrix(
+    int64_t display_id,
+    const std::vector<float>& color_matrix) {
+  NOTREACHED();
+  return false;
+}
+
+bool HeadlessNativeDisplayDelegate::SetGammaCorrection(
+    int64_t display_id,
+    const std::vector<display::GammaRampRGBEntry>& degamma_lut,
+    const std::vector<display::GammaRampRGBEntry>& gamma_lut) {
+  NOTREACHED();
+  return false;
+}
+
+void HeadlessNativeDisplayDelegate::AddObserver(
+    display::NativeDisplayObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void HeadlessNativeDisplayDelegate::RemoveObserver(
+    display::NativeDisplayObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+display::FakeDisplayController*
+HeadlessNativeDisplayDelegate::GetFakeDisplayController() {
+  return nullptr;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/headless/headless_native_display_delegate.h b/ui/ozone/platform/headless/headless_native_display_delegate.h
new file mode 100644
index 0000000..af815a7
--- /dev/null
+++ b/ui/ozone/platform/headless/headless_native_display_delegate.h
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_HEADLESS_HEADLESS_NATIVE_DISPLAY_DELEGATE_H_
+#define UI_OZONE_PLATFORM_HEADLESS_HEADLESS_NATIVE_DISPLAY_DELEGATE_H_
+
+#include "base/observer_list.h"
+#include "ui/display/types/native_display_delegate.h"
+
+namespace display {
+class DisplayMode;
+class DisplaySnapshot;
+}  // namespace display
+
+namespace ui {
+
+class HeadlessNativeDisplayDelegate : public display::NativeDisplayDelegate {
+ public:
+  HeadlessNativeDisplayDelegate();
+  ~HeadlessNativeDisplayDelegate() override;
+
+  // display::NativeDisplayDelegate overrides:
+  void Initialize() override;
+  void TakeDisplayControl(display::DisplayControlCallback callback) override;
+  void RelinquishDisplayControl(
+      display::DisplayControlCallback callback) override;
+  void GetDisplays(display::GetDisplaysCallback callback) override;
+  void Configure(const display::DisplaySnapshot& output,
+                 const display::DisplayMode* mode,
+                 const gfx::Point& origin,
+                 display::ConfigureCallback callback) override;
+  void GetHDCPState(const display::DisplaySnapshot& output,
+                    display::GetHDCPStateCallback callback) override;
+  void SetHDCPState(const display::DisplaySnapshot& output,
+                    display::HDCPState state,
+                    display::SetHDCPStateCallback callback) override;
+  bool SetColorMatrix(int64_t display_id,
+                      const std::vector<float>& color_matrix) override;
+  bool SetGammaCorrection(
+      int64_t display_id,
+      const std::vector<display::GammaRampRGBEntry>& degamma_lut,
+      const std::vector<display::GammaRampRGBEntry>& gamma_lut) override;
+  void AddObserver(display::NativeDisplayObserver* observer) override;
+  void RemoveObserver(display::NativeDisplayObserver* observer) override;
+  display::FakeDisplayController* GetFakeDisplayController() override;
+
+ private:
+  int64_t next_display_id() { return next_display_id_++; }
+  std::unique_ptr<display::DisplaySnapshot> current_snapshot_;
+
+  base::ObserverList<display::NativeDisplayObserver> observers_;
+
+  // The next available display id.
+  int64_t next_display_id_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(HeadlessNativeDisplayDelegate);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_HEADLESS_HEADLESS_NATIVE_DISPLAY_DELEGATE_H_
diff --git a/ui/ozone/platform/headless/ozone_platform_headless.cc b/ui/ozone/platform/headless/ozone_platform_headless.cc
index 3abad66..3e22233 100644
--- a/ui/ozone/platform/headless/ozone_platform_headless.cc
+++ b/ui/ozone/platform/headless/ozone_platform_headless.cc
@@ -8,12 +8,12 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "ui/base/cursor/ozone/bitmap_cursor_factory_ozone.h"
-#include "ui/display/manager/fake_display_delegate.h"
 #include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
 #include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/events/system_input_injector.h"
 #include "ui/ozone/common/stub_overlay_manager.h"
+#include "ui/ozone/platform/headless/headless_native_display_delegate.h"
 #include "ui/ozone/platform/headless/headless_surface_factory.h"
 #include "ui/ozone/platform/headless/headless_window.h"
 #include "ui/ozone/platform/headless/headless_window_manager.h"
@@ -74,7 +74,7 @@
   }
   std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
       override {
-    return std::make_unique<display::FakeDisplayDelegate>();
+    return std::make_unique<HeadlessNativeDisplayDelegate>();
   }
 
   void InitializeUI(const InitParams& params) override {
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
index 679e3a8..0d1601a 100644
--- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
+++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
@@ -16,7 +16,6 @@
         color: #fff;
         display: flex;
         height: var(--cr-toolbar-height);
-        transition: visibility var(--cr-toolbar-overlay-animation-duration);
       }
 
       h1 {
@@ -64,6 +63,7 @@
       }
 
       :host([has-overlay]) {
+        transition: visibility var(--cr-toolbar-overlay-animation-duration);
         visibility: hidden;
       }