diff --git a/.gitignore b/.gitignore
index aaf4bf7..b312630 100644
--- a/.gitignore
+++ b/.gitignore
@@ -202,10 +202,8 @@
 /llvm
 /media/cast/logging/cast_logging_proto_lib.xml
 /media/cdm/api
-/media/media_asm.xml
 /media/media_mojo_bindings.xml
 /media/test/data/internal
-/media/yuv_convert_simd_x86.xml
 /metro_driver
 /mojo/hello_world_service.xml
 /mojo/mojo_application_bindings.xml
diff --git a/DEPS b/DEPS
index 4fa1bd77..998856fc 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'e4fd9d0463b219170d5d6507955906825fbf8fc6',
+  'skia_revision': '936f81b95882be2e171a623b3116cc2ff408c813',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'd4ba150d246eee3a295dc9f062e1c2a5bcb501a1',
+  'v8_revision': '333a5972586e2b246ceceef19b1afaf8fe06ec9e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -52,7 +52,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '875bbba0eeed060d479547c601707454689f98b5',
+  'angle_revision': 'ceb1048fd25faf4f191e30222dfd7d0b813fb976',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '5fb0ad8adac5fcbf8c8f1965164f41d11c0af669',
+  'pdfium_revision': 'f0b65545313f065790de7f91c02e5dd160753abd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '6fa9f83f7490d8d12e32e1386cd1fd8e08462e47',
+  'catapult_revision': '79fa79eb4b20030861f9c1f327194976e6c7f7a6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -205,7 +205,7 @@
     Var('chromium_git') + '/webm/libvpx.git' + '@' +  '91f87e75135cc9722ee72daf5154424f628a906e',
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'a77cdbfeb7b629eb3a5012d7c6c94ef11e0488be',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '38d84d205cd89cb9ce740735d2d31d4bc2a07abb',
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '8679f2b0bf063ac894dc473debefd61dbbebf622',
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 558311b..45ab2d0 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -416,7 +416,7 @@
     const content::Referrer& referrer,
     const std::string& frame_name,
     WindowOpenDisposition disposition,
-    const blink::WebWindowFeatures& features,
+    const blink::mojom::WindowFeatures& features,
     bool user_gesture,
     bool opener_suppressed,
     content::ResourceContext* context,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h
index f02c6d2..8dcff05 100644
--- a/android_webview/browser/aw_content_browser_client.h
+++ b/android_webview/browser/aw_content_browser_client.h
@@ -101,7 +101,7 @@
                        const content::Referrer& referrer,
                        const std::string& frame_name,
                        WindowOpenDisposition disposition,
-                       const blink::WebWindowFeatures& features,
+                       const blink::mojom::WindowFeatures& features,
                        bool user_gesture,
                        bool opener_suppressed,
                        content::ResourceContext* context,
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index 7f85fa9c..93f5155 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -16,9 +16,9 @@
 #include "cc/output/texture_mailbox_deleter.h"
 #include "cc/quads/surface_draw_quad.h"
 #include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/display.h"
 #include "cc/surfaces/display_scheduler.h"
-#include "cc/surfaces/surface_factory.h"
 #include "cc/surfaces/surface_id_allocator.h"
 #include "cc/surfaces/surface_manager.h"
 #include "ui/gfx/geometry/rect.h"
@@ -51,9 +51,9 @@
 
   surface_manager_.reset(new cc::SurfaceManager);
   surface_id_allocator_.reset(new cc::SurfaceIdAllocator());
-  surface_manager_->RegisterFrameSinkId(frame_sink_id_);
-  surface_factory_.reset(
-      new cc::SurfaceFactory(frame_sink_id_, surface_manager_.get(), this));
+  support_.reset(new cc::CompositorFrameSinkSupport(
+      this, surface_manager_.get(), frame_sink_id_,
+      true /* submits_to_display_compositor */));
 
   begin_frame_source_.reset(new cc::StubBeginFrameSource);
   std::unique_ptr<cc::TextureMailboxDeleter> texture_mailbox_deleter(
@@ -75,17 +75,12 @@
 
   DCHECK(!g_surfaces_instance);
   g_surfaces_instance = this;
-
 }
 
 SurfacesInstance::~SurfacesInstance() {
   DCHECK_EQ(g_surfaces_instance, this);
   g_surfaces_instance = nullptr;
-
   DCHECK(child_ids_.empty());
-  surface_factory_->EvictSurface();
-
-  surface_manager_->InvalidateFrameSinkId(frame_sink_id_);
 }
 
 void SurfacesInstance::DisplayOutputSurfaceLost() {
@@ -137,8 +132,7 @@
     root_id_ = surface_id_allocator_->GenerateId();
     display_->SetLocalSurfaceId(root_id_, 1.f);
   }
-  surface_factory_->SubmitCompositorFrame(root_id_, std::move(frame),
-                                          cc::SurfaceFactory::DrawCallback());
+  support_->SubmitCompositorFrame(root_id_, std::move(frame));
 
   display_->Resize(viewport);
   display_->DrawAndSwap();
@@ -163,20 +157,19 @@
 void SurfacesInstance::SetEmptyRootFrame() {
   cc::CompositorFrame empty_frame;
   empty_frame.metadata.referenced_surfaces = child_ids_;
-  surface_factory_->SubmitCompositorFrame(root_id_, std::move(empty_frame),
-                                          cc::SurfaceFactory::DrawCallback());
+  support_->SubmitCompositorFrame(root_id_, std::move(empty_frame));
 }
 
-void SurfacesInstance::ReturnResources(
+void SurfacesInstance::DidReceiveCompositorFrameAck() {}
+
+void SurfacesInstance::OnBeginFrame(const cc::BeginFrameArgs& args) {}
+
+void SurfacesInstance::WillDrawSurface() {}
+
+void SurfacesInstance::ReclaimResources(
     const cc::ReturnedResourceArray& resources) {
   // Root surface should have no resources to return.
   CHECK(resources.empty());
 }
 
-void SurfacesInstance::SetBeginFrameSource(
-    cc::BeginFrameSource* begin_frame_source) {
-  // Parent compsitor calls DrawAndSwap directly and doesn't use
-  // BeginFrameSource.
-}
-
 }  // namespace android_webview
diff --git a/android_webview/browser/surfaces_instance.h b/android_webview/browser/surfaces_instance.h
index 35132b8c..1ba1316 100644
--- a/android_webview/browser/surfaces_instance.h
+++ b/android_webview/browser/surfaces_instance.h
@@ -9,15 +9,16 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
+#include "cc/surfaces/compositor_frame_sink_support_client.h"
 #include "cc/surfaces/display_client.h"
 #include "cc/surfaces/frame_sink_id.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_id.h"
 
 namespace cc {
+class BeginFrameSource;
+class CompositorFrameSinkSupport;
 class Display;
 class SurfaceIdAllocator;
-class SurfaceFactory;
 class SurfaceManager;
 }
 
@@ -33,7 +34,7 @@
 
 class SurfacesInstance : public base::RefCounted<SurfacesInstance>,
                          public cc::DisplayClient,
-                         public cc::SurfaceFactoryClient {
+                         public cc::CompositorFrameSinkSupportClient {
  public:
   static scoped_refptr<SurfacesInstance> GetOrCreateInstance();
 
@@ -62,9 +63,11 @@
       const cc::RenderPassList& render_passes) override {}
   void DisplayDidDrawAndSwap() override {}
 
-  // cc::SurfaceFactoryClient implementation.
-  void ReturnResources(const cc::ReturnedResourceArray& resources) override;
-  void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
+  // cc::CompositorFrameSinkSupportClient implementation.
+  void DidReceiveCompositorFrameAck() override;
+  void OnBeginFrame(const cc::BeginFrameArgs& args) override;
+  void WillDrawSurface() override;
+  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
 
   void SetEmptyRootFrame();
 
@@ -76,7 +79,7 @@
   std::unique_ptr<cc::BeginFrameSource> begin_frame_source_;
   std::unique_ptr<cc::Display> display_;
   std::unique_ptr<cc::SurfaceIdAllocator> surface_id_allocator_;
-  std::unique_ptr<cc::SurfaceFactory> surface_factory_;
+  std::unique_ptr<cc::CompositorFrameSinkSupport> support_;
 
   cc::LocalSurfaceId root_id_;
   std::vector<cc::SurfaceId> child_ids_;
diff --git a/android_webview/tools/system_webview_shell/test/data/run_tests.sh b/android_webview/tools/system_webview_shell/test/data/run_tests.sh
deleted file mode 100755
index e017a50..0000000
--- a/android_webview/tools/system_webview_shell/test/data/run_tests.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-PACKAGE_NAME="org.chromium.webview_shell.test"
-DEVICE_WEBVIEW_TEST_PATH="/sdcard/chromium_tests_root/android_webview/tools/"
-DEVICE_WEBVIEW_TEST_PATH+="system_webview_shell/test/data/"
-TESTRUNNER="../../../../build/android/test_runner.py"
-
-$TESTRUNNER instrumentation \
-    --test-apk SystemWebViewShellLayoutTest \
-    -f 'WebViewLayoutTest*' \
-    --isolate-file-path android_webview/system_webview_shell_test_apk.isolate
-
-if [ "$1" = "rebaseline" ]; then
-  adb shell am instrument -w -e mode rebaseline -e class \
-      $PACKAGE_NAME.WebViewLayoutTest \
-      $PACKAGE_NAME/$PACKAGE_NAME.WebViewLayoutTestRunner
-  adb pull $DEVICE_WEBVIEW_TEST_PATH ../test_rebaseline/
-fi
-
-exit 0
diff --git a/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh b/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh
new file mode 100755
index 0000000..74feb16
--- /dev/null
+++ b/android_webview/tools/system_webview_shell/test/data/run_tests_rebaseline.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# 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.
+
+# How to use:
+#
+# 1. For the tests to run an appropriate version of webview
+#    needs to be installed on the device (e.g. system_webview_apk).
+# 2. Build system_webview_shell_layout_test_apk. This will also
+#    create a base script for running tests used here.
+# 3. Execute run_test_rebaseline.sh [builddir]
+#    "builddir" is the build output directory (e.g. out/Debug/
+#    which is also the default if no directory is provided).
+#    This script will produce a shadow test_rebaseline/ directory
+#    with the new rebased expectation files.
+#    It is recommended to run this script from it's local
+#    directory in order to have the rebaseline files placed
+#    at the same level as the original test files.
+#
+#    Note: to simply run the tests without the rebaseline
+#    use the bin/run_system_webview_shell_layout_test_apk script
+#    located in the build output directory.
+#
+
+if [ "$1" == "" ]; then
+  # use the default
+  SCRIPT_BUILD_DIR="../../../../../out/Debug/"
+else
+  SCRIPT_BUILD_DIR="$1"
+fi
+
+PACKAGE_NAME="org.chromium.webview_shell.test"
+DEVICE_WEBVIEW_TEST_PATH="/sdcard/chromium_tests_root/android_webview/tools/"
+DEVICE_WEBVIEW_TEST_PATH+="system_webview_shell/test/data/"
+RUNNER=$SCRIPT_BUILD_DIR"bin/run_system_webview_shell_layout_test_apk"
+
+echo $SCRIPT_BUILD_DIR
+
+$RUNNER
+
+adb shell am instrument -w -e mode rebaseline -e class \
+    $PACKAGE_NAME.WebViewLayoutTest \
+    $PACKAGE_NAME/$PACKAGE_NAME.WebViewLayoutTestRunner
+adb pull $DEVICE_WEBVIEW_TEST_PATH ../test_rebaseline/
+
+exit 0
diff --git a/apps/DEPS b/apps/DEPS
index 4f7c1189..4a22b50 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -30,9 +30,6 @@
 
   # Pieces of the extensions system that need to move to src/extensions.
   # See http://crbug.com/162530 for details.
-  "+chrome/browser/extensions/api/file_handlers/app_file_handler_util.h",
-  "+chrome/browser/extensions/api/file_handlers/directory_util.h",
-  "+chrome/browser/extensions/api/file_handlers/mime_util.h",
   "+chrome/browser/extensions/api/file_system/file_system_api.h",
   "+chrome/browser/extensions/chrome_extension_web_contents_observer.h",
   "+chrome/browser/extensions/unpacked_installer.h",
diff --git a/apps/launcher.cc b/apps/launcher.cc
index 5a7dbce9..4782fb60 100644
--- a/apps/launcher.cc
+++ b/apps/launcher.cc
@@ -16,10 +16,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
-#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
-#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
-#include "chrome/browser/extensions/api/file_system/file_system_api.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
@@ -27,6 +23,9 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/browser/api/app_runtime/app_runtime_api.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
+#include "extensions/browser/api/file_handlers/directory_util.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/entry_info.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_host.h"
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 0bcedfa2..8011385 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -129,8 +129,6 @@
     "common/new_window_controller.cc",
     "common/new_window_controller.h",
     "common/palette_delegate.h",
-    "common/popup_message.cc",
-    "common/popup_message.h",
     "common/scoped_root_window_for_new_windows.cc",
     "common/scoped_root_window_for_new_windows.h",
     "common/session/session_controller.cc",
@@ -1175,9 +1173,6 @@
     # TODO: convert to use AshTest http://crbug.com/654492.
     "common/metrics/pointer_metrics_recorder_unittest.cc",
 
-    # TODO: convert to use AshTest http://crbug.com/654493.
-    "common/popup_message_unittest.cc",
-
     # TODO: convert to use AshTest http://crbug.com/654494.
     "common/shelf/shelf_application_menu_model_unittest.cc",
     "common/shelf/shelf_background_animator_unittest.cc",
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index aebf6b43..518b25c 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -251,18 +251,6 @@
       <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_DISABLED" desc="The label used in the tray popup to notify that bluetooth is disabled.">
         Bluetooth disabled
       </message>
-      <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_CONNECTING" desc="Shows a connecting bluetooth device in the bluetooth list.">
-        <ph name="BLUETOOTH">$1<ex>Apple Magic Mouse</ex></ph>: Connecting...
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_DISABLE_BLUETOOTH" desc="The label used in the tray popup to disable bluetooth.">
-        Disable Bluetooth
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_ENABLE_BLUETOOTH" desc="The label used in the tray popup to enable bluetooth.">
-        Enable Bluetooth
-      </message>
-      <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_MANAGE_DEVICES" desc="The label used in the tray popup to manage bluetooth devices.">
-        Manage devices...
-      </message>
       <message name="IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING" desc="The label used in the tray popup to show bluetooth is discovering devices.">
         Scanning for devices...
       </message>
diff --git a/ash/common/popup_message.cc b/ash/common/popup_message.cc
deleted file mode 100644
index f745499..0000000
--- a/ash/common/popup_message.cc
+++ /dev/null
@@ -1,233 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/common/popup_message.h"
-
-#include "ash/common/wm_lookup.h"
-#include "ash/common/wm_window.h"
-#include "grit/ash_resources.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/views/bubble/bubble_dialog_delegate.h"
-#include "ui/views/bubble/bubble_frame_view.h"
-#include "ui/views/controls/image_view.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/layout/box_layout.h"
-#include "ui/views/widget/widget.h"
-#include "ui/wm/core/window_animations.h"
-
-namespace ash {
-namespace {
-const int kMessageTopBottomMargin = 10;
-const int kMessageLeftRightMargin = 10;
-const int kMessageMinHeight = 29 - 2 * kMessageTopBottomMargin;
-const SkColor kMessageTextColor = SkColorSetRGB(0x22, 0x22, 0x22);
-
-// The maximum width of the Message bubble.  Borrowed the value from
-// ash/message/message_controller.cc
-const int kMessageMaxWidth = 250;
-
-// The offset for the Message bubble - making sure that the bubble is flush
-// with the shelf. The offset includes the arrow size in pixels as well as
-// the activation bar and other spacing elements.
-const int kArrowOffsetLeftRight = 11;
-const int kArrowOffsetTopBottom = 7;
-
-// The number of pixels between the icon and the text.
-const int kHorizontalPopupPaddingBetweenItems = 10;
-
-// The number of pixels between the text items.
-const int kVerticalPopupPaddingBetweenItems = 10;
-}  // namespace
-
-// The implementation of Message of the launcher.
-class PopupMessage::MessageBubble : public views::BubbleDialogDelegateView {
- public:
-  MessageBubble(const base::string16& caption,
-                const base::string16& message,
-                IconType message_type,
-                views::View* anchor,
-                views::BubbleBorder::Arrow arrow_orientation,
-                const gfx::Size& size_override,
-                int arrow_offset);
-
-  void ClosePopup();
-
- private:
-  // views::BubbleDialogDelegateView overrides:
-  gfx::Size GetPreferredSize() const override;
-  int GetDialogButtons() const override;
-
-  // Each component (width/height) can force a size override for that component
-  // if not 0.
-  gfx::Size size_override_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageBubble);
-};
-
-// static
-const int PopupMessage::kCaptionLabelID = 1000;
-const int PopupMessage::kMessageLabelID = 1001;
-
-PopupMessage::MessageBubble::MessageBubble(const base::string16& caption,
-                                           const base::string16& message,
-                                           IconType message_type,
-                                           views::View* anchor,
-                                           views::BubbleBorder::Arrow arrow,
-                                           const gfx::Size& size_override,
-                                           int arrow_offset)
-    : views::BubbleDialogDelegateView(anchor, arrow),
-      size_override_(size_override) {
-  gfx::Insets insets =
-      gfx::Insets(kArrowOffsetTopBottom, kArrowOffsetLeftRight,
-                  kArrowOffsetTopBottom, kArrowOffsetLeftRight);
-  // An anchor can have an asymmetrical border for spacing reasons. Adjust the
-  // anchor location for this.
-  if (anchor->border())
-    insets += anchor->border()->GetInsets();
-
-  set_anchor_view_insets(insets);
-  set_close_on_deactivate(false);
-  set_can_activate(false);
-  set_accept_events(false);
-
-  set_margins(gfx::Insets(kMessageTopBottomMargin, kMessageLeftRightMargin,
-                          kMessageTopBottomMargin, kMessageLeftRightMargin));
-  set_shadow(views::BubbleBorder::SMALL_SHADOW);
-
-  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0,
-                                        kHorizontalPopupPaddingBetweenItems));
-
-  // Here is the layout:
-  //         arrow_offset (if not 0)
-  //       |-------------|
-  //       |             ^
-  //       +-------------------------------------------------+
-  //      -|                                                 |-
-  //  icon |  [!]  Caption in bold which can be multi line   | caption_label
-  //      -|                                                 |-
-  //       |       Message text which can be multi line      | message_label
-  //       |       as well.                                  |
-  //       |                                                 |-
-  //       +-------------------------------------------------+
-  //             |------------details container--------------|
-  // Note that the icon, caption and message are optional.
-
-  // Add the icon to the first column (if there is one).
-  if (message_type != ICON_NONE) {
-    views::ImageView* icon = new views::ImageView();
-    icon->SetImage(bundle.GetImageNamed(IDR_AURA_WARNING_ICON).ToImageSkia());
-    icon->SetVerticalAlignment(views::ImageView::LEADING);
-    AddChildView(icon);
-  }
-
-  // Create a container for the text items and use it as second column.
-  views::View* details = new views::View();
-  AddChildView(details);
-  details->SetLayoutManager(new views::BoxLayout(
-      views::BoxLayout::kVertical, 0, 0, kVerticalPopupPaddingBetweenItems));
-
-  // The caption label.
-  if (!caption.empty()) {
-    views::Label* caption_label = new views::Label(caption);
-    caption_label->set_id(kCaptionLabelID);
-    caption_label->SetMultiLine(true);
-    caption_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    caption_label->SetFontList(
-        bundle.GetFontList(ui::ResourceBundle::BoldFont));
-    caption_label->SetEnabledColor(kMessageTextColor);
-    details->AddChildView(caption_label);
-  }
-
-  // The message label.
-  if (!message.empty()) {
-    views::Label* message_label = new views::Label(message);
-    message_label->set_id(kMessageLabelID);
-    message_label->SetMultiLine(true);
-    message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-    message_label->SetEnabledColor(kMessageTextColor);
-    details->AddChildView(message_label);
-  }
-  views::BubbleDialogDelegateView::CreateBubble(this);
-
-  // Change the arrow offset if needed.
-  if (arrow_offset) {
-    // With the creation of the bubble, the bubble got already placed (and
-    // possibly re-oriented to fit on the screen). Since it is not possible to
-    // set the arrow offset before the creation, we need to set the offset,
-    // and the orientation variables again and force a re-placement.
-    GetBubbleFrameView()->bubble_border()->set_arrow_offset(arrow_offset);
-    GetBubbleFrameView()->bubble_border()->set_arrow(arrow);
-    SetAlignment(views::BubbleBorder::ALIGN_ARROW_TO_MID_ANCHOR);
-  }
-}
-
-void PopupMessage::MessageBubble::ClosePopup() {
-  if (GetWidget())
-    GetWidget()->Close();
-}
-
-gfx::Size PopupMessage::MessageBubble::GetPreferredSize() const {
-  gfx::Size pref_size = views::BubbleDialogDelegateView::GetPreferredSize();
-  // Override the size with either the provided size or adjust it to not
-  // violate our minimum / maximum sizes.
-  if (size_override_.height())
-    pref_size.set_height(size_override_.height());
-  else if (pref_size.height() < kMessageMinHeight)
-    pref_size.set_height(kMessageMinHeight);
-
-  if (size_override_.width())
-    pref_size.set_width(size_override_.width());
-  else if (pref_size.width() > kMessageMaxWidth)
-    pref_size.set_width(kMessageMaxWidth);
-
-  return pref_size;
-}
-
-int PopupMessage::MessageBubble::GetDialogButtons() const {
-  return ui::DIALOG_BUTTON_NONE;
-}
-
-PopupMessage::PopupMessage(const base::string16& caption,
-                           const base::string16& message,
-                           IconType message_type,
-                           views::View* anchor,
-                           views::BubbleBorder::Arrow arrow,
-                           const gfx::Size& size_override,
-                           int arrow_offset)
-    : view_(NULL) {
-  view_ = new MessageBubble(caption, message, message_type, anchor, arrow,
-                            size_override, arrow_offset);
-  widget_ = view_->GetWidget();
-  WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget_);
-  window->SetVisibilityAnimationType(
-      ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL);
-  window->SetVisibilityAnimationTransition(::wm::ANIMATE_HIDE);
-  view_->GetWidget()->Show();
-}
-
-PopupMessage::~PopupMessage() {
-  CancelHidingAnimation();
-  Close();
-}
-
-void PopupMessage::Close() {
-  if (view_) {
-    view_->ClosePopup();
-    view_ = NULL;
-    widget_ = NULL;
-  }
-}
-
-void PopupMessage::CancelHidingAnimation() {
-  if (!widget_)
-    return;
-
-  WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget_);
-  if (window)
-    window->SetVisibilityAnimationTransition(::wm::ANIMATE_NONE);
-}
-
-}  // namespace ash
diff --git a/ash/common/popup_message.h b/ash/common/popup_message.h
deleted file mode 100644
index c31e2c1..0000000
--- a/ash/common/popup_message.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_COMMON_POPUP_MESSAGE_H_
-#define ASH_COMMON_POPUP_MESSAGE_H_
-
-#include "ash/ash_export.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/views/bubble/bubble_border.h"
-
-namespace views {
-class Widget;
-}
-
-namespace ash {
-
-// PopupMessage shows a message to the user. Since the user is not able to
-// dismiss it, the calling code needs to explictly close and destroy it.
-class ASH_EXPORT PopupMessage {
- public:
-  enum IconType { ICON_WARNING, ICON_NONE };
-
-  // Creates a message pointing towards |anchor| with the requested
-  // |arrow_orientation|. The message contains an optional |caption| which is
-  // drawn in bold and an optional |message| together with an optional icon of
-  // shape |message_type|. If a component in |size_override| is not 0 the value
-  // is the used as output size. If |arrow_offset| is not 0, the number is the
-  // arrow offset in pixels from the border.
-  //
-  // Here is the layout (arrow given as TOP_LEFT):
-  //                    |--------|
-  //                    | Anchor |
-  //                    |--------|
-  //       |-arrow_offset---^
-  //       +-------------------------------------------------+
-  //      -|                                                 |-
-  //  icon |  [!]  Caption in bold which can be multi line   | caption_label
-  //      -|                                                 |-
-  //       |       Message text which can be multi line      | message_label
-  //       |       as well.                                  |
-  //       |                                                 |-
-  //       +-------------------------------------------------+
-  PopupMessage(const base::string16& caption,
-               const base::string16& message,
-               IconType message_type,
-               views::View* anchor,
-               views::BubbleBorder::Arrow arrow,
-               const gfx::Size& size_override,
-               int arrow_offset);
-  // If the message was not explicitly closed before, it closes the message
-  // without animation.
-  virtual ~PopupMessage();
-
-  // Closes the message with a fade out animation.
-  void Close();
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(PopupMessageTest, Layout);
-
-  class MessageBubble;
-
-  static const int kCaptionLabelID;
-  static const int kMessageLabelID;
-
-  void CancelHidingAnimation();
-
-  MessageBubble* view_;
-  views::Widget* widget_;
-
-  base::string16 caption_;
-  base::string16 message_;
-
-  DISALLOW_COPY_AND_ASSIGN(PopupMessage);
-};
-
-}  // namespace ash
-
-#endif  // ASH_COMMON_POPUP_MESSAGE_H_
diff --git a/ash/common/popup_message_unittest.cc b/ash/common/popup_message_unittest.cc
deleted file mode 100644
index 9bdcce0..0000000
--- a/ash/common/popup_message_unittest.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/common/popup_message.h"
-
-#include "ash/test/ash_test_base.h"
-#include "base/strings/utf_string_conversions.h"
-#include "ui/views/controls/label.h"
-#include "ui/views/widget/widget.h"
-
-namespace ash {
-
-using PopupMessageTest = test::AshTestBase;
-
-// Verifies the layout of the popup, especially it does not crop the caption and
-// message text. See http://crbug.com/468494.
-TEST_F(PopupMessageTest, Layout) {
-  views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
-      nullptr, CurrentContext(), gfx::Rect(0, 0, 100, 100));
-  PopupMessage message(
-      base::ASCIIToUTF16("caption text"),
-      base::ASCIIToUTF16("Message text, which will be usually longer than "
-                         "the caption, so that it's wrapped at some width"),
-      PopupMessage::ICON_WARNING, widget->GetContentsView() /* anchor */,
-      views::BubbleBorder::TOP_LEFT, gfx::Size(), 10);
-
-  views::View* contents_view = message.widget_->GetContentsView();
-  views::View* caption_label =
-      contents_view->GetViewByID(PopupMessage::kCaptionLabelID);
-  views::View* message_label =
-      contents_view->GetViewByID(PopupMessage::kMessageLabelID);
-  ASSERT_TRUE(caption_label);
-  ASSERT_TRUE(message_label);
-
-  // The bubble should have enough heights to show both of the labels.
-  EXPECT_GE(contents_view->height(),
-            caption_label->height() + message_label->height());
-
-  // The labels are not cropped -- the assigned height has enough height to show
-  // the full text.
-  EXPECT_GE(caption_label->height(),
-            caption_label->GetHeightForWidth(caption_label->width()));
-  EXPECT_GE(message_label->height(),
-            message_label->GetHeightForWidth(message_label->width()));
-
-  message.Close();
-  widget->Close();
-}
-
-}  // namespace ash
diff --git a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
index 559b563..80a3cbc0 100644
--- a/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
+++ b/ash/common/system/chromeos/bluetooth/tray_bluetooth.cc
@@ -4,7 +4,6 @@
 
 #include "ash/common/system/chromeos/bluetooth/tray_bluetooth.h"
 
-#include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/system/tray/hover_highlight_view.h"
 #include "ash/common/system/tray/system_tray.h"
@@ -14,7 +13,6 @@
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/common/system/tray/tray_details_view.h"
 #include "ash/common/system/tray/tray_item_more.h"
-#include "ash/common/system/tray/tray_popup_header_button.h"
 #include "ash/common/system/tray/tray_popup_item_style.h"
 #include "ash/common/system/tray/tray_popup_utils.h"
 #include "ash/common/system/tray/tri_view.h"
@@ -41,10 +39,6 @@
 namespace tray {
 namespace {
 
-bool UseMd() {
-  return MaterialDesignController::IsSystemTrayMenuMaterial();
-}
-
 // Updates bluetooth device |device| in the |list|. If it is new, append to the
 // end of the |list|; otherwise, keep it at the same place, but update the data
 // with new device info provided by |device|.
@@ -119,14 +113,7 @@
 class BluetoothDefaultView : public TrayItemMore {
  public:
   BluetoothDefaultView(SystemTrayItem* owner, bool show_more)
-      : TrayItemMore(owner, show_more) {
-    if (!UseMd()) {
-      // The icon doesn't change in non-md.
-      ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-      SetImage(
-          *bundle.GetImageNamed(IDR_AURA_UBER_TRAY_BLUETOOTH).ToImageSkia());
-    }
-  }
+      : TrayItemMore(owner, show_more) {}
 
   ~BluetoothDefaultView() override {}
 
@@ -164,10 +151,6 @@
 
   void UpdateStyle() override {
     TrayItemMore::UpdateStyle();
-
-    if (!UseMd())
-      return;
-
     std::unique_ptr<TrayPopupItemStyle> style = CreateStyle();
     SetImage(gfx::CreateVectorIcon(GetCurrentIcon(), style->GetIconColor()));
   }
@@ -199,10 +182,6 @@
   BluetoothDetailedView(SystemTrayItem* owner, LoginStatus login)
       : TrayDetailsView(owner),
         login_(login),
-        manage_devices_(nullptr),
-        throbber_(nullptr),
-        toggle_bluetooth_(nullptr),
-        enable_bluetooth_(nullptr),
         toggle_(nullptr),
         settings_(nullptr),
         disabled_panel_(nullptr) {
@@ -227,7 +206,6 @@
  private:
   void CreateItems() {
     CreateScrollableList();
-    AppendSettingsEntries();
     CreateTitleRow(IDS_ASH_STATUS_TRAY_BLUETOOTH);
   }
 
@@ -260,10 +238,6 @@
     WmShell::Get()->system_tray_delegate()->GetAvailableBluetoothDevices(&list);
     for (size_t i = 0; i < list.size(); ++i) {
       if (list[i].connecting) {
-        if (!UseMd()) {
-          list[i].display_name = l10n_util::GetStringFUTF16(
-              IDS_ASH_STATUS_TRAY_BLUETOOTH_CONNECTING, list[i].display_name);
-        }
         new_connecting_devices.insert(list[i].address);
         UpdateBluetoothDeviceListHelper(&connecting_devices_, list[i]);
       } else if (list[i].connected && list[i].paired) {
@@ -294,33 +268,23 @@
         WmShell::Get()->system_tray_delegate()->GetBluetoothEnabled();
     if (toggle_)
       toggle_->SetIsOn(is_bluetooth_enabled, false);
-    else if (toggle_bluetooth_)
-      toggle_bluetooth_->SetToggled(!is_bluetooth_enabled);
   }
 
   void UpdateDeviceScrollList() {
     device_map_.clear();
     scroll_content()->RemoveAllChildViews(true);
-    enable_bluetooth_ = nullptr;
 
     SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate();
     bool bluetooth_enabled = delegate->GetBluetoothEnabled();
     bool bluetooth_available = delegate->GetBluetoothAvailable();
-    if (bluetooth_available && !bluetooth_enabled && toggle_bluetooth_) {
-      enable_bluetooth_ = AddScrollListItem(
-          l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_BLUETOOTH),
-          false /* highlight */, false /* checked */, true /* enabled */);
-    }
 
     // If Bluetooth is disabled, show a panel which only indicates that it is
     // disabled, instead of the scroller with Bluetooth devices.
-    if (UseMd()) {
-      if (bluetooth_enabled) {
-        HideDisabledPanel();
-      } else {
-        ShowDisabledPanel();
-        return;
-      }
+    if (bluetooth_enabled) {
+      HideDisabledPanel();
+    } else {
+      ShowDisabledPanel();
+      return;
     }
 
     // Add paired devices (and their section header in MD) in the list.
@@ -328,8 +292,7 @@
                                 connecting_devices_.size() +
                                 paired_not_connected_devices_.size();
     if (num_paired_devices > 0) {
-      if (UseMd())
-        AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_DEVICES);
+      AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_PAIRED_DEVICES);
       AppendSameTypeDevicesToScrollList(connected_devices_, true, true,
                                         bluetooth_enabled);
       AppendSameTypeDevicesToScrollList(connecting_devices_, true, false,
@@ -340,12 +303,8 @@
 
     // Add paired devices (and their section header in MD) in the list.
     if (discovered_not_paired_devices_.size() > 0) {
-      if (UseMd()) {
-        if (num_paired_devices > 0)
-          AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_UNPAIRED_DEVICES);
-      } else {
-        AddScrollSeparator();
-      }
+      if (num_paired_devices > 0)
+        AddSubHeader(IDS_ASH_STATUS_TRAY_BLUETOOTH_UNPAIRED_DEVICES);
       AppendSameTypeDevicesToScrollList(discovered_not_paired_devices_, false,
                                         false, bluetooth_enabled);
     }
@@ -353,10 +312,11 @@
     // Show user Bluetooth state if there is no bluetooth devices in list.
     if (device_map_.size() == 0) {
       if (bluetooth_available && bluetooth_enabled) {
-        AddScrollListItem(l10n_util::GetStringUTF16(
-                              IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING),
-                          false /* highlight */, false /* checked */,
-                          true /* enabled */);
+        HoverHighlightView* container = new HoverHighlightView(this);
+        container->AddLabel(l10n_util::GetStringUTF16(
+                                IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING),
+                            gfx::ALIGN_LEFT, false);
+        scroll_content()->AddChildView(container);
       }
     }
 
@@ -369,45 +329,24 @@
                                          bool enabled) {
     for (size_t i = 0; i < list.size(); ++i) {
       HoverHighlightView* container = nullptr;
-      if (UseMd()) {
-        gfx::ImageSkia icon_image = CreateVectorIcon(
-            GetBluetoothDeviceIcon(list[i].device_type, list[i].connected),
-            kMenuIconColor);
-        container = AddScrollListItemMd(list[i].display_name, icon_image,
-                                        list[i].connected, list[i].connecting);
-      } else {
-        container = AddScrollListItem(list[i].display_name, highlight, checked,
-                                      enabled);
-      }
+      gfx::ImageSkia icon_image = CreateVectorIcon(
+          GetBluetoothDeviceIcon(list[i].device_type, list[i].connected),
+          kMenuIconColor);
+      container = AddScrollListItem(list[i].display_name, icon_image,
+                                    list[i].connected, list[i].connecting);
       device_map_[container] = list[i].address;
     }
   }
 
-  // TODO(fukino): Remove this code when material design is enabled by default,
-  // since AddScrollListItem should be used only in the old design.
-  // See crbug.com/614453".
   HoverHighlightView* AddScrollListItem(const base::string16& text,
-                                        bool highlight,
-                                        bool checked,
-                                        bool enabled) {
-    HoverHighlightView* container = new HoverHighlightView(this);
-    views::Label* label =
-        container->AddCheckableLabel(text, highlight, checked);
-    label->SetEnabled(enabled);
-    scroll_content()->AddChildView(container);
-    return container;
-  }
-
-  HoverHighlightView* AddScrollListItemMd(const base::string16& text,
-                                          const gfx::ImageSkia& image,
-                                          bool connected,
-                                          bool connecting) {
-    DCHECK(UseMd());
+                                        const gfx::ImageSkia& image,
+                                        bool connected,
+                                        bool connecting) {
     HoverHighlightView* container = new HoverHighlightView(this);
     if (connected) {
-      SetupConnectedItemMd(container, text, image);
+      SetupConnectedItem(container, text, image);
     } else if (connecting) {
-      SetupConnectingItemMd(container, text, image);
+      SetupConnectingItem(container, text, image);
     } else {
       container->AddIconAndLabel(image, text, false);
     }
@@ -428,9 +367,9 @@
     scroll_content()->AddChildView(header);
   }
 
-  void SetupConnectedItemMd(HoverHighlightView* container,
-                            const base::string16& text,
-                            const gfx::ImageSkia& image) {
+  void SetupConnectedItem(HoverHighlightView* container,
+                          const base::string16& text,
+                          const gfx::ImageSkia& image) {
     container->AddIconAndLabels(
         image, text, l10n_util::GetStringUTF16(
                          IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTED));
@@ -439,9 +378,9 @@
     style.SetupLabel(container->sub_text_label());
   }
 
-  void SetupConnectingItemMd(HoverHighlightView* container,
-                             const base::string16& text,
-                             const gfx::ImageSkia& image) {
+  void SetupConnectingItem(HoverHighlightView* container,
+                           const base::string16& text,
+                           const gfx::ImageSkia& image) {
     container->AddIconAndLabels(
         image, text, l10n_util::GetStringUTF16(
                          IDS_ASH_STATUS_TRAY_NETWORK_STATUS_CONNECTING));
@@ -450,32 +389,6 @@
     container->AddRightView(throbber);
   }
 
-  // Add settings entries.
-  void AppendSettingsEntries() {
-    // Do not append the bottom button row in material design; this is replaced
-    // by the settings button in the header row.
-    if (UseMd())
-      return;
-
-    if (!WmShell::Get()->system_tray_delegate()->ShouldShowSettings())
-      return;
-
-    // Add bluetooth device requires a browser window, hide it for non logged in
-    // user.
-    if (!TrayPopupUtils::CanOpenWebUISettings(login_))
-      return;
-
-    SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate();
-    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-    HoverHighlightView* container = new HoverHighlightView(this);
-    container->AddLabel(
-        rb.GetLocalizedString(IDS_ASH_STATUS_TRAY_BLUETOOTH_MANAGE_DEVICES),
-        gfx::ALIGN_LEFT, false /* highlight */);
-    container->SetEnabled(delegate->GetBluetoothAvailable());
-    AddChildView(container);
-    manage_devices_ = container;
-  }
-
   // Returns true if the device with |device_id| is found in |device_list|,
   // and the display_name of the device will be returned in |display_name| if
   // it's not NULL.
@@ -506,17 +419,11 @@
       item_container->RemoveAllChildViews(true);
       HoverHighlightView* container =
           static_cast<HoverHighlightView*>(item_container);
-      if (UseMd()) {
-        TrayPopupItemStyle style(
-            TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL);
-        gfx::ImageSkia icon_image = CreateVectorIcon(
-            GetBluetoothDeviceIcon(device_type, false), style.GetIconColor());
-        SetupConnectingItemMd(container, display_name, icon_image);
-      } else {
-        display_name = l10n_util::GetStringFUTF16(
-            IDS_ASH_STATUS_TRAY_BLUETOOTH_CONNECTING, display_name);
-        container->AddCheckableLabel(display_name, true /* highlight */, false);
-      }
+      TrayPopupItemStyle style(
+          TrayPopupItemStyle::FontStyle::DETAILED_VIEW_LABEL);
+      gfx::ImageSkia icon_image = CreateVectorIcon(
+          GetBluetoothDeviceIcon(device_type, false), style.GetIconColor());
+      SetupConnectingItem(container, display_name, icon_image);
       scroll_content()->SizeToPreferredSize();
       scroller()->Layout();
     }
@@ -524,20 +431,7 @@
 
   // TrayDetailsView:
   void HandleViewClicked(views::View* view) override {
-    if (view == manage_devices_) {
-      ShowSettings();
-      return;
-    }
-
     SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate();
-    if (view == enable_bluetooth_) {
-      WmShell::Get()->RecordUserMetricsAction(
-          delegate->GetBluetoothEnabled() ? UMA_STATUS_AREA_BLUETOOTH_DISABLED
-                                          : UMA_STATUS_AREA_BLUETOOTH_ENABLED);
-      delegate->ToggleBluetooth();
-      return;
-    }
-
     if (!delegate->GetBluetoothEnabled())
       return;
 
@@ -556,62 +450,29 @@
 
   void HandleButtonPressed(views::Button* sender,
                            const ui::Event& event) override {
-    if (UseMd()) {
-      if (sender == toggle_)
-        WmShell::Get()->system_tray_delegate()->ToggleBluetooth();
-      else if (sender == settings_)
-        ShowSettings();
-      else
-        NOTREACHED();
-      return;
-    }
+    if (sender == toggle_)
+      WmShell::Get()->system_tray_delegate()->ToggleBluetooth();
+    else if (sender == settings_)
+      ShowSettings();
 
-    SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate();
-    if (sender == toggle_bluetooth_)
-      delegate->ToggleBluetooth();
-    else
-      NOTREACHED();
+    NOTREACHED();
   }
 
   void CreateExtraTitleRowButtons() override {
     if (login_ == LoginStatus::LOCKED)
       return;
 
-    if (UseMd()) {
-      DCHECK(!toggle_);
-      DCHECK(!settings_);
+    DCHECK(!toggle_);
+    DCHECK(!settings_);
 
-      tri_view()->SetContainerVisible(TriView::Container::END, true);
+    tri_view()->SetContainerVisible(TriView::Container::END, true);
 
-      toggle_ = TrayPopupUtils::CreateToggleButton(
-          this, IDS_ASH_STATUS_TRAY_BLUETOOTH);
-      tri_view()->AddView(TriView::Container::END, toggle_);
+    toggle_ =
+        TrayPopupUtils::CreateToggleButton(this, IDS_ASH_STATUS_TRAY_BLUETOOTH);
+    tri_view()->AddView(TriView::Container::END, toggle_);
 
-      settings_ = CreateSettingsButton(login_);
-      tri_view()->AddView(TriView::Container::END, settings_);
-      return;
-    }
-
-    throbber_ = new ThrobberView;
-    throbber_->SetTooltipText(
-        l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_BLUETOOTH_DISCOVERING));
-    title_row()->AddViewToRowNonMd(throbber_, false);
-
-    // Do not allow toggling bluetooth in the lock screen.
-    SystemTrayDelegate* delegate = WmShell::Get()->system_tray_delegate();
-    toggle_bluetooth_ =
-        new TrayPopupHeaderButton(this, IDR_AURA_UBER_TRAY_BLUETOOTH_ENABLED,
-                                  IDR_AURA_UBER_TRAY_BLUETOOTH_DISABLED,
-                                  IDR_AURA_UBER_TRAY_BLUETOOTH_ENABLED_HOVER,
-                                  IDR_AURA_UBER_TRAY_BLUETOOTH_DISABLED_HOVER,
-                                  IDS_ASH_STATUS_TRAY_BLUETOOTH);
-    toggle_bluetooth_->SetToggled(!delegate->GetBluetoothEnabled());
-    toggle_bluetooth_->SetTooltipText(
-        l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_DISABLE_BLUETOOTH));
-    toggle_bluetooth_->SetToggledTooltipText(
-        l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ENABLE_BLUETOOTH));
-    toggle_bluetooth_->EnableCanvasFlippingForRTLUI(false);
-    title_row()->AddViewToRowNonMd(toggle_bluetooth_, true);
+    settings_ = CreateSettingsButton(login_);
+    tri_view()->AddView(TriView::Container::END, settings_);
   }
 
   void ShowSettings() {
@@ -622,23 +483,13 @@
   }
 
   void ShowLoadingIndicator() {
-    if (throbber_) {
-      throbber_->Start();
-    } else if (UseMd()) {
-      // Setting a value of -1 gives progress_bar an infinite-loading behavior.
-      ShowProgress(-1, true);
-    }
+    // Setting a value of -1 gives progress_bar an infinite-loading behavior.
+    ShowProgress(-1, true);
   }
 
-  void HideLoadingIndicator() {
-    if (throbber_)
-      throbber_->Stop();
-    else if (UseMd())
-      ShowProgress(0, false);
-  }
+  void HideLoadingIndicator() { ShowProgress(0, false); }
 
   void ShowDisabledPanel() {
-    DCHECK(UseMd());
     DCHECK(scroller());
     if (!disabled_panel_) {
       disabled_panel_ = CreateDisabledPanel();
@@ -654,7 +505,6 @@
   }
 
   void HideDisabledPanel() {
-    DCHECK(UseMd());
     DCHECK(scroller());
     if (disabled_panel_)
       disabled_panel_->SetVisible(false);
@@ -698,28 +548,14 @@
 
   std::map<views::View*, std::string> device_map_;
 
-  // Not used in material design.
-  views::View* manage_devices_;
-
-  // Not used in material design.
-  ThrobberView* throbber_;
-
-  // Not used in material design.
-  TrayPopupHeaderButton* toggle_bluetooth_;
-
-  HoverHighlightView* enable_bluetooth_;
   BluetoothDeviceList connected_devices_;
   BluetoothDeviceList connecting_devices_;
   BluetoothDeviceList paired_not_connected_devices_;
   BluetoothDeviceList discovered_not_paired_devices_;
 
-  // The on/off toggle button used in material design.
   views::ToggleButton* toggle_;
-
-  // Only used in material design.
   views::Button* settings_;
 
-  // Only used in material design.
   // The container of the message "Bluetooth is disabled" and an icon. It should
   // be shown instead of Bluetooth device list when Bluetooth is disabled.
   views::View* disabled_panel_;
diff --git a/ash/common/system/chromeos/ime_menu/ime_list_view.cc b/ash/common/system/chromeos/ime_menu/ime_list_view.cc
index e858d69..e3303da 100644
--- a/ash/common/system/chromeos/ime_menu/ime_list_view.cc
+++ b/ash/common/system/chromeos/ime_menu/ime_list_view.cc
@@ -105,7 +105,8 @@
     // |kMenuIconSize| is not enough. The label will trigger eliding as "I..."
     // or "...". So we shrink the font size until it fits within the bounds.
     int size_delta = -1;
-    while (id_label->GetPreferredSize().width() > kMenuIconSize &&
+    while ((id_label->GetPreferredSize().width() -
+            id_label->GetInsets().width()) > kMenuIconSize &&
            size_delta >= kMinFontSizeDelta) {
       id_label->SetFontList(base_font_list.DeriveWithSizeDelta(size_delta));
       --size_delta;
diff --git a/ash/common/system/user/user_view.cc b/ash/common/system/user/user_view.cc
index c5c238e..7595c0de 100644
--- a/ash/common/system/user/user_view.cc
+++ b/ash/common/system/user/user_view.cc
@@ -8,7 +8,6 @@
 #include <utility>
 
 #include "ash/common/multi_profile_uma.h"
-#include "ash/common/popup_message.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shell_delegate.h"
 #include "ash/common/system/tray/system_tray.h"
@@ -237,9 +236,8 @@
 }
 
 TrayUser::TestState UserView::GetStateForTest() const {
-  if (add_menu_option_.get()) {
+  if (add_menu_option_)
     return add_user_enabled_ ? TrayUser::ACTIVE : TrayUser::ACTIVE_BUT_DISABLED;
-  }
 
   if (!is_user_card_button_)
     return TrayUser::SHOWN;
@@ -278,7 +276,7 @@
       // closed.
       owner_->system_tray()->CloseSystemBubble();
     }
-  } else if (add_menu_option_.get() &&
+  } else if (add_menu_option_ &&
              sender->GetWidget() == add_menu_option_.get()) {
     RemoveAddUserMenuOption();
     // Let the user add another account to the session.
@@ -325,7 +323,7 @@
 }
 
 void UserView::ToggleAddUserMenuOption() {
-  if (add_menu_option_.get()) {
+  if (add_menu_option_) {
     RemoveAddUserMenuOption();
     return;
   }
@@ -398,13 +396,12 @@
 }
 
 void UserView::RemoveAddUserMenuOption() {
-  if (!add_menu_option_.get())
+  if (!add_menu_option_)
     return;
   focus_manager_->RemoveFocusChangeListener(this);
   focus_manager_ = nullptr;
   if (user_card_view_->GetFocusManager())
     user_card_view_->GetFocusManager()->ClearFocus();
-  popup_message_.reset();
   add_menu_option_.reset();
 }
 
diff --git a/ash/common/system/user/user_view.h b/ash/common/system/user/user_view.h
index ce79c63..56d4fb34 100644
--- a/ash/common/system/user/user_view.h
+++ b/ash/common/system/user/user_view.h
@@ -27,7 +27,6 @@
 namespace ash {
 
 enum class LoginStatus;
-class PopupMessage;
 class SystemTrayItem;
 
 namespace tray {
@@ -80,7 +79,6 @@
   bool is_user_card_button_;
 
   views::View* logout_button_;
-  std::unique_ptr<PopupMessage> popup_message_;
   std::unique_ptr<views::Widget> add_menu_option_;
 
   // False when the add user panel is visible but not activatable.
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc
index c677caae5..9a32419 100644
--- a/ash/magnifier/magnification_controller.cc
+++ b/ash/magnifier/magnification_controller.cc
@@ -20,6 +20,7 @@
 #include "base/command_line.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/timer/timer.h"
+#include "chromeos/chromeos_switches.h"
 #include "ui/aura/client/cursor_client.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_tree_host.h"
@@ -34,6 +35,7 @@
 #include "ui/display/screen.h"
 #include "ui/events/event.h"
 #include "ui/events/event_handler.h"
+#include "ui/events/gesture_event_details.h"
 #include "ui/gfx/geometry/point3_f.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/point_f.h"
@@ -191,6 +193,7 @@
   void OnMouseEvent(ui::MouseEvent* event) override;
   void OnScrollEvent(ui::ScrollEvent* event) override;
   void OnTouchEvent(ui::TouchEvent* event) override;
+  void OnGestureEvent(ui::GestureEvent* event) override;
 
   // Moves the view port when |point| is located within
   // |x_panning_margin| and |y_pannin_margin| to the edge of the visible
@@ -690,6 +693,33 @@
   }
 }
 
+void MagnificationControllerImpl::OnGestureEvent(ui::GestureEvent* event) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kEnableTouchSupportForScreenMagnifier)) {
+    return;
+  }
+
+  const ui::GestureEventDetails& details = event->details();
+  if (details.type() == ui::ET_GESTURE_SCROLL_UPDATE &&
+      details.touch_points() == 2) {
+    gfx::Rect viewport_rect_in_dip = GetViewportRect();
+    viewport_rect_in_dip.Offset(-details.scroll_x(), -details.scroll_y());
+    gfx::Rect viewport_rect_in_pixel =
+        ui::ConvertRectToPixel(root_window_->layer(), viewport_rect_in_dip);
+    MoveWindow(viewport_rect_in_pixel.origin(), false);
+    event->SetHandled();
+  } else if (details.type() == ui::ET_GESTURE_PINCH_UPDATE &&
+             details.touch_points() == 3) {
+    float scale = GetScale() * details.scale();
+    scale = std::max(scale, kMinMagnifiedScaleThreshold);
+    scale = std::min(scale, kMaxMagnifiedScaleThreshold);
+
+    point_of_interest_ = event->root_location();
+    SetScale(scale, false);
+    event->SetHandled();
+  }
+}
+
 void MagnificationControllerImpl::MoveMagnifierWindowFollowPoint(
     const gfx::Point& point,
     int x_panning_margin,
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd
index d6a3085..2bb44be0 100644
--- a/ash/resources/ash_resources.grd
+++ b/ash/resources/ash_resources.grd
@@ -64,15 +64,8 @@
       <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_BG_VERTICAL_PRESSED_TOP" file="common/shelf/status_tray_vertical_pressed_top.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_TRAY_BG_VERTICAL_TOP" file="common/shelf/status_tray_vertical_normal_top.png" />
 
-      <structure type="chrome_scaled_image" name="IDR_AURA_WARNING_ICON" file="common/alert_small.png" />
-
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_ACCESSIBILITY" file="cros/status/status_accessibility_mode.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_ACCESSIBILITY_DARK" file="cros/status/status_accessibility_dark.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_BLUETOOTH" file="cros/status/status_bluetooth.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_BLUETOOTH_DISABLED" file="cros/status/status_bluetooth_disabled.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_BLUETOOTH_DISABLED_HOVER" file="cros/status/status_bluetooth_disabled_hover.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_BLUETOOTH_ENABLED" file="cros/status/status_bluetooth_enabled.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_BLUETOOTH_ENABLED_HOVER" file="cros/status/status_bluetooth_enabled_hover.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_CAST" file="cros/status/status_cast.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_CAST_DEVICE_ICON" file="cros/status/status_cast_device_icon.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_CAST_ENABLED" file="cros/status/status_cast_enabled.png" />
diff --git a/ash/resources/default_100_percent/common/alert_small.png b/ash/resources/default_100_percent/common/alert_small.png
deleted file mode 100644
index 7b76b49..0000000
--- a/ash/resources/default_100_percent/common/alert_small.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_bluetooth.png b/ash/resources/default_100_percent/cros/status/status_bluetooth.png
deleted file mode 100644
index 25fbff0..0000000
--- a/ash/resources/default_100_percent/cros/status/status_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_bluetooth_disabled.png b/ash/resources/default_100_percent/cros/status/status_bluetooth_disabled.png
deleted file mode 100644
index 4f8cae03..0000000
--- a/ash/resources/default_100_percent/cros/status/status_bluetooth_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_bluetooth_disabled_hover.png b/ash/resources/default_100_percent/cros/status/status_bluetooth_disabled_hover.png
deleted file mode 100644
index 66b1dd2a..0000000
--- a/ash/resources/default_100_percent/cros/status/status_bluetooth_disabled_hover.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_bluetooth_enabled.png b/ash/resources/default_100_percent/cros/status/status_bluetooth_enabled.png
deleted file mode 100644
index c06841b4..0000000
--- a/ash/resources/default_100_percent/cros/status/status_bluetooth_enabled.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_bluetooth_enabled_hover.png b/ash/resources/default_100_percent/cros/status/status_bluetooth_enabled_hover.png
deleted file mode 100644
index 0bf56fb8..0000000
--- a/ash/resources/default_100_percent/cros/status/status_bluetooth_enabled_hover.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/common/alert_small.png b/ash/resources/default_200_percent/common/alert_small.png
deleted file mode 100644
index cad7944..0000000
--- a/ash/resources/default_200_percent/common/alert_small.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_bluetooth.png b/ash/resources/default_200_percent/cros/status/status_bluetooth.png
deleted file mode 100644
index 1e18e3e..0000000
--- a/ash/resources/default_200_percent/cros/status/status_bluetooth.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_bluetooth_disabled.png b/ash/resources/default_200_percent/cros/status/status_bluetooth_disabled.png
deleted file mode 100644
index 6676cf9..0000000
--- a/ash/resources/default_200_percent/cros/status/status_bluetooth_disabled.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_bluetooth_disabled_hover.png b/ash/resources/default_200_percent/cros/status/status_bluetooth_disabled_hover.png
deleted file mode 100644
index 66f368d..0000000
--- a/ash/resources/default_200_percent/cros/status/status_bluetooth_disabled_hover.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_bluetooth_enabled.png b/ash/resources/default_200_percent/cros/status/status_bluetooth_enabled.png
deleted file mode 100644
index b139ff93..0000000
--- a/ash/resources/default_200_percent/cros/status/status_bluetooth_enabled.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_bluetooth_enabled_hover.png b/ash/resources/default_200_percent/cros/status/status_bluetooth_enabled_hover.png
deleted file mode 100644
index a4fa7eb8..0000000
--- a/ash/resources/default_200_percent/cros/status/status_bluetooth_enabled_hover.png
+++ /dev/null
Binary files differ
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
index ebd1852..4a55f64 100644
--- a/base/debug/stack_trace_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -383,6 +383,7 @@
   // Non-Mac OSes should probably reraise the signal as well, but the Linux
   // sandbox tests break on CrOS devices.
   // https://code.google.com/p/chromium/issues/detail?id=551681
+  PrintToStderr("Calling _exit(1). Core file will not be generated.\n");
   _exit(1);
 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
 }
diff --git a/base/i18n/character_encoding.cc b/base/i18n/character_encoding.cc
index 05d2f50..a1068c3 100644
--- a/base/i18n/character_encoding.cc
+++ b/base/i18n/character_encoding.cc
@@ -25,12 +25,12 @@
 }  // namespace
 
 std::string GetCanonicalEncodingNameByAliasName(const std::string& alias_name) {
-  for (auto& encoding_name : kCanonicalEncodingNames) {
+  for (auto* encoding_name : kCanonicalEncodingNames) {
     if (alias_name == encoding_name)
       return alias_name;
   }
   static const char* kStandards[3] = {"HTML", "MIME", "IANA"};
-  for (auto& standard : kStandards) {
+  for (auto* standard : kStandards) {
     UErrorCode error_code = U_ZERO_ERROR;
     const char* canonical_name =
         ucnv_getStandardName(alias_name.c_str(), standard, &error_code);
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
index 3f560ee5..ea62a34 100644
--- a/base/i18n/time_formatting.cc
+++ b/base/i18n/time_formatting.cc
@@ -171,6 +171,11 @@
   return TimeFormat(formatter.get(), time);
 }
 
+string16 TimeFormatWithPattern(const Time& time, const char* pattern) {
+  icu::SimpleDateFormat formatter = CreateSimpleDateFormatter(pattern);
+  return TimeFormat(&formatter, time);
+}
+
 string16 TimeDurationFormat(const TimeDelta time,
                             const DurationFormatWidth width) {
   UErrorCode status = U_ZERO_ERROR;
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
index 0fb6529..ba09b44 100644
--- a/base/i18n/time_formatting.h
+++ b/base/i18n/time_formatting.h
@@ -87,6 +87,13 @@
 // "Monday, March 6, 2008".
 BASE_I18N_EXPORT string16 TimeFormatFriendlyDate(const Time& time);
 
+// Formats a time using a skeleton to produce a format for different locales
+// when an unusual time format is needed, e.g. "Feb. 2, 18:00".
+//
+// See http://userguide.icu-project.org/formatparse/datetime for details.
+BASE_I18N_EXPORT string16 TimeFormatWithPattern(const Time& time,
+                                                const char* pattern);
+
 // Formats a time duration of hours and minutes into various formats, e.g.,
 // "3:07" or "3 hours, 7 minutes".  See DurationFormatWidth for details.
 //
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc
index 06cd772..0e9f146e 100644
--- a/base/i18n/time_formatting_unittest.cc
+++ b/base/i18n/time_formatting_unittest.cc
@@ -224,6 +224,29 @@
             TimeFormatFriendlyDate(time));
 }
 
+TEST(TimeFormattingTest, TimeFormatWithPattern) {
+  test::ScopedRestoreICUDefaultLocale restore_locale;
+
+  Time time;
+  EXPECT_TRUE(Time::FromLocalExploded(kTestDateTimeExploded, &time));
+
+  i18n::SetICUDefaultLocale("en_US");
+  EXPECT_EQ(ASCIIToUTF16("Apr 30, 2011"), TimeFormatWithPattern(time, "yMMMd"));
+  EXPECT_EQ(ASCIIToUTF16("April 30, 3:42:07 PM"),
+            TimeFormatWithPattern(time, "MMMMdjmmss"));
+
+  i18n::SetICUDefaultLocale("en_GB");
+  EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatWithPattern(time, "yMMMd"));
+  EXPECT_EQ(ASCIIToUTF16("30 April, 15:42:07"),
+            TimeFormatWithPattern(time, "MMMMdjmmss"));
+
+  i18n::SetICUDefaultLocale("ja_JP");
+  EXPECT_EQ(WideToUTF16(L"2011年4月30日"),
+            TimeFormatWithPattern(time, "yMMMd"));
+  EXPECT_EQ(WideToUTF16(L"4月30日") + ASCIIToUTF16(" 15:42:07"),
+            TimeFormatWithPattern(time, "MMMMdjmmss"));
+}
+
 TEST(TimeFormattingTest, TimeDurationFormat) {
   test::ScopedRestoreICUDefaultLocale restore_locale;
   TimeDelta delta = TimeDelta::FromMinutes(15 * 60 + 42);
diff --git a/base/memory/memory_pressure_listener.cc b/base/memory/memory_pressure_listener.cc
index a421c18b..c89ce3a 100644
--- a/base/memory/memory_pressure_listener.cc
+++ b/base/memory/memory_pressure_listener.cc
@@ -51,7 +51,7 @@
 };
 
 MemoryPressureObserver* GetMemoryPressureObserver() {
-  static auto observer = new MemoryPressureObserver();
+  static auto* observer = new MemoryPressureObserver();
   return observer;
 }
 
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 60df713..3d55920 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -39,7 +39,7 @@
 // A lazily created thread local storage for quick access to a thread's message
 // loop, if one exists.
 base::ThreadLocalPointer<MessageLoop>* GetTLSMessageLoop() {
-  static auto lazy_tls_ptr = new base::ThreadLocalPointer<MessageLoop>();
+  static auto* lazy_tls_ptr = new base::ThreadLocalPointer<MessageLoop>();
   return lazy_tls_ptr;
 }
 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
diff --git a/base/path_service.cc b/base/path_service.cc
index 17ba0d7..1b9d394 100644
--- a/base/path_service.cc
+++ b/base/path_service.cc
@@ -129,7 +129,7 @@
 };
 
 static PathData* GetPathData() {
-  static auto path_data = new PathData();
+  static auto* path_data = new PathData();
   return path_data;
 }
 
diff --git a/base/test/histogram_tester.cc b/base/test/histogram_tester.cc
index 59ea1c6..5ca3c2f 100644
--- a/base/test/histogram_tester.cc
+++ b/base/test/histogram_tester.cc
@@ -23,7 +23,7 @@
   // be subtracted later.
   StatisticsRecorder::Histograms histograms;
   StatisticsRecorder::GetSnapshot(std::string(), &histograms);
-  for (const auto& histogram : histograms) {
+  for (const auto* histogram : histograms) {
     histograms_snapshot_[histogram->histogram_name()] =
         histogram->SnapshotSamples();
   }
diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc
index 8dda1b36..a4010d5 100644
--- a/base/test/test_reg_util_win.cc
+++ b/base/test/test_reg_util_win.cc
@@ -70,18 +70,13 @@
 RegistryOverrideManager::ScopedRegistryKeyOverride::ScopedRegistryKeyOverride(
     HKEY override,
     const base::string16& key_path)
-    : override_(override) {
-  EXPECT_EQ(
-      ERROR_SUCCESS,
-      temp_key_.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS));
-  EXPECT_EQ(ERROR_SUCCESS,
-            ::RegOverridePredefKey(override_, temp_key_.Handle()));
-}
+    : override_(override), key_path_(key_path) {}
 
 RegistryOverrideManager::
     ScopedRegistryKeyOverride::~ScopedRegistryKeyOverride() {
   ::RegOverridePredefKey(override_, NULL);
-  temp_key_.DeleteKey(L"");
+  base::win::RegKey(HKEY_CURRENT_USER, L"", KEY_QUERY_VALUE)
+      .DeleteKey(key_path_.c_str());
 }
 
 RegistryOverrideManager::RegistryOverrideManager()
@@ -105,6 +100,12 @@
 void RegistryOverrideManager::OverrideRegistry(HKEY override,
                                                base::string16* override_path) {
   base::string16 key_path = GenerateTempKeyPath(test_key_root_, timestamp_);
+
+  base::win::RegKey temp_key;
+  ASSERT_EQ(ERROR_SUCCESS, temp_key.Create(HKEY_CURRENT_USER, key_path.c_str(),
+                                           KEY_ALL_ACCESS));
+  ASSERT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(override, temp_key.Handle()));
+
   overrides_.push_back(
       base::MakeUnique<ScopedRegistryKeyOverride>(override, key_path));
   if (override_path)
diff --git a/base/test/test_reg_util_win.h b/base/test/test_reg_util_win.h
index 33bcd21..d74028a 100644
--- a/base/test/test_reg_util_win.h
+++ b/base/test/test_reg_util_win.h
@@ -39,6 +39,8 @@
   // Multiple overrides to the same hive are not supported and lead to undefined
   // behavior.
   // Optional return of the registry override path.
+  // Calls to these functions must be wrapped in ASSERT_NO_FATAL_FAILURE to
+  // ensure that tests do not proceeed in case of failure to override.
   void OverrideRegistry(HKEY override);
   void OverrideRegistry(HKEY override, base::string16* override_path);
 
@@ -53,7 +55,7 @@
 
    private:
     HKEY override_;
-    base::win::RegKey temp_key_;
+    base::string16 key_path_;
 
     DISALLOW_COPY_AND_ASSIGN(ScopedRegistryKeyOverride);
   };
diff --git a/base/test/test_reg_util_win_unittest.cc b/base/test/test_reg_util_win_unittest.cc
index 9534fef..ca3bc99 100644
--- a/base/test/test_reg_util_win_unittest.cc
+++ b/base/test/test_reg_util_win_unittest.cc
@@ -55,7 +55,7 @@
 
   void CreateKey(const base::string16& key_path) {
     base::win::RegKey key;
-    EXPECT_EQ(ERROR_SUCCESS,
+    ASSERT_EQ(ERROR_SUCCESS,
               key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS));
   }
 
@@ -74,7 +74,7 @@
 };
 
 TEST_F(RegistryOverrideManagerTest, Basic) {
-  CreateManager(base::Time::Now());
+  ASSERT_NO_FATAL_FAILURE(CreateManager(base::Time::Now()));
 
   base::win::RegKey create_key;
   EXPECT_EQ(ERROR_SUCCESS,
@@ -83,7 +83,7 @@
   EXPECT_EQ(ERROR_SUCCESS, create_key.WriteValue(kTestValueName, 42));
   create_key.Close();
 
-  AssertKeyExists(kTestKeyPath);
+  ASSERT_NO_FATAL_FAILURE(AssertKeyExists(kTestKeyPath));
 
   DWORD value;
   base::win::RegKey read_key;
@@ -96,7 +96,7 @@
 
   manager_.reset();
 
-  AssertKeyAbsent(kTestKeyPath);
+  ASSERT_NO_FATAL_FAILURE(AssertKeyAbsent(kTestKeyPath));
 }
 
 TEST_F(RegistryOverrideManagerTest, DeleteStaleKeys) {
@@ -114,20 +114,20 @@
   base::string16 path_future =
       FakeOverrideManagerPath(kTestTime + base::TimeDelta::FromMinutes(1));
 
-  CreateKey(path_garbage);
-  CreateKey(path_very_stale);
-  CreateKey(path_stale);
-  CreateKey(path_current);
-  CreateKey(path_future);
+  ASSERT_NO_FATAL_FAILURE(CreateKey(path_garbage));
+  ASSERT_NO_FATAL_FAILURE(CreateKey(path_very_stale));
+  ASSERT_NO_FATAL_FAILURE(CreateKey(path_stale));
+  ASSERT_NO_FATAL_FAILURE(CreateKey(path_current));
+  ASSERT_NO_FATAL_FAILURE(CreateKey(path_future));
 
-  CreateManager(kTestTime);
+  ASSERT_NO_FATAL_FAILURE(CreateManager(kTestTime));
   manager_.reset();
 
-  AssertKeyAbsent(path_garbage);
-  AssertKeyAbsent(path_very_stale);
-  AssertKeyAbsent(path_stale);
-  AssertKeyExists(path_current);
-  AssertKeyExists(path_future);
+  ASSERT_NO_FATAL_FAILURE(AssertKeyAbsent(path_garbage));
+  ASSERT_NO_FATAL_FAILURE(AssertKeyAbsent(path_very_stale));
+  ASSERT_NO_FATAL_FAILURE(AssertKeyAbsent(path_stale));
+  ASSERT_NO_FATAL_FAILURE(AssertKeyExists(path_current));
+  ASSERT_NO_FATAL_FAILURE(AssertKeyExists(path_future));
 }
 
 }  // namespace registry_util
diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
index 198a308..48c1dd58 100644
--- a/base/threading/thread_local_storage.cc
+++ b/base/threading/thread_local_storage.cc
@@ -92,7 +92,7 @@
 // This lock isn't needed until after we've constructed the per-thread TLS
 // vector, so it's safe to use.
 base::Lock* GetTLSMetadataLock() {
-  static auto lock = new base::Lock();
+  static auto* lock = new base::Lock();
   return lock;
 }
 TlsMetadata g_tls_metadata[kThreadLocalStorageSize];
diff --git a/base/threading/watchdog.cc b/base/threading/watchdog.cc
index a34c132..339cc56a 100644
--- a/base/threading/watchdog.cc
+++ b/base/threading/watchdog.cc
@@ -31,7 +31,7 @@
 };
 
 StaticData* GetStaticData() {
-  static auto static_data = new StaticData();
+  static auto* static_data = new StaticData();
   return static_data;
 }
 
diff --git a/base/threading/worker_pool.cc b/base/threading/worker_pool.cc
index 9d2b3ba..d47037d 100644
--- a/base/threading/worker_pool.cc
+++ b/base/threading/worker_pool.cc
@@ -118,7 +118,7 @@
 // static
 const scoped_refptr<TaskRunner>&
 WorkerPool::GetTaskRunner(bool tasks_are_slow) {
-  static auto task_runner_holder = new TaskRunnerHolder();
+  static auto* task_runner_holder = new TaskRunnerHolder();
   return task_runner_holder->taskrunners_[tasks_are_slow];
 }
 
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
index ada2058..2cceb0c 100644
--- a/base/time/time_posix.cc
+++ b/base/time/time_posix.cc
@@ -35,7 +35,7 @@
 // This prevents a crash on traversing the environment global and looking up
 // the 'TZ' variable in libc. See: crbug.com/390567.
 base::Lock* GetSysTimeToTimeStructLock() {
-  static auto lock = new base::Lock();
+  static auto* lock = new base::Lock();
   return lock;
 }
 
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index 9f2ce78..6dddb94 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -89,7 +89,7 @@
 
 // List of TraceEventFilter objects from the most recent tracing session.
 std::vector<std::unique_ptr<TraceEventFilter>>& GetCategoryGroupFilters() {
-  static auto filters = new std::vector<std::unique_ptr<TraceEventFilter>>();
+  static auto* filters = new std::vector<std::unique_ptr<TraceEventFilter>>();
   return *filters;
 }
 
@@ -1219,7 +1219,7 @@
     // call (if any), but don't bother if the new name is empty. Note this will
     // not detect a thread name change within the same char* buffer address: we
     // favor common case performance over corner case correctness.
-    static auto current_thread_name = new ThreadLocalPointer<const char>();
+    static auto* current_thread_name = new ThreadLocalPointer<const char>();
     if (new_name != current_thread_name->Get() && new_name && *new_name) {
       current_thread_name->Set(new_name);
 
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index dd2aa8f0..4b3f353 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -257,7 +257,6 @@
       device.RunShellCommand(
           ['log', '-p', 'i', '-t', _TAG, 'START %s' % test_name],
           check_return=True)
-      logcat_url = None
       time_ms = lambda: int(time.time() * 1e3)
       start_ms = time_ms()
 
@@ -265,16 +264,16 @@
           test_name.replace('#', '.'),
           time.strftime('%Y%m%dT%H%M%S', time.localtime()),
           device.serial)
+      logmon = logdog_logcat_monitor.LogdogLogcatMonitor(
+          device.adb, stream_name)
       with contextlib_ext.Optional(
-          logdog_logcat_monitor.LogdogLogcatMonitor(device.adb, stream_name),
-          self._test_instance.should_save_logcat) as logmon:
+          logmon, self._test_instance.should_save_logcat):
         with contextlib_ext.Optional(
             trace_event.trace(test_name),
             self._env.trace_output):
           output = device.StartInstrumentation(
               target, raw=True, extras=extras, timeout=timeout, retries=0)
-        if logmon:
-          logcat_url = logmon.GetLogcatURL()
+      logcat_url = logmon.GetLogcatURL()
     finally:
       device.RunShellCommand(
           ['log', '-p', 'i', '-t', _TAG, 'END %s' % test_name],
diff --git a/build/android/pylib/results/presentation/test_results_presentation.py b/build/android/pylib/results/presentation/test_results_presentation.py
index ef2157ed..e8a49086 100755
--- a/build/android/pylib/results/presentation/test_results_presentation.py
+++ b/build/android/pylib/results/presentation/test_results_presentation.py
@@ -13,8 +13,7 @@
 CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
 BASE_DIR = os.path.abspath(os.path.join(
     CURRENT_DIR, '..', '..', '..', '..', '..'))
-sys.path.append(os.path.join(BASE_DIR, 'third_party', 'markupsafe'))
-sys.path.append(os.path.join(BASE_DIR, 'third_party', 'jinja2'))
+sys.path.append(os.path.join(BASE_DIR, 'third_party'))
 import jinja2  # pylint: disable=import-error
 JINJA_ENVIRONMENT = jinja2.Environment(
     loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
diff --git a/build/config/allocator.gni b/build/config/allocator.gni
index 68f4e6b..6c3b48f 100644
--- a/build/config/allocator.gni
+++ b/build/config/allocator.gni
@@ -16,8 +16,9 @@
 # The debug CRT on Windows has some debug features that are incompatible with
 # the shim. NaCl in particular does seem to link some binaries statically
 # against the debug CRT with "is_nacl=false".
-if ((is_linux || is_android || (is_win && !is_component_build && !is_debug)) &&
-    !is_asan && !is_lsan && !is_tsan && !is_msan) {
+if ((is_linux || is_android || is_mac ||
+     (is_win && !is_component_build && !is_debug)) && !is_asan && !is_lsan &&
+    !is_tsan && !is_msan) {
   _default_use_experimental_allocator_shim = true
 } else {
   _default_use_experimental_allocator_shim = false
diff --git a/build/package_mac_toolchain.py b/build/package_mac_toolchain.py
index 49eec87..ecdc4d7 100755
--- a/build/package_mac_toolchain.py
+++ b/build/package_mac_toolchain.py
@@ -45,7 +45,24 @@
 ]
 
 MAC_EXCLUDE_FOLDERS = [
-'Contents/Developer/Platforms/iPhoneOS.platform',
+# The only thing we need in iPhoneOS.platform on mac is:
+#  \Developer\Library\Xcode\PrivatePlugins
+#  \Info.Plist.
+#  This is the cleanest way to get these.
+'Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks',
+'Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/GPUTools',
+'Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/'
+    'GPUToolsPlatform',
+'Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/'
+    'PrivateFrameworks',
+'Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr',
+'Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs',
+'Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport',
+'Contents/Developer/Platforms/iPhoneOS.platform/Library',
+'Contents/Developer/Platforms/iPhoneOS.platform/usr',
+
+# iPhoneSimulator has a similar requirement, but the bulk of the binary size is
+# in \Developer\SDKs, so only excluding that here.
 'Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs',
 ]
 
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc
index 59493d0..80dfae16 100644
--- a/cc/animation/animation_host.cc
+++ b/cc/animation/animation_host.cc
@@ -182,7 +182,7 @@
 }
 
 void AnimationHost::PushPropertiesTo(MutatorHost* mutator_host_impl) {
-  auto host_impl = static_cast<AnimationHost*>(mutator_host_impl);
+  auto* host_impl = static_cast<AnimationHost*>(mutator_host_impl);
 
   if (needs_push_properties_) {
     needs_push_properties_ = false;
@@ -303,7 +303,7 @@
   if (!NeedsTickAnimations())
     return false;
 
-  auto animation_events = static_cast<AnimationEvents*>(mutator_events);
+  auto* animation_events = static_cast<AnimationEvents*>(mutator_events);
 
   TRACE_EVENT0("cc", "AnimationHost::UpdateAnimationState");
   PlayersList ticking_players_copy = ticking_players_;
diff --git a/cc/ipc/cc_param_traits.cc b/cc/ipc/cc_param_traits.cc
index 495534a..4c562f4 100644
--- a/cc/ipc/cc_param_traits.cc
+++ b/cc/ipc/cc_param_traits.cc
@@ -328,6 +328,7 @@
   WriteParam(m, p.transform_to_root_target);
   WriteParam(m, p.filters);
   WriteParam(m, p.background_filters);
+  WriteParam(m, p.color_space);
   WriteParam(m, p.has_transparent_background);
   WriteParam(m, base::checked_cast<uint32_t>(p.quad_list.size()));
 
@@ -437,6 +438,7 @@
   gfx::Transform transform_to_root_target;
   cc::FilterOperations filters;
   cc::FilterOperations background_filters;
+  gfx::ColorSpace color_space;
   bool has_transparent_background;
   uint32_t quad_list_size;
 
@@ -445,12 +447,13 @@
       !ReadParam(m, iter, &transform_to_root_target) ||
       !ReadParam(m, iter, &filters) ||
       !ReadParam(m, iter, &background_filters) ||
+      !ReadParam(m, iter, &color_space) ||
       !ReadParam(m, iter, &has_transparent_background) ||
       !ReadParam(m, iter, &quad_list_size))
     return false;
 
   p->SetAll(id, output_rect, damage_rect, transform_to_root_target, filters,
-            background_filters, has_transparent_background);
+            background_filters, color_space, has_transparent_background);
 
   for (uint32_t i = 0; i < quad_list_size; ++i) {
     cc::DrawQuad::Material material;
@@ -537,6 +540,8 @@
   l->append(", ");
   LogParam(p.background_filters, l);
   l->append(", ");
+  LogParam(p.color_space, l);
+  l->append(", ");
   LogParam(p.has_transparent_background, l);
   l->append(", ");
 
diff --git a/cc/ipc/cc_param_traits_unittest.cc b/cc/ipc/cc_param_traits_unittest.cc
index 9f1ea9f..fad9c53 100644
--- a/cc/ipc/cc_param_traits_unittest.cc
+++ b/cc/ipc/cc_param_traits_unittest.cc
@@ -75,6 +75,7 @@
                   b->background_filters.at(i).image_filter()->countInputs());
       }
     }
+    EXPECT_EQ(a->color_space, b->color_space);
     EXPECT_EQ(a->has_transparent_background, b->has_transparent_background);
   }
 
@@ -278,9 +279,9 @@
   ResourceId arbitrary_resourceid3 = 23;
   ResourceId arbitrary_resourceid4 = 16;
   SkScalar arbitrary_sigma = SkFloatToScalar(2.0f);
-  YUVVideoDrawQuad::ColorSpace arbitrary_color_space =
+  gfx::ColorSpace arbitrary_color_space = gfx::ColorSpace::CreateREC601();
+  YUVVideoDrawQuad::ColorSpace arbitrary_video_color_space =
       YUVVideoDrawQuad::REC_601;
-  gfx::ColorSpace arbitrary_video_color_space = gfx::ColorSpace::CreateREC601();
 
   int child_id = 30;
   int root_id = 14;
@@ -298,16 +299,19 @@
   std::unique_ptr<RenderPass> child_pass_in = RenderPass::Create();
   child_pass_in->SetAll(child_id, arbitrary_rect2, arbitrary_rect3,
                         arbitrary_matrix2, arbitrary_filters1,
-                        arbitrary_filters2, arbitrary_bool2);
+                        arbitrary_filters2, arbitrary_color_space,
+                        arbitrary_bool2);
 
   std::unique_ptr<RenderPass> child_pass_cmp = RenderPass::Create();
   child_pass_cmp->SetAll(child_id, arbitrary_rect2, arbitrary_rect3,
                          arbitrary_matrix2, arbitrary_filters1,
-                         arbitrary_filters2, arbitrary_bool2);
+                         arbitrary_filters2, arbitrary_color_space,
+                         arbitrary_bool2);
 
   std::unique_ptr<RenderPass> pass_in = RenderPass::Create();
   pass_in->SetAll(root_id, arbitrary_rect1, arbitrary_rect2, arbitrary_matrix1,
-                  arbitrary_filters2, arbitrary_filters1, arbitrary_bool1);
+                  arbitrary_filters2, arbitrary_filters1, arbitrary_color_space,
+                  arbitrary_bool1);
 
   SharedQuadState* shared_state1_in = pass_in->CreateAndAppendSharedQuadState();
   shared_state1_in->SetAll(arbitrary_matrix1, arbitrary_size1, arbitrary_rect1,
@@ -316,7 +320,8 @@
 
   std::unique_ptr<RenderPass> pass_cmp = RenderPass::Create();
   pass_cmp->SetAll(root_id, arbitrary_rect1, arbitrary_rect2, arbitrary_matrix1,
-                   arbitrary_filters2, arbitrary_filters1, arbitrary_bool1);
+                   arbitrary_filters2, arbitrary_filters1,
+                   arbitrary_color_space, arbitrary_bool1);
 
   SharedQuadState* shared_state1_cmp =
       pass_cmp->CreateAndAppendSharedQuadState();
@@ -412,7 +417,7 @@
       arbitrary_rect1_inside_rect1, arbitrary_bool1, arbitrary_rectf1,
       arbitrary_rectf2, arbitrary_size1, arbitrary_size2, arbitrary_resourceid1,
       arbitrary_resourceid2, arbitrary_resourceid3, arbitrary_resourceid4,
-      arbitrary_color_space, arbitrary_video_color_space, arbitrary_float1,
+      arbitrary_video_color_space, arbitrary_color_space, arbitrary_float1,
       arbitrary_float2, arbitrary_int);
   pass_cmp->CopyFromAndAppendDrawQuad(yuvvideo_in,
                                       yuvvideo_in->shared_quad_state);
@@ -493,7 +498,8 @@
 TEST_F(CCParamTraitsTest, UnusedSharedQuadStates) {
   std::unique_ptr<RenderPass> pass_in = RenderPass::Create();
   pass_in->SetAll(1, gfx::Rect(100, 100), gfx::Rect(), gfx::Transform(),
-                  FilterOperations(), FilterOperations(), false);
+                  FilterOperations(), FilterOperations(),
+                  gfx::ColorSpace::CreateSRGB(), false);
 
   // The first SharedQuadState is used.
   SharedQuadState* shared_state1_in = pass_in->CreateAndAppendSharedQuadState();
diff --git a/cc/ipc/cc_serialization_perftest.cc b/cc/ipc/cc_serialization_perftest.cc
index a63324a..df6a2c80 100644
--- a/cc/ipc/cc_serialization_perftest.cc
+++ b/cc/ipc/cc_serialization_perftest.cc
@@ -286,8 +286,16 @@
                          UseSingleSharedQuadState::YES);
 }
 
+// Done for https://crbug.com/691730. Test is too slow as is.
+#if defined(OS_ANDROID)
+#define MAYBE_DelegatedFrame_ManyQuads_10_100000 \
+  DISABLED_DelegatedFrame_ManyQuads_10_100000
+#else
+#define MAYBE_DelegatedFrame_ManyQuads_10_100000 \
+  DelegatedFrame_ManyQuads_10_100000
+#endif
 // Test for compositor frames with 10 render pass and each with 100000 quads.
-TEST_F(CCSerializationPerfTest, DelegatedFrame_ManyQuads_10_100000) {
+TEST_F(CCSerializationPerfTest, MAYBE_DelegatedFrame_ManyQuads_10_100000) {
   // One shared quad state for all quads in one render pass.
   RunCompositorFrameTest("DelegatedFrame_ManyQuads_10_100000", 100000, 10,
                          UseSingleSharedQuadState::YES);
diff --git a/cc/ipc/render_pass.mojom b/cc/ipc/render_pass.mojom
index 954f9cda..cbc94be6 100644
--- a/cc/ipc/render_pass.mojom
+++ b/cc/ipc/render_pass.mojom
@@ -7,6 +7,7 @@
 import "cc/ipc/filter_operations.mojom";
 import "cc/ipc/quads.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
+import "ui/gfx/mojo/color_space.mojom";
 import "ui/gfx/mojo/transform.mojom";
 
 // See cc/quads/render_pass.h.
@@ -17,6 +18,7 @@
   gfx.mojom.Transform transform_to_root_target;
   cc.mojom.FilterOperations filters;
   cc.mojom.FilterOperations background_filters;
+  gfx.mojom.ColorSpace color_space;
   bool has_transparent_background;
   array<DrawQuad> quad_list;
 };
diff --git a/cc/ipc/render_pass_struct_traits.cc b/cc/ipc/render_pass_struct_traits.cc
index c2de5a7..df02f6a 100644
--- a/cc/ipc/render_pass_struct_traits.cc
+++ b/cc/ipc/render_pass_struct_traits.cc
@@ -19,7 +19,8 @@
       !data.ReadDamageRect(&(*out)->damage_rect) ||
       !data.ReadTransformToRootTarget(&(*out)->transform_to_root_target) ||
       !data.ReadFilters(&(*out)->filters) ||
-      !data.ReadBackgroundFilters(&(*out)->background_filters)) {
+      !data.ReadBackgroundFilters(&(*out)->background_filters) ||
+      !data.ReadColorSpace(&(*out)->color_space)) {
     return false;
   }
   (*out)->id = data.id();
diff --git a/cc/ipc/render_pass_struct_traits.h b/cc/ipc/render_pass_struct_traits.h
index 12441523..ee69709ba 100644
--- a/cc/ipc/render_pass_struct_traits.h
+++ b/cc/ipc/render_pass_struct_traits.h
@@ -9,6 +9,7 @@
 #include "cc/ipc/quads_struct_traits.h"
 #include "cc/ipc/render_pass.mojom-shared.h"
 #include "cc/quads/render_pass.h"
+#include "ui/gfx/ipc/color/gfx_param_traits.h"
 #include "ui/gfx/mojo/transform_struct_traits.h"
 
 namespace mojo {
@@ -46,6 +47,11 @@
     return input->background_filters;
   }
 
+  static const gfx::ColorSpace& color_space(
+      const std::unique_ptr<cc::RenderPass>& input) {
+    return input->color_space;
+  }
+
   static bool has_transparent_background(
       const std::unique_ptr<cc::RenderPass>& input) {
     return input->has_transparent_background;
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index 5d22e49..fe8f6ac 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -677,10 +677,11 @@
   background_filters.Append(FilterOperation::CreateSaturateFilter(4.f));
   background_filters.Append(FilterOperation::CreateZoomFilter(2.0f, 1));
   background_filters.Append(FilterOperation::CreateSaturateFilter(2.f));
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
   const bool has_transparent_background = true;
   std::unique_ptr<RenderPass> input = RenderPass::Create();
   input->SetAll(id, output_rect, damage_rect, transform_to_root, filters,
-                background_filters, has_transparent_background);
+                background_filters, color_space, has_transparent_background);
 
   SharedQuadState* shared_state_1 = input->CreateAndAppendSharedQuadState();
   shared_state_1->SetAll(
@@ -729,6 +730,7 @@
   EXPECT_EQ(output_rect, output->output_rect);
   EXPECT_EQ(damage_rect, output->damage_rect);
   EXPECT_EQ(transform_to_root, output->transform_to_root_target);
+  EXPECT_EQ(color_space, output->color_space);
   EXPECT_EQ(has_transparent_background, output->has_transparent_background);
   EXPECT_EQ(filters, output->filters);
   EXPECT_EQ(background_filters, output->background_filters);
@@ -788,10 +790,11 @@
   const gfx::Transform transform_to_root =
       gfx::Transform(1.0, 0.5, 0.5, -0.5, -1.0, 0.0);
   const gfx::Rect damage_rect(56, 123, 19, 43);
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateSCRGBLinear();
   const bool has_transparent_background = true;
   std::unique_ptr<RenderPass> input = RenderPass::Create();
   input->SetAll(id, output_rect, damage_rect, transform_to_root,
-                FilterOperations(), FilterOperations(),
+                FilterOperations(), FilterOperations(), color_space,
                 has_transparent_background);
 
   // Unlike the previous test, don't add any quads to the list; we need to
@@ -808,6 +811,7 @@
   EXPECT_EQ(damage_rect, output->damage_rect);
   EXPECT_EQ(transform_to_root, output->transform_to_root_target);
   EXPECT_EQ(has_transparent_background, output->has_transparent_background);
+  EXPECT_EQ(color_space, output->color_space);
 }
 
 TEST_F(StructTraitsTest, ReturnedResource) {
diff --git a/cc/layers/nine_patch_layer_impl_unittest.cc b/cc/layers/nine_patch_layer_impl_unittest.cc
index 66dc072..d704a83 100644
--- a/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -201,7 +201,7 @@
   // Verify UV rects
   gfx::Rect bitmap_rect(bitmap_size);
   Region tex_remaining(bitmap_rect);
-  for (const auto& quad : quads) {
+  for (auto* quad : quads) {
     const TextureDrawQuad* tex_quad = TextureDrawQuad::MaterialCast(quad);
     gfx::RectF tex_rect =
         gfx::BoundingRect(tex_quad->uv_top_left, tex_quad->uv_bottom_right);
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 0273c4b..3b88d774 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -209,7 +209,6 @@
 
 void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
                                float device_scale_factor,
-                               const gfx::ColorSpace& device_color_space,
                                const gfx::Size& device_viewport_size) {
   DCHECK(visible_);
   TRACE_EVENT0("cc", "DirectRenderer::DrawFrame");
@@ -246,7 +245,6 @@
       overlay_processor_->GetAndResetOverlayDamage());
   current_frame()->root_damage_rect.Intersect(gfx::Rect(device_viewport_size));
   current_frame()->device_viewport_size = device_viewport_size;
-  current_frame()->device_color_space = device_color_space;
 
   // Only reshape when we know we are going to draw. Otherwise, the reshape
   // can leave the window at the wrong size if we never draw and the proper
@@ -256,12 +254,12 @@
   bool use_stencil = overdraw_feedback_;
   if (device_viewport_size != reshape_surface_size_ ||
       device_scale_factor != reshape_device_scale_factor_ ||
-      device_color_space != reshape_device_color_space_ ||
+      root_render_pass->color_space != reshape_device_color_space_ ||
       frame_has_alpha != reshape_has_alpha_ ||
       use_stencil != reshape_use_stencil_) {
     reshape_surface_size_ = device_viewport_size;
     reshape_device_scale_factor_ = device_scale_factor;
-    reshape_device_color_space_ = device_color_space;
+    reshape_device_color_space_ = root_render_pass->color_space;
     reshape_has_alpha_ =
         current_frame()->root_render_pass->has_transparent_background;
     reshape_use_stencil_ = overdraw_feedback_;
@@ -600,9 +598,9 @@
   size.Enlarge(enlarge_pass_texture_amount_.width(),
                enlarge_pass_texture_amount_.height());
   if (!texture->id()) {
-    texture->Allocate(size,
-                      ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
-                      BackbufferFormat(), current_frame()->device_color_space);
+    texture->Allocate(
+        size, ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
+        BackbufferFormat(), current_frame()->current_render_pass->color_space);
   }
   DCHECK(texture->id());
 
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index 0c8df9eb..c7a0b5e 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -55,7 +55,6 @@
   bool HasAllocatedResourcesForTesting(int render_pass_id) const;
   void DrawFrame(RenderPassList* render_passes_in_draw_order,
                  float device_scale_factor,
-                 const gfx::ColorSpace& device_color_space,
                  const gfx::Size& device_viewport_size);
 
   // Public interface implemented by subclasses.
@@ -83,7 +82,6 @@
 
     gfx::Rect root_damage_rect;
     gfx::Size device_viewport_size;
-    gfx::ColorSpace device_color_space;
 
     gfx::Transform projection_matrix;
     gfx::Transform window_matrix;
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index f9cc3d7..cb76e74 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -882,7 +882,7 @@
   // CopyTexImage2D fails when called on a texture having immutable storage.
   device_background_texture->Allocate(
       bounding_rect.size(), ResourceProvider::TEXTURE_HINT_DEFAULT,
-      BackbufferFormat(), current_frame()->device_color_space);
+      BackbufferFormat(), current_frame()->current_render_pass->color_space);
   {
     ResourceProvider::ScopedWriteLockGL lock(
         resource_provider_, device_background_texture->id(), false);
@@ -1034,7 +1034,7 @@
     // RGBA_8888 here is arbitrary and unused.
     Resource tile_resource(tile_quad->resource_id(), tile_quad->texture_size,
                            ResourceFormat::RGBA_8888,
-                           current_frame()->device_color_space);
+                           current_frame()->current_render_pass->color_space);
     // The projection matrix used by GLRenderer has a flip.  As tile texture
     // inputs are oriented opposite to framebuffer outputs, don't flip via
     // texture coords and let the projection matrix naturallyd o it.
@@ -1309,7 +1309,7 @@
                     tex_coord_precision, sampler_type, shader_blend_mode,
                     params->use_aa ? USE_AA : NO_AA, mask_mode,
                     mask_for_background, params->use_color_matrix),
-                current_frame()->device_color_space);
+                current_frame()->current_render_pass->color_space);
 }
 
 void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) {
@@ -2092,7 +2092,8 @@
   // resource, quad->color_space, and quad->video_color_space. Remove two of
   // them.
   gfx::ColorSpace src_color_space = quad->video_color_space;
-  gfx::ColorSpace dst_color_space = current_frame()->device_color_space;
+  gfx::ColorSpace dst_color_space =
+      current_frame()->current_render_pass->color_space;
   if (!base::FeatureList::IsEnabled(media::kVideoColorManagement)) {
     if (!settings_->enable_color_correct_rendering)
       dst_color_space = gfx::ColorSpace();
@@ -3020,7 +3021,7 @@
                                const gfx::ColorSpace& src_color_space) {
   gfx::ColorSpace dst_color_space;
   if (settings_->enable_color_correct_rendering)
-    dst_color_space = current_frame()->device_color_space;
+    dst_color_space = current_frame()->current_render_pass->color_space;
   SetUseProgram(program_key, src_color_space, dst_color_space);
 }
 
@@ -3297,7 +3298,7 @@
 
   *resource = overlay_resource_pool_->AcquireResource(
       gfx::Size(iosurface_width, iosurface_height), ResourceFormat::RGBA_8888,
-      current_frame()->device_color_space);
+      current_frame()->current_render_pass->color_space);
   *new_bounds =
       gfx::RectF(updated_dst_rect.x(), updated_dst_rect.y(),
                  (*resource)->size().width(), (*resource)->size().height());
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index c4683999..0cf7d50 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -66,8 +66,7 @@
     return render_passes_in_draw_order_.back().get();
   }
   void DrawFrame(GLRenderer* renderer, const gfx::Size& viewport_size) {
-    renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, gfx::ColorSpace(),
-                        viewport_size);
+    renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_size);
   }
 
   RenderPassList render_passes_in_draw_order_;
@@ -1560,7 +1559,7 @@
     renderer_->DecideRenderPassAllocationsForFrame(
         render_passes_in_draw_order_);
     renderer_->DrawFrame(&render_passes_in_draw_order_, device_scale_factor,
-                         gfx::ColorSpace(), viewport_size);
+                         viewport_size);
   }
 
   RendererSettings settings_;
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 8dcd8dd..8042cd6 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -1424,7 +1424,7 @@
   }
 
   void DrawFrame(RenderPassList* pass_list, const gfx::Size& viewport_size) {
-    renderer_->DrawFrame(pass_list, 1.f, gfx::ColorSpace(), viewport_size);
+    renderer_->DrawFrame(pass_list, 1.f, viewport_size);
   }
   void SwapBuffers() {
     renderer_->SwapBuffers(std::vector<ui::LatencyInfo>());
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index a259eed..15da1b6 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -67,8 +67,7 @@
                        base::Unretained(&bitmap_result),
                        loop.QuitClosure())));
 
-    renderer()->DrawFrame(list, device_scale_factor, gfx::ColorSpace(),
-                          viewport_size);
+    renderer()->DrawFrame(list, device_scale_factor, viewport_size);
     loop.Run();
     return bitmap_result;
   }
@@ -424,8 +423,7 @@
   root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
 
   renderer()->DecideRenderPassAllocationsForFrame(list);
-  renderer()->DrawFrame(&list, device_scale_factor, gfx::ColorSpace(),
-                        viewport_size);
+  renderer()->DrawFrame(&list, device_scale_factor, viewport_size);
 
   // The damage rect should be reported to the SoftwareOutputDevice.
   EXPECT_EQ(gfx::Rect(2, 2, 3, 3), device->damage_rect_at_start());
diff --git a/cc/playback/discardable_image_map_unittest.cc b/cc/playback/discardable_image_map_unittest.cc
index 926d8aea..672e8617 100644
--- a/cc/playback/discardable_image_map_unittest.cc
+++ b/cc/playback/discardable_image_map_unittest.cc
@@ -535,11 +535,17 @@
   // | x |   | x |   |
   // |---|---|---|---|
   sk_sp<SkImage> discardable_image[4][4];
+
+  // Skia doesn't allow shader instantiation with non-invertible local
+  // transforms, so we can't let the scale drop all the way to 0.
+  static constexpr float kMinScale = 0.1f;
+
   for (int y = 0; y < 4; ++y) {
     for (int x = 0; x < 4; ++x) {
       if ((x + y) & 1) {
         discardable_image[y][x] = CreateDiscardableImage(gfx::Size(500, 500));
-        SkMatrix scale = SkMatrix::MakeScale(x * 0.5f, y * 0.5f);
+        SkMatrix scale = SkMatrix::MakeScale(std::max(x * 0.5f, kMinScale),
+                                             std::max(y * 0.5f, kMinScale));
         SkPaint paint;
         paint.setShader(discardable_image[y][x]->makeShader(
             SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &scale));
@@ -570,8 +576,8 @@
                                                                 << y;
         EXPECT_EQ(gfx::Rect(x * 512 + 6, y * 512 + 6, 500, 500),
                   images[0].image_rect);
-        EXPECT_EQ(x * 0.5f, images[0].scale.fWidth);
-        EXPECT_EQ(y * 0.5f, images[0].scale.fHeight);
+        EXPECT_EQ(std::max(x * 0.5f, kMinScale), images[0].scale.fWidth);
+        EXPECT_EQ(std::max(y * 0.5f, kMinScale), images[0].scale.fHeight);
       } else {
         EXPECT_EQ(0u, images.size()) << x << " " << y;
       }
diff --git a/cc/quads/render_pass.cc b/cc/quads/render_pass.cc
index fd741a5..3ad5fb0 100644
--- a/cc/quads/render_pass.cc
+++ b/cc/quads/render_pass.cc
@@ -90,7 +90,8 @@
   std::unique_ptr<RenderPass> copy_pass(
       Create(shared_quad_state_list.size(), quad_list.size()));
   copy_pass->SetAll(new_id, output_rect, damage_rect, transform_to_root_target,
-                    filters, background_filters, has_transparent_background);
+                    filters, background_filters, color_space,
+                    has_transparent_background);
   return copy_pass;
 }
 
@@ -102,7 +103,8 @@
   std::unique_ptr<RenderPass> copy_pass(
       Create(shared_quad_state_list.size(), quad_list.size()));
   copy_pass->SetAll(id, output_rect, damage_rect, transform_to_root_target,
-                    filters, background_filters, has_transparent_background);
+                    filters, background_filters, color_space,
+                    has_transparent_background);
   for (auto* shared_quad_state : shared_quad_state_list) {
     SharedQuadState* copy_shared_quad_state =
         copy_pass->CreateAndAppendSharedQuadState();
@@ -164,6 +166,7 @@
                         const gfx::Transform& transform_to_root_target,
                         const FilterOperations& filters,
                         const FilterOperations& background_filters,
+                        const gfx::ColorSpace& color_space,
                         bool has_transparent_background) {
   DCHECK(id);
 
@@ -173,6 +176,7 @@
   this->transform_to_root_target = transform_to_root_target;
   this->filters = filters;
   this->background_filters = background_filters;
+  this->color_space = color_space;
   this->has_transparent_background = has_transparent_background;
 
   DCHECK(quad_list.empty());
diff --git a/cc/quads/render_pass.h b/cc/quads/render_pass.h
index cc87ff6..274c27e 100644
--- a/cc/quads/render_pass.h
+++ b/cc/quads/render_pass.h
@@ -19,6 +19,7 @@
 #include "cc/output/filter_operations.h"
 #include "cc/quads/draw_quad.h"
 #include "cc/quads/largest_draw_quad.h"
+#include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/transform.h"
@@ -84,6 +85,7 @@
               const gfx::Transform& transform_to_root_target,
               const FilterOperations& filters,
               const FilterOperations& background_filters,
+              const gfx::ColorSpace& color_space,
               bool has_transparent_background);
 
   void AsValueInto(base::trace_event::TracedValue* dict) const;
@@ -120,6 +122,9 @@
   // background of the render pass, from behind it.
   FilterOperations background_filters;
 
+  // The color space into which content will be rendered for this render pass.
+  gfx::ColorSpace color_space;
+
   // If false, the pixels in the render pass' texture are all opaque.
   bool has_transparent_background = true;
 
diff --git a/cc/quads/render_pass_unittest.cc b/cc/quads/render_pass_unittest.cc
index 3854471..3587a4d5 100644
--- a/cc/quads/render_pass_unittest.cc
+++ b/cc/quads/render_pass_unittest.cc
@@ -28,6 +28,7 @@
   gfx::Transform transform_to_root_target;
   FilterOperations filters;
   FilterOperations background_filters;
+  gfx::ColorSpace color_space;
   bool has_transparent_background;
   std::vector<std::unique_ptr<CopyOutputRequest>> copy_callbacks;
   QuadList quad_list;
@@ -76,11 +77,12 @@
   filters.Append(FilterOperation::CreateOpacityFilter(0.5));
   FilterOperations background_filters;
   background_filters.Append(FilterOperation::CreateInvertFilter(1.0));
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
   bool has_transparent_background = true;
 
   std::unique_ptr<RenderPass> pass = RenderPass::Create();
   pass->SetAll(id, output_rect, damage_rect, transform_to_root, filters,
-               background_filters, has_transparent_background);
+               background_filters, color_space, has_transparent_background);
   pass->copy_requests.push_back(CopyOutputRequest::CreateEmptyRequest());
 
   // Stick a quad in the pass, this should not get copied.
@@ -124,11 +126,12 @@
   filters.Append(FilterOperation::CreateOpacityFilter(0.5));
   FilterOperations background_filters;
   background_filters.Append(FilterOperation::CreateInvertFilter(1.0));
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateXYZD50();
   bool has_transparent_background = true;
 
   std::unique_ptr<RenderPass> pass = RenderPass::Create();
   pass->SetAll(id, output_rect, damage_rect, transform_to_root, filters,
-               background_filters, has_transparent_background);
+               background_filters, color_space, has_transparent_background);
 
   // Two quads using one shared state.
   SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
@@ -174,12 +177,13 @@
   contrib_filters.Append(FilterOperation::CreateSepiaFilter(0.5));
   FilterOperations contrib_background_filters;
   contrib_background_filters.Append(FilterOperation::CreateSaturateFilter(1));
+  gfx::ColorSpace contrib_color_space = gfx::ColorSpace::CreateSCRGBLinear();
   bool contrib_has_transparent_background = true;
 
   std::unique_ptr<RenderPass> contrib = RenderPass::Create();
   contrib->SetAll(contrib_id, contrib_output_rect, contrib_damage_rect,
                   contrib_transform_to_root, contrib_filters,
-                  contrib_background_filters,
+                  contrib_background_filters, contrib_color_space,
                   contrib_has_transparent_background);
 
   SharedQuadState* contrib_shared_state =
@@ -222,11 +226,12 @@
   filters.Append(FilterOperation::CreateOpacityFilter(0.5));
   FilterOperations background_filters;
   background_filters.Append(FilterOperation::CreateInvertFilter(1.0));
+  gfx::ColorSpace color_space = gfx::ColorSpace::CreateSCRGBLinear();
   bool has_transparent_background = true;
 
   std::unique_ptr<RenderPass> pass = RenderPass::Create();
   pass->SetAll(id, output_rect, damage_rect, transform_to_root, filters,
-               background_filters, has_transparent_background);
+               background_filters, color_space, has_transparent_background);
 
   // A shared state with a quad.
   SharedQuadState* shared_state1 = pass->CreateAndAppendSharedQuadState();
diff --git a/cc/surfaces/compositor_frame_sink_support.cc b/cc/surfaces/compositor_frame_sink_support.cc
index b6b2a66..2b8860b4 100644
--- a/cc/surfaces/compositor_frame_sink_support.cc
+++ b/cc/surfaces/compositor_frame_sink_support.cc
@@ -73,31 +73,6 @@
       local_surface_id, std::move(frame),
       base::Bind(&CompositorFrameSinkSupport::DidReceiveCompositorFrameAck,
                  weak_factory_.GetWeakPtr()));
-
-  if (surface_manager_->using_surface_references()) {
-    SurfaceId last_surface_id = reference_tracker_.current_surface_id();
-
-    // Populate list of surface references to add and remove based on reference
-    // surfaces in current frame compared with the last frame. The list of
-    // surface references includes references from both the pending and active
-    // frame if any.
-    SurfaceId current_surface_id(frame_sink_id_, local_surface_id);
-    Surface* surface = surface_manager_->GetSurfaceForId(current_surface_id);
-    // TODO(fsamuel): This is pretty inefficent. We copy over referenced
-    // surfaces. Then we pass them into the ReferencedSurfaceTracker to copy
-    // them again into a set. ReferencedSurfaceTracker should just take in two
-    // vectors, one for pending referenced surfaces and one for active
-    // referenced surfaces.
-    std::vector<SurfaceId> referenced_surfaces =
-        surface->active_referenced_surfaces();
-
-    referenced_surfaces.insert(referenced_surfaces.end(),
-                               surface->pending_referenced_surfaces().begin(),
-                               surface->pending_referenced_surfaces().end());
-    reference_tracker_.UpdateReferences(local_surface_id, referenced_surfaces);
-
-    UpdateSurfaceReferences(last_surface_id, local_surface_id);
-  }
 }
 
 void CompositorFrameSinkSupport::Require(const LocalSurfaceId& local_surface_id,
@@ -186,6 +161,25 @@
   child_frame_sinks_.erase(it);
 }
 
+void CompositorFrameSinkSupport::ReferencedSurfacesChanged(
+    const LocalSurfaceId& local_surface_id,
+    const std::vector<SurfaceId>* active_referenced_surfaces,
+    const std::vector<SurfaceId>* pending_referenced_surfaces) {
+  if (!surface_manager_->using_surface_references())
+    return;
+
+  // Populate list of surface references to add and remove based on reference
+  // surfaces in current frame compared with the last frame. The list of
+  // surface references includes references from both the pending and active
+  // frame if any.
+  reference_tracker_.UpdateReferences(local_surface_id,
+                                      active_referenced_surfaces,
+                                      pending_referenced_surfaces);
+
+  SurfaceId last_surface_id = reference_tracker_.current_surface_id();
+  UpdateSurfaceReferences(last_surface_id, local_surface_id);
+}
+
 void CompositorFrameSinkSupport::ReturnResources(
     const ReturnedResourceArray& resources) {
   if (resources.empty())
diff --git a/cc/surfaces/compositor_frame_sink_support.h b/cc/surfaces/compositor_frame_sink_support.h
index b1c18d3..2779a12 100644
--- a/cc/surfaces/compositor_frame_sink_support.h
+++ b/cc/surfaces/compositor_frame_sink_support.h
@@ -68,6 +68,10 @@
   void DidReceiveCompositorFrameAck();
 
   // SurfaceFactoryClient implementation.
+  void ReferencedSurfacesChanged(
+      const LocalSurfaceId& local_surface_id,
+      const std::vector<SurfaceId>* active_referenced_surfaces,
+      const std::vector<SurfaceId>* pending_referenced_surfaces) override;
   void ReturnResources(const ReturnedResourceArray& resources) override;
   void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override;
   void WillDrawSurface(const LocalSurfaceId& local_surface_id,
diff --git a/cc/surfaces/compositor_frame_sink_support_unittest.cc b/cc/surfaces/compositor_frame_sink_support_unittest.cc
index 7984c872..acd242a 100644
--- a/cc/surfaces/compositor_frame_sink_support_unittest.cc
+++ b/cc/surfaces/compositor_frame_sink_support_unittest.cc
@@ -573,5 +573,113 @@
   EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id));
 }
 
+// The parent Surface is blocked on |child_id2| which is blocked on |child_id3|.
+// child_support1 evicts its blocked Surface. The parent surface should
+// activate.
+TEST_F(CompositorFrameSinkSupportTest, EvictSurfaceWithPendingFrame) {
+  const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
+  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+  // Submit a CompositorFrame that depends on |child_id1|.
+  parent_support().SubmitCompositorFrame(parent_id1.local_surface_id(),
+                                         MakeCompositorFrame({child_id1}));
+
+  // Verify that the CompositorFrame is blocked on |child_id1|.
+  EXPECT_FALSE(parent_surface()->HasActiveFrame());
+  EXPECT_TRUE(parent_surface()->HasPendingFrame());
+  EXPECT_THAT(parent_surface()->blocking_surfaces_for_testing(),
+              UnorderedElementsAre(child_id1));
+
+  // Submit a CompositorFrame that depends on |child_id2|.
+  child_support1().SubmitCompositorFrame(child_id1.local_surface_id(),
+                                         MakeCompositorFrame({child_id2}));
+
+  // Verify that the CompositorFrame is blocked on |child_id2|.
+  EXPECT_FALSE(child_surface1()->HasActiveFrame());
+  EXPECT_TRUE(child_surface1()->HasPendingFrame());
+  EXPECT_THAT(child_surface1()->blocking_surfaces_for_testing(),
+              UnorderedElementsAre(child_id2));
+
+  // Evict child_support1's current Surface.
+  // TODO(fsamuel): EvictFrame => EvictCurrentSurface.
+  child_support1().EvictFrame();
+
+  // The parent Surface should immediately activate.
+  EXPECT_TRUE(parent_surface()->HasActiveFrame());
+  EXPECT_FALSE(parent_surface()->HasPendingFrame());
+  EXPECT_THAT(parent_surface()->blocking_surfaces_for_testing(), IsEmpty());
+  EXPECT_FALSE(dependency_tracker().has_deadline());
+}
+
+// This test verifies that if a surface has both a pending and active
+// CompositorFrame and the pending CompositorFrame activates, replacing the
+// existing active CompositorFrame, then the surface reference hierarchy will be
+// updated allowing garbage collection of surfaces that are no longer
+// referenced.
+TEST_F(CompositorFrameSinkSupportTest, DropStaleReferencesAfterActivation) {
+  const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
+  const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
+  const SurfaceId child_id2 = MakeSurfaceId(kChildFrameSink2, 1);
+
+  // The parent submits a CompositorFrame that depends on |child_id1| before the
+  // child submits a CompositorFrame.
+  parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
+                                         MakeCompositorFrame({child_id1}));
+
+  // Verify that the CompositorFrame is blocked on |child_id|.
+  EXPECT_FALSE(parent_surface()->HasActiveFrame());
+  EXPECT_TRUE(parent_surface()->HasPendingFrame());
+  EXPECT_THAT(parent_surface()->blocking_surfaces_for_testing(),
+              UnorderedElementsAre(child_id1));
+
+  // Verify that a SurfaceReference(parent_id, child_id1) exists in the
+  // SurfaceManager.
+  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
+
+  child_support1().SubmitCompositorFrame(
+      child_id1.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
+
+  // Verify that the child CompositorFrame activates immediately.
+  EXPECT_TRUE(child_surface1()->HasActiveFrame());
+  EXPECT_FALSE(child_surface1()->HasPendingFrame());
+  EXPECT_THAT(child_surface1()->blocking_surfaces_for_testing(), IsEmpty());
+
+  // Verify that the parent Surface has activated.
+  EXPECT_TRUE(parent_surface()->HasActiveFrame());
+  EXPECT_FALSE(parent_surface()->HasPendingFrame());
+  EXPECT_THAT(parent_surface()->blocking_surfaces_for_testing(), IsEmpty());
+
+  // Verify that there is no temporary reference for the child and that
+  // the reference from the parent to the child still exists.
+  EXPECT_THAT(GetTempReferences(child_id1.frame_sink_id()), IsEmpty());
+  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id1));
+
+  // The parent submits another CompositorFrame that depends on |child_id2|.
+  parent_support().SubmitCompositorFrame(parent_id.local_surface_id(),
+                                         MakeCompositorFrame({child_id2}));
+
+  // The parent surface should now have both a pending and activate
+  // CompositorFrame. Verify that the set of child references from
+  // |parent_id| include both the pending and active CompositorFrames.
+  EXPECT_TRUE(parent_surface()->HasActiveFrame());
+  EXPECT_TRUE(parent_surface()->HasPendingFrame());
+  EXPECT_THAT(parent_surface()->blocking_surfaces_for_testing(),
+              UnorderedElementsAre(child_id2));
+  EXPECT_THAT(GetChildReferences(parent_id),
+              UnorderedElementsAre(child_id1, child_id2));
+
+  child_support2().SubmitCompositorFrame(
+      child_id2.local_surface_id(), MakeCompositorFrame(empty_surface_ids()));
+
+  // Verify that the parent Surface has activated and no longer has a pending
+  // CompositorFrame. Also verify that |child_id1| is no longer a child
+  // reference of |parent_id|.
+  EXPECT_TRUE(parent_surface()->HasActiveFrame());
+  EXPECT_FALSE(parent_surface()->HasPendingFrame());
+  EXPECT_THAT(parent_surface()->blocking_surfaces_for_testing(), IsEmpty());
+  EXPECT_THAT(GetChildReferences(parent_id), UnorderedElementsAre(child_id2));
+}
+
 }  // namespace test
 }  // namespace cc
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index 5136fc5..0e2c932b 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -159,6 +159,8 @@
 
 void Display::SetColorSpace(const gfx::ColorSpace& color_space) {
   device_color_space_ = color_space;
+  if (aggregator_)
+    aggregator_->SetOutputColorSpace(device_color_space_);
 }
 
 void Display::SetOutputIsSecure(bool secure) {
@@ -215,6 +217,7 @@
   aggregator_.reset(new SurfaceAggregator(
       surface_manager_, resource_provider_.get(), output_partial_list));
   aggregator_->set_output_is_secure(output_is_secure_);
+  aggregator_->SetOutputColorSpace(device_color_space_);
 }
 
 void Display::UpdateRootSurfaceResourcesLocked() {
@@ -314,7 +317,7 @@
 
     renderer_->DecideRenderPassAllocationsForFrame(frame.render_pass_list);
     renderer_->DrawFrame(&frame.render_pass_list, device_scale_factor_,
-                         device_color_space_, current_surface_size_);
+                         current_surface_size_);
   } else {
     TRACE_EVENT_INSTANT0("cc", "Draw skipped.", TRACE_EVENT_SCOPE_THREAD);
   }
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
index cff8555..a196585b 100644
--- a/cc/surfaces/display_unittest.cc
+++ b/cc/surfaces/display_unittest.cc
@@ -179,9 +179,12 @@
   settings.partial_swap_enabled = true;
   settings.finish_rendering_on_resize = true;
   SetUpDisplay(settings, nullptr);
+  gfx::ColorSpace color_space_1 = gfx::ColorSpace::CreateXYZD50();
+  gfx::ColorSpace color_space_2 = gfx::ColorSpace::CreateSCRGBLinear();
 
   StubDisplayClient client;
   display_->Initialize(&client, &manager_);
+  display_->SetColorSpace(color_space_1);
 
   LocalSurfaceId local_surface_id(id_allocator_.GenerateId());
   EXPECT_FALSE(scheduler_->damaged);
@@ -213,7 +216,9 @@
 
   EXPECT_FALSE(scheduler_->swapped);
   EXPECT_EQ(0u, output_surface_->num_sent_frames());
+  EXPECT_EQ(gfx::ColorSpace(), output_surface_->last_reshape_color_space());
   display_->DrawAndSwap();
+  EXPECT_EQ(color_space_1, output_surface_->last_reshape_color_space());
   EXPECT_TRUE(scheduler_->swapped);
   EXPECT_EQ(1u, output_surface_->num_sent_frames());
   EXPECT_EQ(gfx::Size(100, 100),
@@ -235,7 +240,10 @@
     EXPECT_FALSE(scheduler_->has_new_root_surface);
 
     scheduler_->swapped = false;
+    EXPECT_EQ(color_space_1, output_surface_->last_reshape_color_space());
+    display_->SetColorSpace(color_space_2);
     display_->DrawAndSwap();
+    EXPECT_EQ(color_space_2, output_surface_->last_reshape_color_space());
     EXPECT_TRUE(scheduler_->swapped);
     EXPECT_EQ(2u, output_surface_->num_sent_frames());
     EXPECT_EQ(gfx::Size(100, 100),
diff --git a/cc/surfaces/pending_frame_observer.h b/cc/surfaces/pending_frame_observer.h
index ec7acab..3efd6783 100644
--- a/cc/surfaces/pending_frame_observer.h
+++ b/cc/surfaces/pending_frame_observer.h
@@ -19,6 +19,12 @@
 // changes should implement this class.
 class CC_SURFACES_EXPORT PendingFrameObserver {
  public:
+  // Called when one or both of the sets of referenced surfaces have changed.
+  virtual void OnReferencedSurfacesChanged(
+      Surface* surface,
+      const std::vector<SurfaceId>* active_referenced_surfaces,
+      const std::vector<SurfaceId>* pending_referenced_surfaces) = 0;
+
   // Called when a CompositorFrame within |surface| has activated.
   virtual void OnSurfaceActivated(Surface* surface) = 0;
 
diff --git a/cc/surfaces/referenced_surface_tracker.cc b/cc/surfaces/referenced_surface_tracker.cc
index 8b51848..ce1bf61 100644
--- a/cc/surfaces/referenced_surface_tracker.cc
+++ b/cc/surfaces/referenced_surface_tracker.cc
@@ -20,7 +20,8 @@
 
 void ReferencedSurfaceTracker::UpdateReferences(
     const LocalSurfaceId& local_surface_id,
-    const std::vector<SurfaceId>& referenced_surfaces) {
+    const std::vector<SurfaceId>* active_referenced_surfaces,
+    const std::vector<SurfaceId>* pending_referenced_surfaces) {
   DCHECK(local_surface_id.is_valid());
 
   // Clear references to add/remove from the last frame.
@@ -36,8 +37,17 @@
     referenced_surfaces_.clear();
   }
 
-  std::unordered_set<SurfaceId, SurfaceIdHash> referenced_surface_set(
-      referenced_surfaces.begin(), referenced_surfaces.end());
+  std::unordered_set<SurfaceId, SurfaceIdHash> referenced_surface_set;
+  if (active_referenced_surfaces) {
+    referenced_surface_set.insert(active_referenced_surfaces->begin(),
+                                  active_referenced_surfaces->end());
+  }
+
+  if (pending_referenced_surfaces) {
+    referenced_surface_set.insert(pending_referenced_surfaces->begin(),
+                                  pending_referenced_surfaces->end());
+  }
+
   ProcessNewReferences(referenced_surface_set);
 }
 
diff --git a/cc/surfaces/referenced_surface_tracker.h b/cc/surfaces/referenced_surface_tracker.h
index bc6e9064..8153b644f 100644
--- a/cc/surfaces/referenced_surface_tracker.h
+++ b/cc/surfaces/referenced_surface_tracker.h
@@ -39,8 +39,10 @@
   // |referenced_surfaces|. Otherwise a diff from the referenced surfaces in the
   // last frame will be computed. This should be called once per
   // CompositorFrame.
-  void UpdateReferences(const LocalSurfaceId& local_surface_id,
-                        const std::vector<SurfaceId>& referenced_surfaces);
+  void UpdateReferences(
+      const LocalSurfaceId& local_surface_id,
+      const std::vector<SurfaceId>* active_referenced_surfaces,
+      const std::vector<SurfaceId>* pending_referenced_surfaces);
 
  private:
   // Updates |referenced_surfaces_| based on a |new_referenced_surfaces| from a
diff --git a/cc/surfaces/referenced_surface_tracker_unittest.cc b/cc/surfaces/referenced_surface_tracker_unittest.cc
index 2e31f2b..70a33b1 100644
--- a/cc/surfaces/referenced_surface_tracker_unittest.cc
+++ b/cc/surfaces/referenced_surface_tracker_unittest.cc
@@ -27,10 +27,6 @@
 constexpr FrameSinkId kChildFrameSink1(65563, 1);
 constexpr FrameSinkId kChildFrameSink2(65564, 1);
 
-std::vector<SurfaceId> empty_surface_ids() {
-  return std::vector<SurfaceId>();
-}
-
 SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
   return SurfaceId(
       frame_sink_id,
@@ -67,7 +63,7 @@
   EXPECT_FALSE(tracker().current_surface_id().is_valid());
 
   // After setting current SurfaceId then current_surface_id() should be valid.
-  tracker().UpdateReferences(parent_id.local_surface_id(), empty_surface_ids());
+  tracker().UpdateReferences(parent_id.local_surface_id(), nullptr, nullptr);
   EXPECT_EQ(parent_id, tracker().current_surface_id());
 }
 
@@ -77,7 +73,10 @@
   const SurfaceReference reference(parent_id, child_id1);
 
   // First frame has a reference to |child_id1|, check that reference is added.
-  tracker().UpdateReferences(parent_id.local_surface_id(), {child_id1});
+  std::vector<SurfaceId> active_referenced_surfaces = {child_id1};
+  tracker().UpdateReferences(parent_id.local_surface_id(),
+                             &active_referenced_surfaces,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_add(), UnorderedElementsAre(reference));
   EXPECT_THAT(tracker().references_to_remove(), IsEmpty());
 }
@@ -88,13 +87,18 @@
   const SurfaceReference reference(parent_id, child_id1);
 
   // First frame has a reference to |child_id1|, check that reference is added.
-  tracker().UpdateReferences(parent_id.local_surface_id(), {child_id1});
+  std::vector<SurfaceId> active_referenced_surfaces = {child_id1};
+  tracker().UpdateReferences(parent_id.local_surface_id(),
+                             &active_referenced_surfaces,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_remove(), IsEmpty());
   EXPECT_THAT(tracker().references_to_add(), UnorderedElementsAre(reference));
 
   // Second frame has same reference, check that no references are added or
   // removed.
-  tracker().UpdateReferences(parent_id.local_surface_id(), {child_id1});
+  tracker().UpdateReferences(parent_id.local_surface_id(),
+                             &active_referenced_surfaces,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_remove(), IsEmpty());
   EXPECT_THAT(tracker().references_to_add(), IsEmpty());
 }
@@ -104,11 +108,16 @@
   const SurfaceId child_id1 = MakeSurfaceId(kChildFrameSink1, 1);
   const SurfaceReference reference(parent_id, child_id1);
 
-  tracker().UpdateReferences(parent_id.local_surface_id(), {child_id1});
+  std::vector<SurfaceId> active_referenced_surfaces = {child_id1};
+  tracker().UpdateReferences(parent_id.local_surface_id(),
+                             &active_referenced_surfaces,
+                             nullptr /* pending_referenced_surfaces */);
 
   // Second frame no longer references |child_id1|, check that reference to is
   // removed.
-  tracker().UpdateReferences(parent_id.local_surface_id(), empty_surface_ids());
+  tracker().UpdateReferences(parent_id.local_surface_id(),
+                             nullptr /* active_referenced_surfaces */,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_add(), IsEmpty());
   EXPECT_THAT(tracker().references_to_remove(),
               UnorderedElementsAre(reference));
@@ -122,14 +131,20 @@
   const SurfaceReference reference_second(parent_id, child_id1_second);
 
   // First frame has reference to |child_id1_first|.
-  tracker().UpdateReferences(parent_id.local_surface_id(), {child_id1_first});
+  std::vector<SurfaceId> active_referenced_surfaces1 = {child_id1_first};
+  tracker().UpdateReferences(parent_id.local_surface_id(),
+                             &active_referenced_surfaces1,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_add(),
               UnorderedElementsAre(reference_first));
 
   // Second frame has reference to |child_id1_second| which has the same
   // FrameSinkId but different LocalSurfaceId. Check that first reference is
   // removed and second reference is added.
-  tracker().UpdateReferences(parent_id.local_surface_id(), {child_id1_second});
+  std::vector<SurfaceId> active_referenced_surfaces2 = {child_id1_second};
+  tracker().UpdateReferences(parent_id.local_surface_id(),
+                             &active_referenced_surfaces2,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_remove(),
               UnorderedElementsAre(reference_first));
   EXPECT_THAT(tracker().references_to_add(),
@@ -143,13 +158,18 @@
   const SurfaceReference reference(parent_id_second, child_id1);
 
   // First frame references |child_id1|.
-  tracker().UpdateReferences(parent_id_first.local_surface_id(), {child_id1});
+  std::vector<SurfaceId> active_referenced_surfaces = {child_id1};
+  tracker().UpdateReferences(parent_id_first.local_surface_id(),
+                             &active_referenced_surfaces,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_add(), SizeIs(1));
 
   // Second frame still reference |child_id1| but the parent SurfaceId has
   // changed. The new parent SurfaceId should have a reference added to
   // |child_id1|.
-  tracker().UpdateReferences(parent_id_second.local_surface_id(), {child_id1});
+  tracker().UpdateReferences(parent_id_second.local_surface_id(),
+                             &active_referenced_surfaces,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_add(), UnorderedElementsAre(reference));
   EXPECT_THAT(tracker().references_to_remove(), IsEmpty());
 }
@@ -162,14 +182,19 @@
   const SurfaceReference reference2(parent_id, child_id2);
 
   // First frame references both surfaces.
+  std::vector<SurfaceId> active_referenced_surfaces1 = {child_id1, child_id2};
   tracker().UpdateReferences(parent_id.local_surface_id(),
-                             {child_id1, child_id2});
+                             &active_referenced_surfaces1,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_add(),
               UnorderedElementsAre(reference1, reference2));
 
   // Second frame references only |child_id2|, check that reference to
   // |child_id1| is removed.
-  tracker().UpdateReferences(parent_id.local_surface_id(), {child_id2});
+  std::vector<SurfaceId> active_referenced_surfaces2 = {child_id2};
+  tracker().UpdateReferences(parent_id.local_surface_id(),
+                             &active_referenced_surfaces2,
+                             nullptr /* pending_referenced_surfaces */);
   EXPECT_THAT(tracker().references_to_remove(),
               UnorderedElementsAre(reference1));
   EXPECT_THAT(tracker().references_to_add(), IsEmpty());
diff --git a/cc/surfaces/surface.cc b/cc/surfaces/surface.cc
index cd95ac0..6f482f5 100644
--- a/cc/surfaces/surface.cc
+++ b/cc/surfaces/surface.cc
@@ -65,10 +65,16 @@
 
   if (!blocking_surfaces_.empty()) {
     pending_frame_ = std::move(frame);
-    pending_referenced_surfaces_ = pending_frame_->metadata.referenced_surfaces;
     // Ask the surface manager to inform |this| when its dependencies are
     // resolved.
     factory_->manager()->RequestSurfaceResolution(this);
+
+    // We do not have to notify observers that referenced surfaces have changed
+    // in the else case because ActivateFrame will notify observers.
+    for (auto& observer : observers_) {
+      observer.OnReferencedSurfacesChanged(this, active_referenced_surfaces(),
+                                           pending_referenced_surfaces());
+    }
   } else {
     // If there are no blockers, then immediately activate the frame.
     ActivateFrame(std::move(frame));
@@ -151,7 +157,6 @@
   DCHECK(pending_frame_);
   ActivateFrame(std::move(pending_frame_.value()));
   pending_frame_.reset();
-  pending_referenced_surfaces_.clear();
 }
 
 // A frame is activated if all its Surface ID dependences are active or a
@@ -176,10 +181,13 @@
   if (previous_frame)
     UnrefFrameResources(*previous_frame);
 
-  active_referenced_surfaces_ = active_frame_->metadata.referenced_surfaces;
-
   for (auto& observer : observers_)
     observer.OnSurfaceActivated(this);
+
+  for (auto& observer : observers_) {
+    observer.OnReferencedSurfacesChanged(this, active_referenced_surfaces(),
+                                         pending_referenced_surfaces());
+  }
 }
 
 void Surface::UpdateBlockingSurfaces(
diff --git a/cc/surfaces/surface.h b/cc/surfaces/surface.h
index e8fbccf..c42292e 100644
--- a/cc/surfaces/surface.h
+++ b/cc/surfaces/surface.h
@@ -101,12 +101,14 @@
     return destruction_dependencies_.size();
   }
 
-  const std::vector<SurfaceId>& active_referenced_surfaces() const {
-    return active_referenced_surfaces_;
+  const std::vector<SurfaceId>* active_referenced_surfaces() const {
+    return active_frame_ ? &active_frame_->metadata.referenced_surfaces
+                         : nullptr;
   }
 
-  const std::vector<SurfaceId>& pending_referenced_surfaces() const {
-    return pending_referenced_surfaces_;
+  const std::vector<SurfaceId>* pending_referenced_surfaces() const {
+    return pending_frame_ ? &pending_frame_->metadata.referenced_surfaces
+                          : nullptr;
   }
 
   const SurfaceDependencies& blocking_surfaces_for_testing() const {
@@ -144,20 +146,6 @@
   // on multiple Displays.
   std::set<BeginFrameSource*> begin_frame_sources_;
 
-  // The set of SurfaceIds referenced by the active CompositorFrame.
-  // TODO(fsamuel): It seems unnecessary to copy this vector over
-  // from CompostiorFrameMetadata to store locally here. We can simply
-  // provide an accessor to the referenced surfaces directly from
-  // CompositorFrameMetadata.
-  std::vector<SurfaceId> active_referenced_surfaces_;
-
-  // The set of SurfaceIds referenced by the pending CompositorFrame.
-  // TODO(fsamuel): It seems unnecessary to copy this vector over
-  // from CompostiorFrameMetadata to store locally here. We can simply
-  // provide an accessor to the referenced surfaces directly from
-  // CompositorFrameMetadata.
-  std::vector<SurfaceId> pending_referenced_surfaces_;
-
   SurfaceDependencies blocking_surfaces_;
   base::ObserverList<PendingFrameObserver, true> observers_;
 
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index 82bc500..cb07427 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -208,7 +208,7 @@
 
     copy_pass->SetAll(remapped_pass_id, source.output_rect, source.output_rect,
                       source.transform_to_root_target, source.filters,
-                      source.background_filters,
+                      source.background_filters, output_color_space_,
                       source.has_transparent_background);
 
     MoveMatchingRequests(source.id, &copy_requests, &copy_pass->copy_requests);
@@ -475,7 +475,7 @@
 
     copy_pass->SetAll(remapped_pass_id, source.output_rect, source.output_rect,
                       source.transform_to_root_target, source.filters,
-                      source.background_filters,
+                      source.background_filters, output_color_space_,
                       source.has_transparent_background);
 
     CopyQuadsToPass(source.quad_list, source.shared_quad_state_list,
@@ -848,4 +848,9 @@
   it->second = 0;
 }
 
+void SurfaceAggregator::SetOutputColorSpace(
+    const gfx::ColorSpace& output_color_space) {
+  output_color_space_ = output_color_space;
+}
+
 }  // namespace cc
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h
index ea2b8e6..e60eed5 100644
--- a/cc/surfaces/surface_aggregator.h
+++ b/cc/surfaces/surface_aggregator.h
@@ -18,6 +18,7 @@
 #include "cc/resources/transferable_resource.h"
 #include "cc/surfaces/surface_id.h"
 #include "cc/surfaces/surfaces_export.h"
+#include "ui/gfx/color_space.h"
 
 namespace cc {
 
@@ -44,6 +45,10 @@
   void SetFullDamageForSurface(const SurfaceId& surface_id);
   void set_output_is_secure(bool secure) { output_is_secure_ = secure; }
 
+  // Set the color spaces for the created RenderPasses, which is propagated
+  // to the output surface.
+  void SetOutputColorSpace(const gfx::ColorSpace& output_color_space);
+
  private:
   struct ClipData {
     ClipData() : is_clipped(false) {}
@@ -125,6 +130,7 @@
   int next_render_pass_id_;
   const bool aggregate_only_damaged_;
   bool output_is_secure_;
+  gfx::ColorSpace output_color_space_;
 
   using SurfaceToResourceChildIdMap =
       std::unordered_map<SurfaceId, int, SurfaceIdHash>;
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index 788e52e..e836410 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -2086,6 +2086,36 @@
   factory2.EvictSurface();
 }
 
+// Ensure that the render passes have correct color spaces.
+TEST_F(SurfaceAggregatorValidSurfaceTest, ColorSpaceTest) {
+  test::Quad quads[][2] = {{test::Quad::SolidColorQuad(SK_ColorWHITE),
+                            test::Quad::SolidColorQuad(SK_ColorLTGRAY)},
+                           {test::Quad::SolidColorQuad(SK_ColorGRAY),
+                            test::Quad::SolidColorQuad(SK_ColorDKGRAY)}};
+  test::Pass passes[] = {test::Pass(quads[0], arraysize(quads[0]), 2),
+                         test::Pass(quads[1], arraysize(quads[1]), 1)};
+  gfx::ColorSpace color_space1 = gfx::ColorSpace::CreateXYZD50();
+  gfx::ColorSpace color_space2 = gfx::ColorSpace::CreateSRGB();
+
+  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+                        root_local_surface_id_);
+
+  SurfaceId surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+
+  CompositorFrame aggregated_frame;
+  aggregator_.SetOutputColorSpace(color_space1);
+  aggregated_frame = aggregator_.Aggregate(surface_id);
+  EXPECT_EQ(2u, aggregated_frame.render_pass_list.size());
+  EXPECT_EQ(color_space1, aggregated_frame.render_pass_list[0]->color_space);
+  EXPECT_EQ(color_space1, aggregated_frame.render_pass_list[1]->color_space);
+
+  aggregator_.SetOutputColorSpace(color_space2);
+  aggregated_frame = aggregator_.Aggregate(surface_id);
+  EXPECT_EQ(2u, aggregated_frame.render_pass_list.size());
+  EXPECT_EQ(color_space2, aggregated_frame.render_pass_list[0]->color_space);
+  EXPECT_EQ(color_space2, aggregated_frame.render_pass_list[1]->color_space);
+}
+
 }  // namespace
 }  // namespace cc
 
diff --git a/cc/surfaces/surface_dependency_tracker.cc b/cc/surfaces/surface_dependency_tracker.cc
index df20152..6cfeae8 100644
--- a/cc/surfaces/surface_dependency_tracker.cc
+++ b/cc/surfaces/surface_dependency_tracker.cc
@@ -84,6 +84,11 @@
 
 void SurfaceDependencyTracker::OnBeginFrameSourcePausedChanged(bool paused) {}
 
+void SurfaceDependencyTracker::OnReferencedSurfacesChanged(
+    Surface* surface,
+    const std::vector<SurfaceId>* active_referenced_surfaces,
+    const std::vector<SurfaceId>* pending_referenced_surfaces) {}
+
 void SurfaceDependencyTracker::OnSurfaceDiscarded(Surface* surface) {
   // If the surface being destroyed doesn't have a pending frame then we have
   // nothing to do here.
@@ -115,10 +120,9 @@
   pending_surfaces_.erase(surface);
   surface->RemoveObserver(this);
 
-  // TODO(fsamuel): We should consider removing this surface as a dependency on
-  // other surfaces. This dependency will be removed when the deadline hits
-  // anyway but maybe we should try to actiate these frames early (see
-  // https://crbug.com/689725).
+  // Pretend that the discarded surface's SurfaceId is now available to unblock
+  // dependencies because we now know the surface will never activate.
+  NotifySurfaceIdAvailable(surface->surface_id());
 }
 
 void SurfaceDependencyTracker::OnSurfaceActivated(Surface* surface) {
diff --git a/cc/surfaces/surface_dependency_tracker.h b/cc/surfaces/surface_dependency_tracker.h
index 908a2b2..193eb31 100644
--- a/cc/surfaces/surface_dependency_tracker.h
+++ b/cc/surfaces/surface_dependency_tracker.h
@@ -50,12 +50,16 @@
   void OnBeginFrameSourcePausedChanged(bool paused) override;
 
   // PendingFrameObserver implementation:
-  void OnSurfaceActivated(Surface* pending_frame) override;
+  void OnReferencedSurfacesChanged(
+      Surface* surface,
+      const std::vector<SurfaceId>* active_referenced_surfaces,
+      const std::vector<SurfaceId>* pending_referenced_surfaces) override;
+  void OnSurfaceActivated(Surface* surface) override;
   void OnSurfaceDependenciesChanged(
-      Surface* pending_frame,
+      Surface* surface,
       const SurfaceDependencies& added_dependencies,
       const SurfaceDependencies& removed_dependencies) override;
-  void OnSurfaceDiscarded(Surface* pending_frame) override;
+  void OnSurfaceDiscarded(Surface* surface) override;
 
   // SurfaceObserver implementation:
   void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
diff --git a/cc/surfaces/surface_factory.cc b/cc/surfaces/surface_factory.cc
index 907a59f..f641274 100644
--- a/cc/surfaces/surface_factory.cc
+++ b/cc/surfaces/surface_factory.cc
@@ -38,9 +38,7 @@
 void SurfaceFactory::EvictSurface() {
   if (!current_surface_)
     return;
-  if (manager_)
-    manager_->Destroy(std::move(current_surface_));
-  current_surface_.reset();
+  Destroy(std::move(current_surface_));
 }
 
 void SurfaceFactory::Reset() {
@@ -115,8 +113,22 @@
   holder_.UnrefResources(resources);
 }
 
+void SurfaceFactory::OnReferencedSurfacesChanged(
+    Surface* surface,
+    const std::vector<SurfaceId>* active_referenced_surfaces,
+    const std::vector<SurfaceId>* pending_referenced_surfaces) {
+  client_->ReferencedSurfacesChanged(surface->surface_id().local_surface_id(),
+                                     active_referenced_surfaces,
+                                     pending_referenced_surfaces);
+}
+
 void SurfaceFactory::OnSurfaceActivated(Surface* surface) {
   DCHECK(surface->HasActiveFrame());
+  if (seen_first_frame_activation_)
+    return;
+
+  seen_first_frame_activation_ = true;
+
   const CompositorFrame& frame = surface->GetActiveFrame();
   // CompositorFrames might not be populated with a RenderPass in unit tests.
   gfx::Size frame_size;
@@ -127,31 +139,28 @@
   // SurfaceFactory stops observing new activations after the first one.
   manager_->SurfaceCreated(SurfaceInfo(
       surface->surface_id(), frame.metadata.device_scale_factor, frame_size));
-  surface->RemoveObserver(this);
 }
 
 void SurfaceFactory::OnSurfaceDependenciesChanged(
-    Surface* pending_surface,
+    Surface* surface,
     const SurfaceDependencies& added_dependencies,
     const SurfaceDependencies& removed_dependencies) {}
 
-void SurfaceFactory::OnSurfaceDiscarded(Surface* pending_surface) {}
+void SurfaceFactory::OnSurfaceDiscarded(Surface* surface) {}
 
 std::unique_ptr<Surface> SurfaceFactory::Create(
     const LocalSurfaceId& local_surface_id) {
   auto surface = base::MakeUnique<Surface>(
       SurfaceId(frame_sink_id_, local_surface_id), weak_factory_.GetWeakPtr());
+  seen_first_frame_activation_ = false;
   manager_->RegisterSurface(surface.get());
-  // Observe a Surface from the time it's created until it's activated for the
-  // first time.
   surface->AddObserver(this);
   return surface;
 }
 
 void SurfaceFactory::Destroy(std::unique_ptr<Surface> surface) {
   surface->RemoveObserver(this);
-  if (manager_)
-    manager_->Destroy(std::move(surface));
+  manager_->Destroy(std::move(surface));
 }
 
 }  // namespace cc
diff --git a/cc/surfaces/surface_factory.h b/cc/surfaces/surface_factory.h
index 4a9f6af..911c044 100644
--- a/cc/surfaces/surface_factory.h
+++ b/cc/surfaces/surface_factory.h
@@ -87,18 +87,18 @@
   bool needs_sync_points() const { return needs_sync_points_; }
   void set_needs_sync_points(bool needs) { needs_sync_points_ = needs; }
 
-  // SurfaceFactory's owner can call this when it finds out that SurfaceManager
-  // is no longer alive during destruction.
-  void DidDestroySurfaceManager() { manager_ = nullptr; }
-
  private:
   // PendingFrameObserver implementation.
-  void OnSurfaceActivated(Surface* pending_surface) override;
+  void OnReferencedSurfacesChanged(
+      Surface* surface,
+      const std::vector<SurfaceId>* active_referenced_surfaces,
+      const std::vector<SurfaceId>* pending_referenced_surfaces) override;
+  void OnSurfaceActivated(Surface* surface) override;
   void OnSurfaceDependenciesChanged(
-      Surface* pending_surface,
+      Surface* surface,
       const SurfaceDependencies& added_dependencies,
       const SurfaceDependencies& removed_dependencies) override;
-  void OnSurfaceDiscarded(Surface* pending_surface) override;
+  void OnSurfaceDiscarded(Surface* surface) override;
 
   std::unique_ptr<Surface> Create(const LocalSurfaceId& local_surface_id);
   void Destroy(std::unique_ptr<Surface> surface);
@@ -108,6 +108,7 @@
   SurfaceFactoryClient* client_;
   SurfaceResourceHolder holder_;
   bool needs_sync_points_;
+  bool seen_first_frame_activation_ = false;
   std::unique_ptr<Surface> current_surface_;
   base::WeakPtrFactory<SurfaceFactory> weak_factory_;
 
diff --git a/cc/surfaces/surface_factory_client.h b/cc/surfaces/surface_factory_client.h
index e405788d..ea32344 100644
--- a/cc/surfaces/surface_factory_client.h
+++ b/cc/surfaces/surface_factory_client.h
@@ -13,11 +13,17 @@
 namespace cc {
 
 class BeginFrameSource;
+class SurfaceId;
 
 class CC_SURFACES_EXPORT SurfaceFactoryClient {
  public:
   virtual ~SurfaceFactoryClient() {}
 
+  virtual void ReferencedSurfacesChanged(
+      const LocalSurfaceId& local_surface_id,
+      const std::vector<SurfaceId>* active_referenced_surfaces,
+      const std::vector<SurfaceId>* pending_referenced_surfaces) {}
+
   virtual void ReturnResources(const ReturnedResourceArray& resources) = 0;
 
   virtual void WillDrawSurface(const LocalSurfaceId& local_surface_id,
diff --git a/cc/surfaces/surface_manager.cc b/cc/surfaces/surface_manager.cc
index c7f34ef..981d7d74 100644
--- a/cc/surfaces/surface_manager.cc
+++ b/cc/surfaces/surface_manager.cc
@@ -321,7 +321,10 @@
 
     // TODO(fsamuel): We should probably keep alive pending referenced surfaces
     // too.
-    for (const SurfaceId& id : surf->active_referenced_surfaces()) {
+    if (!surf->active_referenced_surfaces())
+      continue;
+
+    for (const SurfaceId& id : *surf->active_referenced_surfaces()) {
       if (live_surfaces_set.count(id))
         continue;
 
diff --git a/cc/test/animation_timelines_test_common.cc b/cc/test/animation_timelines_test_common.cc
index d6c2890..35879f7 100644
--- a/cc/test/animation_timelines_test_common.cc
+++ b/cc/test/animation_timelines_test_common.cc
@@ -432,7 +432,7 @@
   host_impl_->TickAnimations(time);
   host_impl_->UpdateAnimationState(true, events.get());
 
-  auto animation_events = static_cast<const AnimationEvents*>(events.get());
+  auto* animation_events = static_cast<const AnimationEvents*>(events.get());
   EXPECT_EQ(expect_events, animation_events->events_.size());
 
   host_->TickAnimations(time);
diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc
index 7b7d4f50..cafd10b 100644
--- a/cc/test/fake_output_surface.cc
+++ b/cc/test/fake_output_surface.cc
@@ -38,6 +38,7 @@
   } else {
     software_device()->Resize(size, device_scale_factor);
   }
+  last_reshape_color_space_ = color_space;
 }
 
 void FakeOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index 5049827e..4a83f8d 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -98,6 +98,10 @@
     return last_swap_rect_;
   }
 
+  const gfx::ColorSpace& last_reshape_color_space() {
+    return last_reshape_color_space_;
+  }
+
  protected:
   explicit FakeOutputSurface(scoped_refptr<ContextProvider> context_provider);
   explicit FakeOutputSurface(
@@ -113,6 +117,7 @@
   OverlayCandidateValidator* overlay_candidate_validator_ = nullptr;
   bool last_swap_rect_valid_ = false;
   gfx::Rect last_swap_rect_;
+  gfx::ColorSpace last_reshape_color_space_;
 
  private:
   void SwapBuffersAck();
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index bcf495b..a435231 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -82,8 +82,7 @@
 
   renderer_->DecideRenderPassAllocationsForFrame(*pass_list);
   float device_scale_factor = 1.f;
-  renderer_->DrawFrame(pass_list, device_scale_factor, gfx::ColorSpace(),
-                       device_viewport_size_);
+  renderer_->DrawFrame(pass_list, device_scale_factor, device_viewport_size_);
 
   // Wait for the readback to complete.
   if (output_surface_->context_provider())
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index 13ed0512..0169819 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -646,7 +646,7 @@
   }
   {
     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
-                 "SoftwareImageDecodeCache::GetOriginalImageDecode - "
+                 "SoftwareImageDecodeCache::GetSubrectImageDecode - "
                  "read pixels");
     bool result = decoded_draw_image.image()->readPixels(
         subrect_info, subrect_pixels->data(), subrect_info.minRowBytes(),
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 7ee8b0b0..bd839f0 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -358,7 +358,7 @@
                         const PropertyTrees* property_trees,
                         bool non_root_surfaces_enabled) {
   const ClipTree& clip_tree = property_trees->clip_tree;
-  for (auto& layer : visible_layer_list) {
+  for (auto* layer : visible_layer_list) {
     const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
     bool layer_needs_clip_rect =
         non_root_surfaces_enabled
@@ -414,7 +414,7 @@
   const EffectTree& effect_tree = property_trees->effect_tree;
   const TransformTree& transform_tree = property_trees->transform_tree;
   const ClipTree& clip_tree = property_trees->clip_tree;
-  for (auto& layer : visible_layer_list) {
+  for (auto* layer : visible_layer_list) {
     gfx::Size layer_bounds = layer->bounds();
 
     int effect_ancestor_with_copy_request =
@@ -1229,7 +1229,7 @@
 
 void VerifyVisibleRectsCalculations(const LayerImplList& layer_list,
                                     const PropertyTrees* property_trees) {
-  for (auto layer : layer_list) {
+  for (auto* layer : layer_list) {
     gfx::Rect visible_rect_dynamic =
         ComputeLayerVisibleRectDynamic(property_trees, layer);
     DCHECK(layer->visible_layer_rect() == visible_rect_dynamic)
diff --git a/chrome/VERSION b/chrome/VERSION
index 08526fa..a2a47ea 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=58
 MINOR=0
-BUILD=3012
+BUILD=3013
 PATCH=0
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index b307954..b5b9a97 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -459,7 +459,7 @@
         <activity android:name="org.chromium.chrome.browser.bookmarks.BookmarkActivity"
             android:theme="@style/FullscreenWhiteActivityTheme"
             android:exported="false"
-            android:windowSoftInputMode="adjustResize"
+            android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
         </activity>
         <activity android:name="org.chromium.chrome.browser.bookmarks.BookmarkAddActivity"
@@ -494,7 +494,7 @@
         <!-- Activities for downloads. -->
         <activity android:name="org.chromium.chrome.browser.download.DownloadActivity"
             android:theme="@style/FullscreenWhiteActivityTheme"
-            android:windowSoftInputMode="adjustResize"
+            android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
             android:exported="false"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
         </activity>
@@ -502,7 +502,7 @@
         <!-- Activities for history. -->
         <activity android:name="org.chromium.chrome.browser.history.HistoryActivity"
             android:theme="@style/FullscreenWhiteActivityTheme"
-            android:windowSoftInputMode="adjustResize"
+            android:windowSoftInputMode="stateAlwaysHidden|adjustResize"
             android:exported="false"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
         </activity>
diff --git a/chrome/android/java/res/layout/location_bar.xml b/chrome/android/java/res/layout/location_bar.xml
index b1a8a2c..ad826c3 100644
--- a/chrome/android/java/res/layout/location_bar.xml
+++ b/chrome/android/java/res/layout/location_bar.xml
@@ -5,6 +5,26 @@
 
 <!-- The location bar also know as URL bar -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- The container for the Google G is kept at a fixed width to make the horizonal translation
+         calculations work. The contents are end-aligned, so when the location bar expands,
+         the space in the start margin will be pushed out, creating the effect of both margins
+         shrinking simultaneously. -->
+    <FrameLayout android:id="@+id/google_g_container"
+        android:layout_width="@dimen/location_bar_google_g_container_width"
+        android:layout_height="match_parent" >
+
+        <ImageView android:id="@+id/google_g"
+            style="@style/LocationBarButton"
+            android:layout_width="@dimen/location_bar_google_g_width"
+            android:layout_height="match_parent"
+            android:layout_marginEnd="@dimen/location_bar_google_g_margin"
+            android:layout_gravity="end"
+            android:scaleType="fitCenter"
+            android:src="@drawable/googleg"
+            android:contentDescription="@null" />
+
+    </FrameLayout>
+
     <ImageView android:id="@+id/incognito_badge"
         style="@style/LocationBarButton"
         android:layout_width="wrap_content"
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml
index aca5715..4cc3b46 100644
--- a/chrome/android/java/res/layout/new_tab_page_layout.xml
+++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -77,6 +77,8 @@
             android:layout_marginStart="12dp"
             android:layout_weight="1"
             android:background="@null"
+            android:drawableStart="@drawable/googleg"
+            android:drawablePadding="8dp"
             android:ellipsize="end"
             android:focusableInTouchMode="false"
             android:gravity="center_vertical"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 1e457ba02..1fb7d8d 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -224,7 +224,7 @@
     <dimen name="webapp_splash_large_title_margin_bottom">16dp</dimen>
 
     <dimen name="webapk_badge_icon_size">24dp</dimen>
-    
+
     <!-- Toolbar dimensions -->
     <dimen name="toolbar_tab_count_text_size_1_digit">12dp</dimen>
     <dimen name="toolbar_tab_count_text_size_2_digit">10dp</dimen>
@@ -234,6 +234,10 @@
     <dimen name="toolbar_button_width">48dp</dimen>
 
     <dimen name="toolbar_edge_padding">8dp</dimen>
+    <dimen name="location_bar_google_g_width">24dp</dimen>
+    <dimen name="location_bar_google_g_margin">8dp</dimen>
+    <!-- location_bar_google_g_width + 2 * location_bar_google_g_margin -->
+    <dimen name="location_bar_google_g_container_width">40dp</dimen>
     <dimen name="location_bar_vertical_margin">8dp</dimen>
     <dimen name="location_bar_url_text_size">16sp</dimen>
     <dimen name="location_bar_incognito_badge_padding">7dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BasicNativePage.java b/chrome/android/java/src/org/chromium/chrome/browser/BasicNativePage.java
index cce1182..91d59df 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BasicNativePage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BasicNativePage.java
@@ -11,7 +11,6 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content_public.browser.LoadUrlParams;
 
 /**
@@ -20,16 +19,16 @@
 public abstract class BasicNativePage implements NativePage {
 
     private final Activity mActivity;
-    private final Tab mTab;
+    private final NativePageHost mHost;
     private final int mBackgroundColor;
     private final int mThemeColor;
 
     private String mUrl;
 
-    public BasicNativePage(Activity activity, Tab tab) {
-        initialize(activity, tab);
+    public BasicNativePage(Activity activity, NativePageHost host) {
+        initialize(activity, host);
         mActivity = activity;
-        mTab = tab;
+        mHost = host;
         mBackgroundColor = ApiCompatibilityUtils.getColor(activity.getResources(),
                 R.color.default_primary_color);
         mThemeColor = ApiCompatibilityUtils.getColor(
@@ -49,7 +48,7 @@
     /**
      * Subclasses shall implement this method to initialize the UI that they hold.
      */
-    protected abstract void initialize(Activity activity, Tab tab);
+    protected abstract void initialize(Activity activity, NativePageHost host);
 
     @Override
     public abstract View getView();
@@ -87,6 +86,6 @@
      */
     public void onStateChange(String url) {
         if (url.equals(mUrl)) return;
-        mTab.loadUrl(new LoadUrlParams(url));
+        mHost.loadUrl(new LoadUrlParams(url));
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BrowserRestartActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/BrowserRestartActivity.java
index e8f95ff5..f5f59e69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BrowserRestartActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BrowserRestartActivity.java
@@ -8,10 +8,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.Process;
-import android.text.TextUtils;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.browser.util.IntentUtils;
@@ -28,58 +25,40 @@
  * AlarmManager, which requires a minimum alarm duration of 5 seconds: https://crbug.com/515919.
  */
 public class BrowserRestartActivity extends Activity {
-    public static final String ACTION_START_WATCHDOG =
-            "org.chromium.chrome.browser.BrowserRestartActivity.start_watchdog";
-    public static final String ACTION_KILL_PROCESS =
-            "org.chromium.chrome.browser.BrowserRestartActivity.kill_process";
-
     public static final String EXTRA_MAIN_PID =
             "org.chromium.chrome.browser.BrowserRestartActivity.main_pid";
     public static final String EXTRA_RESTART =
             "org.chromium.chrome.browser.BrowserRestartActivity.restart";
 
-    private static final String TAG = "BrowserRestartActivity";
-
-    // The amount of time to wait for Chrome to destroy all the activities of the main process
-    // before this Activity forcefully kills it.
-    private static final long WATCHDOG_DELAY_MS = 1000;
+    /**
+     * Creates an Intent to start the {@link BrowserRestartActivity}.  Must only be called by the
+     * {@link org.chromium.chrome.browser.init.ChromeLifetimeController}.
+     * @param context       Context to use when constructing the Intent.
+     * @param restartChrome Whether or not to restart Chrome after killing the process.
+     * @return Intent that can be used to restart Chrome.
+     */
+    public static Intent createIntent(Context context, boolean restartChrome) {
+        Intent intent = new Intent();
+        intent.setClassName(context.getPackageName(), BrowserRestartActivity.class.getName());
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(BrowserRestartActivity.EXTRA_MAIN_PID, Process.myPid());
+        intent.putExtra(BrowserRestartActivity.EXTRA_RESTART, restartChrome);
+        return intent;
+    }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        handleIntent(getIntent());
-    }
 
-    @Override
-    public void onNewIntent(Intent intent) {
-        handleIntent(intent);
-    }
-
-    private void handleIntent(final Intent intent) {
-        if (TextUtils.equals(ACTION_START_WATCHDOG, intent.getAction())) {
-            // Kick off a timer to kill the process after a delay.
-            Handler handler = new Handler(Looper.getMainLooper());
-            handler.postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    destroyProcess(intent);
-                }
-            }, WATCHDOG_DELAY_MS);
-        } else if (TextUtils.equals(ACTION_KILL_PROCESS, intent.getAction())) {
-            destroyProcess(intent);
-        } else {
-            assert false;
-        }
-    }
-
-    private void destroyProcess(Intent intent) {
         // Kill the main Chrome process.
+        Intent intent = getIntent();
         int mainBrowserPid = IntentUtils.safeGetIntExtra(
                 intent, BrowserRestartActivity.EXTRA_MAIN_PID, -1);
         assert mainBrowserPid != -1;
+        assert mainBrowserPid != Process.myPid();
         Process.killProcess(mainBrowserPid);
 
-        // Fire an Intent to restart Chrome.
+        // Fire an Intent to restart Chrome, if necessary.
         boolean restart = IntentUtils.safeGetBooleanExtra(
                 intent, BrowserRestartActivity.EXTRA_RESTART, false);
         if (restart) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index cc89280..b8a5d98 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -135,6 +135,7 @@
     public static final String NTP_FAKE_OMNIBOX_TEXT = "NTPFakeOmniboxText";
     public static final String NTP_FOREIGN_SESSIONS_SUGGESTIONS = "NTPForeignSessionsSuggestions";
     public static final String NTP_OFFLINE_PAGES_FEATURE_NAME = "NTPOfflinePages";
+    public static final String NTP_SHOW_GOOGLE_G_IN_OMNIBOX = "NTPShowGoogleGInOmnibox";
     public static final String NTP_SNIPPETS_INCREASED_VISIBILITY = "NTPSnippetsIncreasedVisibility";
     public static final String NTP_SNIPPETS_SAVE_TO_OFFLINE = "NTPSaveToOffline";
     public static final String NTP_SNIPPETS_OFFLINE_BADGE = "NTPOfflineBadge";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
index 347b2b3..63f5bd2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -118,13 +118,6 @@
     public static final String GOOGLE_BASE_URL = "google-base-url";
 
     /**
-     * Use fake device for Media Stream to replace actual camera and microphone.
-     * Native switch - switches::kUseFakeDeviceForMediaStream.
-     */
-    public static final String USE_FAKE_DEVICE_FOR_MEDIA_STREAM =
-            "use-fake-device-for-media-stream";
-
-    /**
      * Disable domain reliability
      * Native switch - switches::kDisableDomainReliability
      */
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 5751377..738da92 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -114,7 +114,6 @@
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.chrome.browser.vr_shell.VrShellDelegate;
-import org.chromium.chrome.browser.webapps.ChromeWebApkHost;
 import org.chromium.chrome.browser.widget.BottomSheet;
 import org.chromium.chrome.browser.widget.emptybackground.EmptyBackgroundViewWrapper;
 import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager;
@@ -402,10 +401,6 @@
                 } else {
                     preferenceManager.setPromosSkippedOnFirstStart(true);
                 }
-
-                // Notify users experimenting with WebAPKs if they need to do extra steps to enable
-                // WebAPKs.
-                ChromeWebApkHost.launchWebApkRequirementsDialogIfNeeded(this);
             }
 
             initializeUI();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java b/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java
new file mode 100644
index 0000000..43ebc0e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/NativePageHost.java
@@ -0,0 +1,43 @@
+// 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.
+
+package org.chromium.chrome.browser;
+
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.content_public.browser.LoadUrlParams;
+
+/**
+ * This interface represents a view that is capable of hosting a NativePage.
+ */
+public interface NativePageHost {
+    /**
+     * Load a non-native URL in an active tab. This should be used to either navigate away from
+     * the current native page or load external content in a content area (i.e. a tab or web
+     * contents).
+     * @param urlParams The params describing the URL to be loaded.
+     * @return {@link TabLoadStatus.FULL_PRERENDERED_PAGE_LOAD} or
+     *         {@link TabLoadStatus.PARTIAL_PRERENDERED_PAGE_LOAD} if the page has been prerendered.
+     *         {@link TabLoadStatus.DEFAULT_PAGE_LOAD} if it had not
+     */
+    int loadUrl(LoadUrlParams urlParams);
+
+    /**
+     * Determine if the browser is currently in an incognito context.
+     * @return True if the browser is incognito.
+     */
+    boolean isIncognito();
+
+    /**
+     * If the host is a tab, get the ID of its parent.
+     * @return The ID of the parent tab or INVALID_TAB_ID.
+     */
+    int getParentId();
+
+    /**
+     * Get the currently active tab. This may be the tab that is displaying the native page or the
+     * tab behind the bottom sheet (if enabled).
+     * @return The active tab.
+     */
+    Tab getActiveTab();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
index 66ca0f2..1f22fbd2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkPage.java
@@ -9,8 +9,8 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.BasicNativePage;
+import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.UrlConstants;
-import org.chromium.chrome.browser.tab.Tab;
 
 /**
  * A native page holding a {@link BookmarkManager} on _tablet_.
@@ -22,14 +22,14 @@
     /**
      * Create a new instance of the bookmarks page.
      * @param activity The activity to get context and manage fragments.
-     * @param tab The tab to load urls.
+     * @param host A NativePageHost to load urls.
      */
-    public BookmarkPage(Activity activity, Tab tab) {
-        super(activity, tab);
+    public BookmarkPage(Activity activity, NativePageHost host) {
+        super(activity, host);
     }
 
     @Override
-    protected void initialize(Activity activity, Tab tab) {
+    protected void initialize(Activity activity, NativePageHost host) {
         mManager = new BookmarkManager(activity, false);
         mManager.setBasicNativePage(this);
         mTitle = activity.getString(R.string.bookmarks);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index f8e5977..bf752e3ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -56,6 +56,7 @@
             R.id.contextmenu_add_to_contacts,
             R.id.contextmenu_copy,
             R.id.contextmenu_copy_link_text,
+            R.id.contextmenu_load_original_image,
             R.id.contextmenu_save_link_as,
             R.id.contextmenu_save_image,
             R.id.contextmenu_share_image,
@@ -69,7 +70,6 @@
             R.id.contextmenu_open_in_other_window,
             R.id.contextmenu_open_in_incognito_tab,
             R.id.contextmenu_save_link_as,
-            R.id.contextmenu_load_original_image,
             R.id.contextmenu_open_image_in_new_tab,
             R.id.contextmenu_search_by_image,
     };
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 d243419..cdbb845f 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
@@ -802,6 +802,7 @@
                 new OnClickListener() {
                     @Override
                     public void onClick(View v) {
+                        if (getActivityTab() == null) return;
                         mIntentDataProvider.sendButtonPendingIntentWithUrl(
                                 getApplicationContext(), getActivityTab().getUrl());
                         RecordUserAction.record("CustomTabsCustomActionButtonClick");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadPage.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadPage.java
index 86f5e7cb..8aafb08 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadPage.java
@@ -13,9 +13,9 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.BasicNativePage;
+import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.download.ui.DownloadManagerUi;
-import org.chromium.chrome.browser.tab.Tab;
 
 /**
  * Native page for managing downloads handled through Chrome.
@@ -29,17 +29,17 @@
     /**
      * Create a new instance of the downloads page.
      * @param activity The activity to get context and manage fragments.
-     * @param tab The tab to load urls.
+     * @param host A NativePageHost to load urls.
      */
-    public DownloadPage(Activity activity, Tab tab) {
-        super(activity, tab);
+    public DownloadPage(Activity activity, NativePageHost host) {
+        super(activity, host);
     }
 
     @Override
-    protected void initialize(Activity activity, final Tab tab) {
+    protected void initialize(Activity activity, final NativePageHost host) {
         ThreadUtils.assertOnUiThread();
 
-        mManager = new DownloadManagerUi(activity, tab.isIncognito(), activity.getComponentName());
+        mManager = new DownloadManagerUi(activity, host.isIncognito(), activity.getComponentName());
         mManager.setBasicNativePage(this);
         mTitle = activity.getString(R.string.download_manager_ui_all_downloads);
 
@@ -53,7 +53,7 @@
             public void onActivityStateChange(Activity activity, int newState) {
                 if (newState == ActivityState.RESUMED) {
                     DownloadUtils.checkForExternallyRemovedDownloads(
-                            mManager.getBackendProvider(), tab.isIncognito());
+                            mManager.getBackendProvider(), host.isIncognito());
                 }
             }
         };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/BackendItems.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/BackendItems.java
index eea1dee..4f5ed22 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/BackendItems.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/BackendItems.java
@@ -32,24 +32,17 @@
     }
 
     /**
-     * Filters out items that are displayed in this list for the current filter.
-     *
-     * @param filterType    Filter to use.
-     * @param filteredItems List for appending items that match the filter.
-     */
-    public void filter(int filterType, BackendItems filteredItems) {
-        for (DownloadHistoryItemWrapper item : this) {
-            if (item.isVisibleToUser(filterType)) filteredItems.add(item);
-        }
-    }
-
-    /**
      * Filters out items that match the query and are displayed in this list for the current filter.
      * @param filterType    Filter to use.
      * @param query         The text to match.
      * @param filteredItems List for appending items that match the filter.
      */
     public void filter(int filterType, String query, BackendItems filteredItems) {
+        if (TextUtils.isEmpty(query)) {
+            filter(filterType, filteredItems);
+            return;
+        }
+
         for (DownloadHistoryItemWrapper item : this) {
             query = query.toLowerCase(Locale.getDefault());
             Locale locale = Locale.getDefault();
@@ -91,4 +84,16 @@
     public void setIsInitialized() {
         mIsInitialized = true;
     }
+
+    /**
+     * Filters out items that are displayed in this list for the current filter.
+     *
+     * @param filterType    Filter to use.
+     * @param filteredItems List for appending items that match the filter.
+     */
+    private void filter(int filterType, BackendItems filteredItems) {
+        for (DownloadHistoryItemWrapper item : this) {
+            if (item.isVisibleToUser(filterType)) filteredItems.add(item);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
index b6b11e5..d0229505 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapter.java
@@ -63,6 +63,8 @@
      */
     private static final DeletedFileTracker sDeletedFileTracker = new DeletedFileTracker();
 
+    private static final String EMPTY_QUERY = null;
+
     private final BackendItems mRegularDownloadItems = new BackendItemsImpl();
     private final BackendItems mIncognitoDownloadItems = new BackendItemsImpl();
     private final BackendItems mOfflinePageItems = new BackendItemsImpl();
@@ -80,6 +82,7 @@
     private BackendProvider mBackendProvider;
     private OfflinePageDownloadBridge.Observer mOfflinePageObserver;
     private int mFilter = DownloadFilter.FILTER_ALL;
+    private String mSearchQuery = EMPTY_QUERY;
 
     DownloadHistoryAdapter(boolean showOffTheRecord, ComponentName parentComponent) {
         mShowOffTheRecord = showOffTheRecord;
@@ -362,23 +365,15 @@
      * @param query The text to search for.
      */
     void search(String query) {
-        if (TextUtils.isEmpty(query)) {
-            filter(mFilter);
-            return;
-        }
-
-        mFilteredItems.clear();
-        mRegularDownloadItems.filter(mFilter, query, mFilteredItems);
-        mIncognitoDownloadItems.filter(mFilter, query, mFilteredItems);
-        mOfflinePageItems.filter(mFilter, query, mFilteredItems);
-        clear(false);
-        loadItems(mFilteredItems);
+        mSearchQuery = query;
+        filter(mFilter);
     }
 
     /**
      * Called when a search is ended.
      */
     void onEndSearch() {
+        mSearchQuery = EMPTY_QUERY;
         filter(mFilter);
     }
 
@@ -398,9 +393,9 @@
     private void filter(int filterType) {
         mFilter = filterType;
         mFilteredItems.clear();
-        mRegularDownloadItems.filter(mFilter, mFilteredItems);
-        mIncognitoDownloadItems.filter(mFilter, mFilteredItems);
-        mOfflinePageItems.filter(mFilter, mFilteredItems);
+        mRegularDownloadItems.filter(mFilter, mSearchQuery, mFilteredItems);
+        mIncognitoDownloadItems.filter(mFilter, mSearchQuery, mFilteredItems);
+        mOfflinePageItems.filter(mFilter, mSearchQuery, mFilteredItems);
         clear(false);
         loadItems(mFilteredItems);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryPage.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryPage.java
index 7879df35..f19402d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryPage.java
@@ -9,8 +9,8 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.BasicNativePage;
+import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.UrlConstants;
-import org.chromium.chrome.browser.tab.Tab;
 
 /**
  * Native page for managing browsing history.
@@ -23,14 +23,14 @@
      * Create a new instance of the history page.
      * @param activity The {@link Activity} used to get context and instantiate the
      *                 {@link HistoryManager}.
-     * @param tab The tab to load URLs.
+     * @param host A NativePageHost to load URLs.
      */
-    public HistoryPage(Activity activity, Tab tab) {
-        super(activity, tab);
+    public HistoryPage(Activity activity, NativePageHost host) {
+        super(activity, host);
     }
 
     @Override
-    protected void initialize(Activity activity, final Tab tab) {
+    protected void initialize(Activity activity, final NativePageHost host) {
         mHistoryManager = new HistoryManager(activity, this);
         mTitle = activity.getString(R.string.menu_history);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeLifetimeController.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeLifetimeController.java
index e4709bc..c983ea80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeLifetimeController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeLifetimeController.java
@@ -7,7 +7,8 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
-import android.os.Process;
+import android.os.Handler;
+import android.os.Looper;
 
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
@@ -22,7 +23,7 @@
 /**
  * Answers requests to kill and (potentially) restart Chrome's main browser process.
  *
- * This class fires an Intent to start the {@link BrowserRestartActivity}, which will utltimately
+ * This class fires an Intent to start the {@link BrowserRestartActivity}, which will ultimately
  * kill the main browser process from its own process.
  *
  * https://crbug.com/515919 details why another Activity is used instead of using the AlarmManager.
@@ -30,11 +31,25 @@
  */
 class ChromeLifetimeController implements ApplicationLifetime.Observer,
         ApplicationStatus.ActivityStateListener {
-    private static final String TAG = "LifetimeController";
+    /** Amount of time to wait for Chrome to destroy all the activities of the main process. */
+    private static final long WATCHDOG_DELAY_MS = 1000;
 
+    /** Singleton instance of the class. */
     private static ChromeLifetimeController sInstance;
 
+    /** Handler to post tasks to. */
+    private final Handler mHandler;
+
+    /** Restarts the process. */
+    private final Runnable mRestartRunnable;
+
+    /** Whether or not killing the process was already initiated. */
+    private boolean mIsWaitingForProcessDeath;
+
+    /** Whether or not Chrome should be restarted after the process is killed. */
     private boolean mRestartChromeOnDestroy;
+
+    /** How many Chrome Activities are still alive. */
     private int mRemainingActivitiesCount;
 
     /**
@@ -48,12 +63,21 @@
         ApplicationLifetime.addObserver(sInstance);
     }
 
-    private ChromeLifetimeController() {}
+    private ChromeLifetimeController() {
+        mHandler = new Handler(Looper.getMainLooper());
+        mRestartRunnable = new Runnable() {
+            @Override
+            public void run() {
+                fireBrowserRestartActivityIntent();
+            }
+        };
+    }
 
     @Override
     public void onTerminate(boolean restart) {
         mRestartChromeOnDestroy = restart;
 
+        // Tell all Chrome Activities to finish themselves.
         for (WeakReference<Activity> weakActivity : ApplicationStatus.getRunningActivities()) {
             Activity activity = weakActivity.get();
             if (activity != null) {
@@ -63,8 +87,9 @@
             }
         }
 
-        // Start the Activity that will ultimately kill this process.
-        fireBrowserRestartActivityIntent(BrowserRestartActivity.ACTION_START_WATCHDOG);
+        // Kick off a timer to kill the process after a delay, which fires only if the Activities
+        // take too long to be finished.
+        mHandler.postDelayed(mRestartRunnable, WATCHDOG_DELAY_MS);
     }
 
     @Override
@@ -73,20 +98,22 @@
         if (newState == ActivityState.DESTROYED) {
             mRemainingActivitiesCount--;
             if (mRemainingActivitiesCount == 0) {
-                fireBrowserRestartActivityIntent(BrowserRestartActivity.ACTION_KILL_PROCESS);
+                fireBrowserRestartActivityIntent();
             }
         }
     }
 
-    private void fireBrowserRestartActivityIntent(String action) {
+    /** Start the Activity that will ultimately kill this process. */
+    private void fireBrowserRestartActivityIntent() {
+        ThreadUtils.assertOnUiThread();
+
+        if (mIsWaitingForProcessDeath) return;
+        mIsWaitingForProcessDeath = true;
+        mHandler.removeCallbacks(mRestartRunnable);
+
+        // The {@link BrowserRestartActivity} starts in its own process.
         Context context = ContextUtils.getApplicationContext();
-        Intent intent = new Intent();
-        intent.setAction(action);
-        intent.setClassName(
-                context.getPackageName(), BrowserRestartActivity.class.getName());
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        intent.putExtra(BrowserRestartActivity.EXTRA_MAIN_PID, Process.myPid());
-        intent.putExtra(BrowserRestartActivity.EXTRA_RESTART, mRestartChromeOnDestroy);
+        Intent intent = BrowserRestartActivity.createIntent(context, mRestartChromeOnDestroy);
         context.startActivity(intent);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index ab8ef61..9c82b82 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -296,8 +296,14 @@
         TraceEvent.begin(TAG + ".initializeSearchBoxTextView()");
         final TextView searchBoxTextView = (TextView) mSearchBoxView
                 .findViewById(R.id.search_box_text);
-        String hintText = getResources().getString(R.string.search_or_type_url);
 
+        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SHOW_GOOGLE_G_IN_OMNIBOX)) {
+            // Not using the relative version of this call because we only want to clear
+            // the drawables.
+            searchBoxTextView.setCompoundDrawables(null, null, null, null);
+        }
+
+        String hintText = getResources().getString(R.string.search_or_type_url);
         if (!DeviceFormFactor.isTablet(getContext()) || mManager.isFakeOmniboxTextEnabledTablet()) {
             searchBoxTextView.setHint(hintText);
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
index 2a73e5b..ebca6f0d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
@@ -91,10 +91,11 @@
      *                               GCMNetworkManager one.
      * @param useBackgroundLoader True if using background loader. False for prerenderer.
      */
-    public static OfflinePageEvaluationBridge getForProfile(
+    public OfflinePageEvaluationBridge(
             Profile profile, boolean useEvaluationScheduler, boolean useBackgroundLoader) {
         ThreadUtils.assertOnUiThread();
-        return nativeGetBridgeForProfile(profile, useEvaluationScheduler, useBackgroundLoader);
+        mNativeOfflinePageEvaluationBridge =
+                nativeCreateBridgeForProfile(profile, useEvaluationScheduler, useBackgroundLoader);
     }
 
     private static final String TAG = "OPEvalBridge";
@@ -105,19 +106,14 @@
 
     private OutputStreamWriter mLogOutput;
 
-    /**
-     * Creates an offline page evalutaion bridge for a given profile.
-     */
-    OfflinePageEvaluationBridge(long nativeOfflinePageEvaluationBridge) {
-        mNativeOfflinePageEvaluationBridge = nativeOfflinePageEvaluationBridge;
-    }
-
-    /**
-     * Called by the native OfflinePageEvaluationBridge.
-     */
-    @CalledByNative
-    private static OfflinePageEvaluationBridge create(long nativeOfflinePageEvaluationBridge) {
-        return new OfflinePageEvaluationBridge(nativeOfflinePageEvaluationBridge);
+    /** Destroys the native portion of the bridge. */
+    public void destory() {
+        if (mNativeOfflinePageEvaluationBridge != 0) {
+            nativeDestory(mNativeOfflinePageEvaluationBridge);
+            mNativeOfflinePageEvaluationBridge = 0;
+            mIsOfflinePageModelLoaded = false;
+        }
+        mObservers.clear();
     }
 
     /**
@@ -250,17 +246,6 @@
     }
 
     @CalledByNative
-    private void offlinePageEvaluationBridgeDestroyed() {
-        ThreadUtils.assertOnUiThread();
-        assert mNativeOfflinePageEvaluationBridge != 0;
-
-        mNativeOfflinePageEvaluationBridge = 0;
-        mIsOfflinePageModelLoaded = false;
-
-        mObservers.clear();
-    }
-
-    @CalledByNative
     private static void createOfflinePageAndAddToList(List<OfflinePageItem> offlinePagesList,
             String url, long offlineId, String clientNamespace, String clientId, String filePath,
             long fileSize, long creationTime, int accessCount, long lastAccessTimeMs) {
@@ -275,8 +260,9 @@
                 creationTime, accessCount, lastAccessTimeMs);
     }
 
-    private static native OfflinePageEvaluationBridge nativeGetBridgeForProfile(
+    private native long nativeCreateBridgeForProfile(
             Profile profile, boolean useEvaluationScheduler, boolean useBackgroundLoader);
+    private native void nativeDestory(long nativeOfflinePageEvaluationBridge);
 
     private native void nativeGetAllPages(long nativeOfflinePageEvaluationBridge,
             List<OfflinePageItem> offlinePages, final Callback<List<OfflinePageItem>> callback);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 97cc3b3b..bb75d52 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -407,15 +407,6 @@
     public static final int BUTTON_TYPE_NAVIGATION_ICON = 2;
 
     /**
-     * @param outRect Populated with a {@link Rect} that represents the {@link Tab} specific content
-     *                of this {@link LocationBar}.
-     */
-    public void getContentRect(Rect outRect) {
-        outRect.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(),
-                getHeight() - getPaddingBottom());
-    }
-
-    /**
      * A widget for showing a list of omnibox suggestions.
      */
     @VisibleForTesting
@@ -2155,7 +2146,13 @@
             LoadUrlParams loadUrlParams = new LoadUrlParams(url);
             loadUrlParams.setVerbatimHeaders(GeolocationHeader.getGeoHeader(url, currentTab));
             loadUrlParams.setTransitionType(transition | PageTransition.FROM_ADDRESS_BAR);
-            currentTab.loadUrl(loadUrlParams);
+
+            // If the bottom sheet exists, route the navigation through it instead of the tab.
+            if (mBottomSheet != null) {
+                mBottomSheet.loadUrl(loadUrlParams);
+            } else {
+                currentTab.loadUrl(loadUrlParams);
+            }
 
             setUrlToPageUrl();
             RecordUserAction.record("MobileOmniboxUse");
@@ -2314,7 +2311,7 @@
      * Updates the display of the mic button.
      * @param urlFocusChangePercent The completeion percentage of the URL focus change animation.
      */
-    protected void updateMicButtonVisiblity(float urlFocusChangePercent) {
+    protected void updateMicButtonVisibility(float urlFocusChangePercent) {
         boolean visible = !shouldShowDeleteButton();
         boolean showMicButton = mVoiceSearchEnabled && visible
                 && (mUrlBar.hasFocus() || mUrlFocusChangeInProgress
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
index 30093bb..d60cb41 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -12,6 +12,7 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Rect;
+import android.support.v4.view.animation.FastOutLinearInInterpolator;
 import android.text.Selection;
 import android.util.AttributeSet;
 import android.view.KeyEvent;
@@ -20,15 +21,19 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.WindowDelegate;
 import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper;
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.util.MathUtils;
 import org.chromium.chrome.browser.widget.TintedImageButton;
 import org.chromium.ui.UiUtils;
 
@@ -41,13 +46,20 @@
 
     private static final int ACTION_BUTTON_TOUCH_OVERFLOW_LEFT = 15;
 
+    private static final Interpolator GOOGLE_G_FADE_INTERPOLATOR =
+            new FastOutLinearInInterpolator();
+
     private View mFirstVisibleFocusedView;
     private View mIncognitoBadge;
+    private View mGoogleGContainer;
+    private View mGoogleG;
     private View mUrlActionsContainer;
     private TintedImageButton mMenuButton;
     private ImageView mMenuBadge;
     private View mMenuButtonWrapper;
     private int mIncognitoBadgePadding;
+    private int mGoogleGWidth;
+    private int mGoogleGMargin;
     private float mUrlFocusChangePercent;
     private Runnable mKeyboardResizeModeTask;
     private ObjectAnimator mOmniboxBackgroundAnimator;
@@ -72,6 +84,11 @@
         mIncognitoBadgePadding =
                 getResources().getDimensionPixelSize(R.dimen.location_bar_incognito_badge_padding);
 
+        mGoogleGContainer = findViewById(R.id.google_g_container);
+        mGoogleG = findViewById(R.id.google_g);
+        mGoogleGWidth = getResources().getDimensionPixelSize(R.dimen.location_bar_google_g_width);
+        mGoogleGMargin = getResources().getDimensionPixelSize(R.dimen.location_bar_google_g_margin);
+
         mUrlActionsContainer = findViewById(R.id.url_action_container);
         Rect delegateArea = new Rect();
         mUrlActionsContainer.getHitRect(delegateArea);
@@ -113,18 +130,6 @@
         return mMenuButton;
     }
 
-    @Override
-    public void getContentRect(Rect outRect) {
-        super.getContentRect(outRect);
-        if (mIncognitoBadge.getVisibility() == View.GONE) return;
-
-        if (!ApiCompatibilityUtils.isLayoutRtl(this)) {
-            outRect.left += mIncognitoBadge.getWidth();
-        } else {
-            outRect.right -= mIncognitoBadge.getWidth();
-        }
-    }
-
     /**
      * @return The first view visible when the location bar is focused.
      */
@@ -270,7 +275,35 @@
     @Override
     protected void updateButtonVisibility() {
         updateDeleteButtonVisibility();
-        updateMicButtonVisiblity(mUrlFocusChangePercent);
+        updateMicButtonVisibility(mUrlFocusChangePercent);
+        updateGoogleG();
+    }
+
+    private void updateGoogleG() {
+        NewTabPage ntp = getToolbarDataProvider().getNewTabPageForCurrentTab();
+
+        // If the default search engine is not Google, isLocationBarShownInNTP() will return false.
+        if (ntp == null || !ntp.isLocationBarShownInNTP()
+                || !ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SHOW_GOOGLE_G_IN_OMNIBOX)) {
+            mGoogleGContainer.setVisibility(View.GONE);
+            return;
+        }
+
+        mGoogleGContainer.setVisibility(View.VISIBLE);
+        float animationProgress =
+                GOOGLE_G_FADE_INTERPOLATOR.getInterpolation(mUrlFocusChangePercent);
+        mGoogleG.setAlpha(1 - animationProgress);
+
+        // Shrink the width down to zero, and the end margin down to half of its starting value.
+        FrameLayout.LayoutParams layoutParams =
+                (FrameLayout.LayoutParams) mGoogleG.getLayoutParams();
+        layoutParams.width = Math.round(mGoogleGWidth * (1 - animationProgress));
+        ApiCompatibilityUtils.setMarginEnd(
+                layoutParams, Math.round(MathUtils.interpolate(
+                                      mGoogleGMargin, mGoogleGMargin / 2f, animationProgress)));
+
+        // Just calling requestLayout() would not resolve the end margin.
+        mGoogleG.setLayoutParams(layoutParams);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
index ece6a6d..07cb7c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
@@ -277,7 +277,7 @@
         if (showSaveOfflineButton) mSaveOfflineButton.setEnabled(isSaveOfflineButtonEnabled());
 
         if (!mShouldShowButtonsWhenUnfocused) {
-            updateMicButtonVisiblity(mUrlFocusChangePercent);
+            updateMicButtonVisibility(mUrlFocusChangePercent);
         } else {
             mMicButton.setVisibility(shouldShowMicButton() ? View.VISIBLE : View.GONE);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
index da59e61..9e4f089 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/physicalweb/PhysicalWebDiagnosticsPage.java
@@ -17,8 +17,8 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.BasicNativePage;
+import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.UrlConstants;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.components.location.LocationUtils;
 
 import java.util.HashSet;
@@ -38,15 +38,15 @@
     /**
      * Create a new instance of the Physical Web diagnostics page.
      * @param activity The activity to get context and manage fragments.
-     * @param tab The tab to load urls.
+     * @param host A NativePageHost to load urls.
      */
-    public PhysicalWebDiagnosticsPage(Activity activity, Tab tab) {
-        super(activity, tab);
+    public PhysicalWebDiagnosticsPage(Activity activity, NativePageHost host) {
+        super(activity, host);
     }
 
     @Override
-    @SuppressWarnings("deprecation")  // Update usage of Html.fromHtml when API min is 24
-    protected void initialize(final Activity activity, Tab tab) {
+    @SuppressWarnings("deprecation") // Update usage of Html.fromHtml when API min is 24
+    protected void initialize(final Activity activity, NativePageHost host) {
         Resources resources = activity.getResources();
         mSuccessColor = colorToHexValue(ApiCompatibilityUtils.getColor(resources,
                 R.color.physical_web_diags_success_color));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index 3aeae80..9088cf0f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -10,6 +10,7 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
@@ -17,7 +18,6 @@
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.widget.BottomSheet;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
@@ -36,7 +36,7 @@
     private final TileGroup.Delegate mTileGroupDelegate;
 
     public SuggestionsBottomSheetContent(
-            final ChromeActivity activity, Tab tab, TabModelSelector tabModelSelector) {
+            final ChromeActivity activity, NativePageHost host, TabModelSelector tabModelSelector) {
         mRecyclerView = (NewTabPageRecyclerView) LayoutInflater.from(activity).inflate(
                 R.layout.new_tab_page_recycler_view, null, false);
 
@@ -45,11 +45,10 @@
 
         mSnippetsBridge = new SnippetsBridge(profile);
         SuggestionsNavigationDelegate navigationDelegate =
-                new SuggestionsNavigationDelegateImpl(activity, profile, tab, tabModelSelector);
+                new SuggestionsNavigationDelegateImpl(activity, profile, host, tabModelSelector);
 
         mSuggestionsManager = new SuggestionsUiDelegateImpl(
-                mSnippetsBridge, mSnippetsBridge, navigationDelegate, profile, tab);
-
+                mSnippetsBridge, mSnippetsBridge, navigationDelegate, profile, host);
         mContextMenuManager = new ContextMenuManager(activity, navigationDelegate, mRecyclerView);
         activity.getWindowAndroid().addContextMenuCloseListener(mContextMenuManager);
         mSuggestionsManager.addDestructionObserver(new DestructionObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
index 1bdeebf..2295647d3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
@@ -7,6 +7,7 @@
 import android.app.Activity;
 
 import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.bookmarks.BookmarkUtils;
 import org.chromium.chrome.browser.download.DownloadUtils;
@@ -19,7 +20,6 @@
 import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageNotificationBridge;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -42,14 +42,14 @@
     private final Activity mActivity;
     private final Profile mProfile;
 
-    private final Tab mTab;
+    private final NativePageHost mHost;
     private final TabModelSelector mTabModelSelector;
 
-    public SuggestionsNavigationDelegateImpl(
-            Activity activity, Profile profile, Tab currentTab, TabModelSelector tabModelSelector) {
+    public SuggestionsNavigationDelegateImpl(Activity activity, Profile profile,
+            NativePageHost host, TabModelSelector tabModelSelector) {
         mActivity = activity;
         mProfile = profile;
-        mTab = currentTab;
+        mHost = host;
         mTabModelSelector = tabModelSelector;
     }
 
@@ -72,13 +72,13 @@
     @Override
     public void navigateToRecentTabs() {
         RecordUserAction.record("MobileNTPSwitchToOpenTabs");
-        mTab.loadUrl(new LoadUrlParams(UrlConstants.RECENT_TABS_URL));
+        mHost.loadUrl(new LoadUrlParams(UrlConstants.RECENT_TABS_URL));
     }
 
     @Override
     public void navigateToDownloadManager() {
         RecordUserAction.record("MobileNTPSwitchToDownloadManager");
-        DownloadUtils.showDownloadManager(mActivity, mTab);
+        DownloadUtils.showDownloadManager(mActivity, mHost.getActiveTab());
     }
 
     @Override
@@ -112,7 +112,7 @@
 
         // TODO(treib): Also track other dispositions. crbug.com/665915
         if (windowOpenDisposition == WindowOpenDisposition.CURRENT_TAB) {
-            NewTabPageUma.monitorContentSuggestionVisit(mTab, article.mCategory);
+            NewTabPageUma.monitorContentSuggestionVisit(mHost.getActiveTab(), article.mCategory);
         }
 
         LoadUrlParams loadUrlParams;
@@ -147,7 +147,7 @@
     public void openUrl(int windowOpenDisposition, LoadUrlParams loadUrlParams) {
         switch (windowOpenDisposition) {
             case WindowOpenDisposition.CURRENT_TAB:
-                mTab.loadUrl(loadUrlParams);
+                mHost.loadUrl(loadUrlParams);
                 break;
             case WindowOpenDisposition.NEW_FOREGROUND_TAB:
                 openUrlInNewTab(loadUrlParams, false);
@@ -177,12 +177,12 @@
 
     private void openUrlInNewWindow(LoadUrlParams loadUrlParams) {
         TabDelegate tabDelegate = new TabDelegate(false);
-        tabDelegate.createTabInOtherWindow(loadUrlParams, mActivity, mTab.getParentId());
+        tabDelegate.createTabInOtherWindow(loadUrlParams, mActivity, mHost.getParentId());
     }
 
     private void openUrlInNewTab(LoadUrlParams loadUrlParams, boolean incognito) {
-        mTabModelSelector.openNewTab(
-                loadUrlParams, TabLaunchType.FROM_LONGPRESS_BACKGROUND, mTab, incognito);
+        mTabModelSelector.openNewTab(loadUrlParams, TabLaunchType.FROM_LONGPRESS_BACKGROUND,
+                mHost.getActiveTab(), incognito);
     }
 
     private void saveUrlForOffline(String url) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
index 50bcd29..e5b5c47 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
@@ -12,6 +12,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
@@ -22,7 +23,6 @@
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.tab.Tab;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -41,7 +41,7 @@
 
     private final Profile mProfile;
 
-    private final Tab mTab;
+    private final NativePageHost mHost;
 
     private FaviconHelper mFaviconHelper;
     private LargeIconBridge mLargeIconBridge;
@@ -50,13 +50,14 @@
 
     public SuggestionsUiDelegateImpl(SuggestionsSource suggestionsSource,
             SuggestionsMetricsReporter metricsReporter,
-            SuggestionsNavigationDelegate navigationDelegate, Profile profile, Tab currentTab) {
+            SuggestionsNavigationDelegate navigationDelegate, Profile profile,
+            NativePageHost host) {
         mSuggestionsSource = suggestionsSource;
         mSuggestionsMetricsReporter = metricsReporter;
         mSuggestionsNavigationDelegate = navigationDelegate;
 
         mProfile = profile;
-        mTab = currentTab;
+        mHost = host;
     }
 
     @Override
@@ -76,8 +77,11 @@
     public void ensureIconIsAvailable(String pageUrl, String iconUrl, boolean isLargeIcon,
             boolean isTemporary, IconAvailabilityCallback callback) {
         if (mIsDestroyed) return;
-        getFaviconHelper().ensureIconIsAvailable(mProfile, mTab.getWebContents(), pageUrl, iconUrl,
-                isLargeIcon, isTemporary, callback);
+        if (mHost.getActiveTab() != null) {
+            getFaviconHelper().ensureIconIsAvailable(mProfile,
+                    mHost.getActiveTab().getWebContents(), pageUrl, iconUrl, isLargeIcon,
+                    isTemporary, callback);
+        }
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index fdcf2d0..2f573f618 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -47,6 +47,7 @@
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.IntentHandler.TabOpenType;
 import org.chromium.chrome.browser.NativePage;
+import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.SwipeRefreshHandler;
 import org.chromium.chrome.browser.TabState;
 import org.chromium.chrome.browser.TabState.WebContentsState;
@@ -128,7 +129,7 @@
  *    object.
  */
 public class Tab implements ViewGroup.OnHierarchyChangeListener,
-        View.OnSystemUiVisibilityChangeListener {
+                            View.OnSystemUiVisibilityChangeListener, NativePageHost {
     public static final int INVALID_TAB_ID = -1;
 
     /** Return value from {@link #getBookmarkId()} if this tab is not bookmarked. */
@@ -637,6 +638,7 @@
      * @return FULL_PRERENDERED_PAGE_LOAD or PARTIAL_PRERENDERED_PAGE_LOAD if the page has been
      *         prerendered. DEFAULT_PAGE_LOAD if it had not.
      */
+    @Override
     public int loadUrl(LoadUrlParams params) {
         try {
             TraceEvent.begin("Tab.loadUrl");
@@ -1017,9 +1019,7 @@
         return mId;
     }
 
-    /**
-     * @return Whether or not this tab is incognito.
-     */
+    @Override
     public boolean isIncognito() {
         return mIncognito;
     }
@@ -2135,10 +2135,16 @@
     /**
      * @return The id of the tab that caused this tab to be opened.
      */
+    @Override
     public int getParentId() {
         return mParentId;
     }
 
+    @Override
+    public Tab getActiveTab() {
+        return this;
+    }
+
     /**
      * @return Whether the tab should be grouped with its parent tab (true by default).
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
index 2eb8d89..40a13bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -19,9 +19,6 @@
     /** A handle to the bottom sheet. */
     private BottomSheet mBottomSheet;
 
-    /** The state of the bottom sheet before the URL bar was focused. */
-    private int mStateBeforeUrlFocus;
-
     /**
      * Constructs a BottomToolbarPhone object.
      * @param context The Context in which this View object is created.
@@ -42,11 +39,9 @@
     protected void triggerUrlFocusAnimation(final boolean hasFocus) {
         super.triggerUrlFocusAnimation(hasFocus);
 
-        if (mBottomSheet == null) return;
+        if (mBottomSheet == null || !hasFocus) return;
 
-        if (hasFocus) mStateBeforeUrlFocus = mBottomSheet.getSheetState();
-        mBottomSheet.setSheetState(
-                hasFocus ? BottomSheet.SHEET_STATE_FULL : mStateBeforeUrlFocus, true);
+        mBottomSheet.setSheetState(BottomSheet.SHEET_STATE_FULL, true);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 0f77bac..51c48a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -287,11 +287,11 @@
         }
         // TODO(mthiesse): When we have VR UI for opening new tabs, etc., allow VR Shell to be
         // entered without any current tabs.
-        if (tab == null || tab.getContentViewCore() == null) {
+        if (tab == null) {
             return false;
         }
-        // For now we don't handle native pages. crbug.com/661609
-        if (tab.getNativePage() != null || tab.isShowingSadTab()) {
+        // For now we don't handle sad tab page. crbug.com/661609
+        if (tab.isShowingSadTab()) {
             return false;
         }
         // crbug.com/667781
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
index 203ccc7..b5f9ce3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.vr_shell;
 
 import android.annotation.SuppressLint;
+import android.graphics.Canvas;
 import android.graphics.Point;
 import android.os.StrictMode;
 import android.view.MotionEvent;
@@ -25,6 +26,7 @@
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeVersionInfo;
+import org.chromium.chrome.browser.NativePage;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -39,6 +41,7 @@
 import org.chromium.content.browser.ContentView;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.ViewAndroidDelegate;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid;
@@ -78,17 +81,17 @@
     private final View.OnTouchListener mTouchListener;
     private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
 
-
     private long mNativeVrShell;
 
     private FrameLayout mUiCVCContainer;
+    private FrameLayout mRenderToSurfaceLayout;
+    private Surface mSurface;
     private View mPresentationView;
 
     // The tab that holds the main ContentViewCore.
     private Tab mTab;
+    private NativePage mNativePage;
 
-    // The ContentViewCore for the main content rect in VR.
-    private ContentViewCore mContentCVC;
     private WindowAndroid mOriginalWindowAndroid;
     private VrWindowAndroid mContentVrWindowAndroid;
 
@@ -159,17 +162,44 @@
         mTabObserver = new EmptyTabObserver() {
             @Override
             public void onContentChanged(Tab tab) {
-                if (tab.getNativePage() != null || tab.isShowingSadTab()) {
-                    // For now we don't handle native pages. crbug.com/661609.
+                if (mNativeVrShell == 0) return;
+                if (tab.isShowingSadTab()) {
+                    // For now we don't support the sad tab page. crbug.com/661609.
                     forceExitVr();
+                    return;
+                }
+                if (mNativePage != null) {
+                    UiUtils.removeViewFromParent(mNativePage.getView());
+                    mNativePage = null;
+                    if (tab.getNativePage() == null) {
+                        nativeRestoreContentSurface(mNativeVrShell);
+                        mRenderToSurfaceLayout.setVisibility(View.INVISIBLE);
+                        mSurface = null;
+                    }
+                }
+                if (tab.getNativePage() != null) {
+                    mRenderToSurfaceLayout.setVisibility(View.VISIBLE);
+                    mNativePage = tab.getNativePage();
+                    if (mSurface == null) mSurface = nativeTakeContentSurface(mNativeVrShell);
+                    mRenderToSurfaceLayout.addView(mNativePage.getView(),
+                            new FrameLayout.LayoutParams(
+                                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+                    mNativePage.getView().invalidate();
+                }
+                setContentCssSize(mLastContentWidth, mLastContentHeight, mLastContentDpr);
+                if (tab.getNativePage() == null && mTab.getContentViewCore() != null) {
+                    mTab.getContentViewCore().onAttachedToWindow();
+                    mTab.getContentViewCore().getContainerView().requestFocus();
+                    nativeSwapContents(mNativeVrShell, mTab.getContentViewCore().getWebContents());
+                } else {
+                    nativeSwapContents(mNativeVrShell, null);
                 }
             }
 
             @Override
             public void onWebContentsSwapped(
                     Tab tab, boolean didStartLoad, boolean didFinishLoad) {
-                nativeSwapContents(mNativeVrShell, mContentCVC.getWebContents());
-                setContentCssSize(mLastContentWidth, mLastContentHeight, mLastContentDpr);
+                onContentChanged(tab);
             }
 
             @Override
@@ -204,13 +234,27 @@
                 return false;
             }
         };
+
+        mRenderToSurfaceLayout = new FrameLayout(mActivity) {
+            @Override
+            protected void dispatchDraw(Canvas canvas) {
+                if (mSurface == null) return;
+                final Canvas surfaceCanvas = mSurface.lockCanvas(null);
+                super.dispatchDraw(surfaceCanvas);
+                mSurface.unlockCanvasAndPost(surfaceCanvas);
+            }
+
+            @Override
+            public boolean dispatchTouchEvent(MotionEvent event) {
+                return true;
+            }
+        };
+        mRenderToSurfaceLayout.setVisibility(View.INVISIBLE);
+        addView(mRenderToSurfaceLayout);
     }
 
     @Override
     public void initializeNative(Tab currentTab, boolean forWebVR) {
-        assert currentTab.getContentViewCore() != null;
-        mTab = currentTab;
-        mContentCVC = mTab.getContentViewCore();
         mContentVrWindowAndroid = new VrWindowAndroid(mActivity, mContentVirtualDisplay);
 
         mUiVrWindowAndroid = new VrWindowAndroid(mActivity, mUiVirtualDisplay);
@@ -220,8 +264,7 @@
         mUiCVC.initialize(ViewAndroidDelegate.createBasicDelegate(uiContentView),
                 uiContentView, mUiContents, mUiVrWindowAndroid);
 
-        mNativeVrShell = nativeInit(mContentCVC.getWebContents(),
-                mContentVrWindowAndroid.getNativePointer(), mUiContents,
+        mNativeVrShell = nativeInit(mUiContents, mContentVrWindowAndroid.getNativePointer(),
                 mUiVrWindowAndroid.getNativePointer(), forWebVR, mDelegate,
                 getGvrApi().getNativeGvrContext(), mReprojectedRendering);
 
@@ -235,6 +278,11 @@
             setContentCssSize(DEFAULT_CONTENT_WIDTH, DEFAULT_CONTENT_HEIGHT, DEFAULT_DPR);
         }
 
+        swapToForegroundTab();
+        createTabList();
+        mActivity.getTabModelSelector().addObserver(mTabModelSelectorObserver);
+        createTabModelSelectorTabObserver();
+
         nativeLoadUIContent(mNativeVrShell);
 
         mPresentationView.setOnTouchListener(mTouchListener);
@@ -247,13 +295,6 @@
         mUiCVC.setBottomControlsHeight(0);
         mUiCVC.setTopControlsHeight(0, false);
         mUiVrWindowAndroid.onVisibilityChanged(true);
-
-        initializeTabForVR();
-        mTab.addObserver(mTabObserver);
-        mTab.updateFullscreenEnabledState();
-        createTabList();
-        mActivity.getTabModelSelector().addObserver(mTabModelSelectorObserver);
-        createTabModelSelectorTabObserver();
     }
 
     private void createTabList() {
@@ -280,24 +321,22 @@
             forceExitVr();
             return;
         }
-        mTab.removeObserver(mTabObserver);
-        restoreTabFromVR();
-        mTab.updateFullscreenEnabledState();
+        if (mTab != null) {
+            mTab.removeObserver(mTabObserver);
+            restoreTabFromVR();
+            mTab.updateFullscreenEnabledState();
+        }
 
         mTab = tab;
-        mContentCVC = mTab.getContentViewCore();
         initializeTabForVR();
-        nativeSwapContents(mNativeVrShell, mContentCVC.getWebContents());
-        setContentCssSize(mLastContentWidth, mLastContentHeight, mLastContentDpr);
         mTab.addObserver(mTabObserver);
         mTab.updateFullscreenEnabledState();
+        mTabObserver.onContentChanged(mTab);
     }
 
     private void initializeTabForVR() {
-        mOriginalWindowAndroid = mContentCVC.getWindowAndroid();
+        mOriginalWindowAndroid = mTab.getWindowAndroid();
         mTab.updateWindowAndroid(mContentVrWindowAndroid);
-        mContentCVC.onAttachedToWindow();
-        mContentCVC.getContainerView().requestFocus();
 
         // Make sure we are not redirecting to another app, i.e. out of VR mode.
         mNonVrTabRedirectHandler = mTab.getTabRedirectHandler();
@@ -340,16 +379,37 @@
         mLastContentWidth = width;
         mLastContentHeight = height;
         mLastContentDpr = dpr;
+
+        if (mNativePage != null) {
+            // Native pages don't listen to our DPR changes, so to get them to render at the correct
+            // size we need to make them larger.
+            DisplayAndroid primaryDisplay = DisplayAndroid.getNonMultiDisplay(mActivity);
+            float dip = primaryDisplay.getDipScale();
+            width *= (dip / dpr);
+            height *= (dip / dpr);
+        }
+
         int surfaceWidth = (int) Math.ceil(width * dpr);
         int surfaceHeight = (int) Math.ceil(height * dpr);
 
         Point size = new Point(surfaceWidth, surfaceHeight);
         mContentVirtualDisplay.update(size, size, dpr, null, null, null);
-        mContentCVC.onSizeChanged(surfaceWidth, surfaceHeight, 0, 0);
-        mContentCVC.onPhysicalBackingSizeChanged(surfaceWidth, surfaceHeight);
+        if (mTab != null && mTab.getContentViewCore() != null) {
+            mTab.getContentViewCore().onSizeChanged(surfaceWidth, surfaceHeight, 0, 0);
+            mTab.getContentViewCore().onPhysicalBackingSizeChanged(surfaceWidth, surfaceHeight);
+        }
+        mRenderToSurfaceLayout.setLayoutParams(
+                new FrameLayout.LayoutParams(surfaceWidth, surfaceHeight));
         nativeContentPhysicalBoundsChanged(mNativeVrShell, surfaceWidth, surfaceHeight, dpr);
     }
 
+    @CalledByNative
+    public void contentSurfaceChanged() {
+        if (mSurface != null || mNativePage == null) return;
+        mSurface = nativeTakeContentSurface(mNativeVrShell);
+        mNativePage.getView().invalidate();
+    }
+
     @Override
     public boolean dispatchTouchEvent(MotionEvent event) {
         // Normally, touch event is dispatched to presentation view only if the phone is paired with
@@ -473,9 +533,9 @@
         };
     }
 
-    private native long nativeInit(WebContents contentWebContents,
-            long nativeContentWindowAndroid, WebContents uiWebContents, long nativeUiWindowAndroid,
-            boolean forWebVR, VrShellDelegate delegate, long gvrApi, boolean reprojectedRendering);
+    private native long nativeInit(WebContents uiWebContents, long nativeContentWindowAndroid,
+            long nativeUiWindowAndroid, boolean forWebVR, VrShellDelegate delegate, long gvrApi,
+            boolean reprojectedRendering);
     private native void nativeSetSurface(long nativeVrShell, Surface surface);
     private native void nativeSwapContents(long nativeVrShell, WebContents webContents);
     private native void nativeLoadUIContent(long nativeVrShell);
@@ -494,4 +554,6 @@
     private native void nativeOnTabUpdated(long nativeVrShell, boolean incognito, int id,
             String title);
     private native void nativeOnTabRemoved(long nativeVrShell, boolean incognito, int id);
+    private native Surface nativeTakeContentSurface(long nativeVrShell);
+    private native void nativeRestoreContentSurface(long nativeVrShell);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
index 10ec297..d1bcd8d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
@@ -5,21 +5,16 @@
 package org.chromium.chrome.browser.webapps;
 
 import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
 import android.os.StrictMode;
 import android.provider.Settings;
-import android.support.v7.app.AlertDialog;
 
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.library_loader.LibraryLoader;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeApplication;
 import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
 import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
@@ -144,25 +139,6 @@
     }
 
     /**
-     * Show dialog warning user that "installation from unknown sources" is required by the WebAPK
-     * experiment if the user enabled "Improved Add to Home screen" via chrome://flags.
-     */
-    public static void launchWebApkRequirementsDialogIfNeeded(Context context) {
-        // Show dialog on Canary & Dev. Installation via "unknown sources" is disabled via
-        // variations on other channels.
-        if (!ChromeVersionInfo.isCanaryBuild() && !ChromeVersionInfo.isDevBuild()) return;
-
-        // Update cached state. {@link #isEnabled()} and {@link #canUseGooglePlayToInstallWebApk()}
-        // need the state to be up to date.
-        cacheEnabledStateForNextLaunch();
-
-        if (isEnabled() && !canUseGooglePlayToInstallWebApk()
-                && !installingFromUnknownSourcesAllowed()) {
-            showUnknownSourcesNeededDialog(context);
-        }
-    }
-
-    /**
      * Once native is loaded we can consult the command-line (set via about:flags) and also finch
      * state to see if we should enable WebAPKs.
      */
@@ -193,31 +169,6 @@
         }
     }
 
-    /**
-     * Show dialog warning user that "installation from unknown sources" is required by the WebAPK
-     * experiment.
-     */
-    private static void showUnknownSourcesNeededDialog(final Context context) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(context);
-        builder.setTitle(R.string.webapk_unknown_sources_dialog_title);
-        builder.setMessage(R.string.webapk_unknown_sources_dialog_message);
-        builder.setPositiveButton(R.string.webapk_unknown_sources_settings_button,
-                new DialogInterface.OnClickListener() {
-                    @Override
-                    public void onClick(DialogInterface dialog, int id) {
-                        // Open Android Security settings.
-                        Intent intent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
-                        context.startActivity(intent);
-                    }
-                });
-        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-            @Override
-            public void onClick(DialogInterface dialog, int id) {}
-        });
-        AlertDialog dialog = builder.create();
-        dialog.show();
-    }
-
     private static native boolean nativeCanUseGooglePlayToInstallWebApk();
     private static native boolean nativeCanInstallFromUnknownSources();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
index 15bd2a5..80debdf6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/BottomSheet.java
@@ -24,10 +24,16 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ObserverList;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.NativePageHost;
+import org.chromium.chrome.browser.TabLoadStatus;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
+import org.chromium.chrome.browser.ntp.NativePageFactory;
 import org.chromium.chrome.browser.suggestions.SuggestionsBottomSheetContent;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.util.MathUtils;
+import org.chromium.content_public.browser.LoadUrlParams;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -42,7 +48,9 @@
  * All the computation in this file is based off of the bottom of the screen instead of the top
  * for simplicity. This means that the bottom of the screen is 0 on the Y axis.
  */
-public class BottomSheet extends FrameLayout implements FadingBackgroundView.FadingViewObserver {
+
+public class BottomSheet
+        extends FrameLayout implements FadingBackgroundView.FadingViewObserver, NativePageHost {
     /** The different states that the bottom sheet can have. */
     @IntDef({SHEET_STATE_PEEK, SHEET_STATE_HALF, SHEET_STATE_FULL})
     @Retention(RetentionPolicy.SOURCE)
@@ -325,6 +333,7 @@
      * Adds layout change listeners to the views that the bottom sheet depends on. Namely the
      * heights of the root view and control container are important as they are used in many of the
      * calculations in this class.
+     * @param activity An activity for loading native pages.
      * @param root The container of the bottom sheet.
      * @param controlContainer The container for the toolbar.
      */
@@ -379,6 +388,45 @@
         mBottomSheetContentContainer.addView(mPlaceholder, placeHolderParams);
     }
 
+    @Override
+    public int loadUrl(LoadUrlParams params) {
+        // Native page URLs in this context do not need to communicate with the tab.
+        if (NativePageFactory.isNativePageUrl(params.getUrl(), isIncognito())) {
+            return TabLoadStatus.PAGE_LOAD_FAILED;
+        }
+
+        // In all non-native cases, minimize the sheet.
+        setSheetState(SHEET_STATE_PEEK, true);
+
+        assert mTabModelSelector != null;
+
+        // First try to get the tab behind the sheet.
+        if (mTabModelSelector.getCurrentTab() != null) {
+            return mTabModelSelector.getCurrentTab().loadUrl(params);
+        }
+
+        // If no tab is active behind the sheet, open a new one.
+        mTabModelSelector.openNewTab(
+                params, TabModel.TabLaunchType.FROM_CHROME_UI, null, isIncognito());
+        return TabLoadStatus.DEFAULT_PAGE_LOAD;
+    }
+
+    @Override
+    public boolean isIncognito() {
+        if (getActiveTab() == null) return false;
+        return getActiveTab().isIncognito();
+    }
+
+    @Override
+    public int getParentId() {
+        return Tab.INVALID_TAB_ID;
+    }
+
+    @Override
+    public Tab getActiveTab() {
+        return mTabModelSelector.getCurrentTab();
+    }
+
     /**
      * Determines if a touch event is inside the toolbar. This assumes the toolbar is the full
      * width of the screen and that the toolbar is at the top of the bottom sheet.
@@ -399,8 +447,7 @@
     private void onExitPeekState() {
         if (mSuggestionsContent == null) {
             mSuggestionsContent = new SuggestionsBottomSheetContent(
-                        mTabModelSelector.getCurrentTab().getActivity(),
-                        mTabModelSelector.getCurrentTab(), mTabModelSelector);
+                    mTabModelSelector.getCurrentTab().getActivity(), this, mTabModelSelector);
         }
 
         showContent(mSuggestionsContent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
index 2135dfa..923253b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
@@ -106,6 +106,9 @@
      * Triggers a fade out of the omnibox results background creating a new animation if necessary.
      */
     public void hideFadingOverlay(boolean fadeOut) {
+        // If the overlay is already invisible, do nothing.
+        if (getVisibility() != VISIBLE) return;
+
         if (mOverlayFadeOutAnimator == null) {
             mOverlayFadeOutAnimator = ObjectAnimator.ofFloat(this, ALPHA, 0f);
             mOverlayFadeOutAnimator.setDuration(FADE_DURATION_MS);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
index de8a7c0..7bdda2b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
@@ -252,6 +252,7 @@
                 } else {
                     clearResults();
                     mFindInPageBridge.stopFinding(true);
+                    setPrevNextEnabled(false);
                 }
 
                 if (!mCurrentTab.isIncognito()) {
@@ -588,8 +589,12 @@
             model.removeObserver(mTabModelObserver);
         }
 
-        mCurrentTab.getTabWebContentsDelegateAndroid().setFindResultListener(null);
-        mCurrentTab.getTabWebContentsDelegateAndroid().setFindMatchRectsListener(null);
+        TabWebContentsDelegateAndroid delegate = mCurrentTab.getTabWebContentsDelegateAndroid();
+        if (delegate != null) {
+            delegate.setFindResultListener(null);
+            delegate.setFindMatchRectsListener(null);
+        }
+
         mCurrentTab.removeObserver(mTabObserver);
 
         UiUtils.hideKeyboard(mFindQuery);
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index ad8260c..baefead7 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -45,6 +45,7 @@
   "java/src/org/chromium/chrome/browser/LoginPrompt.java",
   "java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java",
   "java/src/org/chromium/chrome/browser/NativePage.java",
+  "java/src/org/chromium/chrome/browser/NativePageHost.java",
   "java/src/org/chromium/chrome/browser/NavigationPopup.java",
   "java/src/org/chromium/chrome/browser/PasswordUIView.java",
   "java/src/org/chromium/chrome/browser/PowerBroadcastReceiver.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java
index 82a08cd0..3d6ee2e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/DownloadHistoryAdapterTest.java
@@ -484,6 +484,41 @@
         checkAdapterContents(null, item1, item0);
     }
 
+    @SmallTest
+    public void testSearch_RemoveItem() throws Exception {
+        DownloadItem item0 = StubbedProvider.createDownloadItem(0, "19840116 12:00");
+        DownloadItem item1 = StubbedProvider.createDownloadItem(1, "19840116 12:01");
+        DownloadItem item2 = StubbedProvider.createDownloadItem(2, "19840117 12:00");
+        DownloadItem item3 = StubbedProvider.createDownloadItem(3, "19840117 12:01");
+        DownloadItem item4 = StubbedProvider.createDownloadItem(4, "19840118 12:00");
+        DownloadItem item5 = StubbedProvider.createDownloadItem(5, "19840118 12:01");
+        OfflinePageDownloadItem item6 = StubbedProvider.createOfflineItem(0, "19840118 6:00");
+        mDownloadDelegate.regularItems.add(item0);
+        mDownloadDelegate.offTheRecordItems.add(item1);
+        mDownloadDelegate.regularItems.add(item2);
+        mDownloadDelegate.regularItems.add(item3);
+        mDownloadDelegate.offTheRecordItems.add(item4);
+        mDownloadDelegate.regularItems.add(item5);
+        mOfflineDelegate.items.add(item6);
+        initializeAdapter(true);
+        checkAdapterContents(null, item5, item4, item6, null, item3, item2, null, item1, item0);
+
+        // Perform a search that matches the file name for a few downloads.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mAdapter.search("FiLe");
+            }
+        });
+
+        // Only items matching the query should be shown.
+        checkAdapterContents(null, item2, null, item1, item0);
+
+        mAdapter.onDownloadItemRemoved(item1.getId(), false);
+
+        checkAdapterContents(null, item2, null, item0);
+    }
+
     /** Checks that the adapter has the correct items in the right places. */
     private void checkAdapterContents(Object... expectedItems) {
         assertEquals(expectedItems.length, mAdapter.getItemCount());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
index 86de9aa..f98dacc7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
@@ -145,6 +145,7 @@
         checkTrue(mClearingSemaphore.tryAcquire(REMOVE_REQUESTS_TIMEOUT_MS, TimeUnit.MILLISECONDS),
                 "Timed out when clearing remaining requests!");
         mBridge.closeLog();
+        mBridge.destory();
         super.tearDown();
     }
 
@@ -228,7 +229,7 @@
             @Override
             public void run() {
                 Profile profile = Profile.getLastUsedProfile();
-                mBridge = OfflinePageEvaluationBridge.getForProfile(
+                mBridge = new OfflinePageEvaluationBridge(
                         profile, useTestingScheduler, useBackgroundLoader);
                 if (mBridge == null) {
                     fail("OfflinePageEvaluationBridge initialization failed!");
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
index aad37c4..3cf63bb6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/permissions/MediaTest.java
@@ -9,15 +9,15 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
-import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.content.common.ContentSwitches;
 
 /**
  * Test suite for media permissions requests.
  */
 @RetryOnFailure
 public class MediaTest extends PermissionTestCaseBase {
-    private static final String FAKE_DEVICE = ChromeSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM;
+    private static final String FAKE_DEVICE = ContentSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM;
     private static final String TEST_FILE = "/content/test/data/android/media_permissions.html";
 
     public MediaTest() {}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
index ec00cd5..7c30124 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/website/SiteSettingsPreferencesTest.java
@@ -13,7 +13,6 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
 import org.chromium.chrome.browser.preferences.ChromeBaseCheckBoxPreference;
 import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
@@ -24,6 +23,7 @@
 import org.chromium.chrome.test.ChromeActivityTestCaseBase;
 import org.chromium.chrome.test.util.InfoBarTestAnimationListener;
 import org.chromium.chrome.test.util.browser.LocationSettingsTestUtil;
+import org.chromium.content.common.ContentSwitches;
 import org.chromium.net.test.EmbeddedTestServer;
 
 import java.util.concurrent.Callable;
@@ -445,7 +445,7 @@
      */
     @SmallTest
     @Feature({"Preferences"})
-    @CommandLineFlags.Add(ChromeSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM)
+    @CommandLineFlags.Add(ContentSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM)
     public void testCameraBlocked() throws Exception {
         setEnableCamera(false);
 
@@ -463,7 +463,7 @@
      */
     @SmallTest
     @Feature({"Preferences"})
-    @CommandLineFlags.Add(ChromeSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM)
+    @CommandLineFlags.Add(ContentSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM)
     public void testMicBlocked() throws Exception {
         setEnableMic(false);
 
@@ -481,7 +481,7 @@
      */
     @SmallTest
     @Feature({"Preferences"})
-    @CommandLineFlags.Add(ChromeSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM)
+    @CommandLineFlags.Add(ContentSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM)
     public void testCameraNotBlocked() throws Exception {
         setEnableCamera(true);
 
@@ -501,7 +501,7 @@
      */
     @SmallTest
     @Feature({"Preferences"})
-    @CommandLineFlags.Add(ChromeSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM)
+    @CommandLineFlags.Add(ContentSwitches.USE_FAKE_DEVICE_FOR_MEDIA_STREAM)
     public void testMicNotBlocked() throws Exception {
         setEnableCamera(true);
 
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 2ecd90f..84c4713 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -988,11 +988,6 @@
         ''' It also controls what page is shown when you start Chromium or search from the Omnibox. '''
       </message>
 
-      <!-- Website Settings bubble -->
-      <message name="IDS_WEBSITE_SETTINGS_INTERNAL_PAGE" desc="Text that is displayed in the header of the Website Settings popup if the page was generated by Chrome itself.">
-        You're viewing a secure Chromium page
-      </message>
-
       <!-- Webstore strings -->
       <message name="IDS_WEBSTORE_APP_DESCRIPTION" desc="Description for the WebStore app.">
         Discover great apps, games, extensions and themes for Chromium.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 4621e0a..ce15d8ea 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6547,6 +6547,12 @@
       <message name="IDS_FLAGS_ENABLE_ENUMERATING_AUDIO_DEVICES_DESCRIPTION" desc="Description of the flag that experimentally enables enumerating audio devices on ChromeOS.">
         Experimentally enable the use of enumerating audio devices.
       </message>
+      <message name="IDS_FLAGS_NEW_USB_BACKEND_NAME" desc="Name of the flag to enable the new USB backend.">
+        Enable new USB backend
+      </message>
+      <message name="IDS_FLAGS_NEW_USB_BACKEND_DESCRIPTION" desc="Description of the flag to enable the new USB backend.">
+        Enables the new experimental USB backend for Windows.
+      </message>
 
       <!-- WebRTC logs -->
       <message name="IDS_WEBRTC_LOGS_TITLE" desc="Title for the chrome://webrtc-logs page.">
@@ -14250,6 +14256,12 @@
       <message name="IDS_FLAGS_ENABLE_ANDROID_WALLPAPERS_APP_DESCRIPTION" desc="Description of the Android Wallpapers App flag.">
         Enables the Android Wallpapers App as the default Wallpaper App on Chrome OS.
       </message>
+      <message name="IDS_FLAGS_ENABLE_TOUCH_SUPPORT_FOR_SCREEN_MAGNIFIER_NAME" desc="Name of the touch support for screen magnifier flag.">
+        Touch support for screen magnifier
+      </message>
+      <message name="IDS_FLAGS_ENABLE_TOUCH_SUPPORT_FOR_SCREEN_MAGNIFIER_DESCRIPTION" desc="Description of the touch support for screen magnifier flag.">
+        Enables touch support for screen magnifier
+      </message>
     </if>
 
     <if expr="is_android">
@@ -14337,6 +14349,12 @@
       <message name="IDS_FLAGS_NTP_CONDENSED_LAYOUT_DESCRIPTION" desc="Description for the flag to enable the condensed New Tab Page layout." translateable="false">
         Show a condensed layout on the New Tab Page.
       </message>
+      <message name="IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_NAME" desc="Name for the flag to show a Google G in the omnibox on the New Tab Page." translateable="false">
+        Google G in New Tab Page omnibox
+      </message>
+      <message name="IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_DESCRIPTION" desc="Description for the flag to show a Google G in the omnibox on the New Tab Page." translateable="false">
+        Show a Google G in the omnibox on the New Tab Page.
+      </message>
     </if>
 
     <if expr="is_android">
@@ -14363,6 +14381,13 @@
       </message>
     </if>
 
+    <message name="IDS_FLAGS_ENABLE_AUTOFILL_CREDIT_CARD_LAST_USED_DATE_DISPLAY" desc="Name for the flag to enable display the last used date of a credit card in autofill.">
+      Display the last used date of a credit card in autofill.
+    </message>
+    <message name="IDS_FLAGS_ENABLE_AUTOFILL_CREDIT_CARD_LAST_USED_DATE_DISPLAY_DESCRIPTION" desc="Description for the flag to enable display the last used date of a credit card in autofill.">
+      If enabled, display the last used date of a credit card in autofill.
+    </message>
+
     <if expr="not is_android and _google_chrome">
       <message name="IDS_FLAGS_GOOGLE_BRANDED_CONTEXT_MENU_NAME" desc="Name for the flag to enable Google branding in the context menu.">
         Google branding in the context menu
@@ -14761,6 +14786,11 @@
     <message name="IDS_FLAGS_ENABLE_MIDI_MANAGER_DYNAMIC_INSTANTIATION_DESCRIPTION" desc="Description for the flag to enable MIDIManager dynamic instantiation" translateable="false">
       Enable MIDIManager dynamic instantiation for Web MIDI.
     </message>
+
+    <!-- Automation info bar -->
+    <message name="IDS_CONTROLLED_BY_AUTOMATION" desc="Message shown when the browser session is being controlled by an automated test.">
+      Chrome is being controlled by automated test software.
+    </message>
   </messages>
  </release>
 </grit>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 8a9d672..4e570aa 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -989,11 +989,6 @@
         ''' It also controls what page is shown when you start Chrome or search from the Omnibox. '''
       </message>
 
-      <!-- Website Settings bubble -->
-      <message name="IDS_WEBSITE_SETTINGS_INTERNAL_PAGE" desc="Text that is displayed in the header of the Website Settings popup if the page was generated by Chrome itself.">
-        You're viewing a secure Google Chrome page
-      </message>
-
       <!-- Webstore strings -->
       <message name="IDS_WEBSTORE_APP_DESCRIPTION" desc="Description for the WebStore app.">
         Discover great apps, games, extensions and themes for Google Chrome.
diff --git a/chrome/app/mash/BUILD.gn b/chrome/app/mash/BUILD.gn
index e8df7e1..feba96a3 100644
--- a/chrome/app/mash/BUILD.gn
+++ b/chrome/app/mash/BUILD.gn
@@ -78,6 +78,7 @@
 catalog("catalog") {
   embedded_services = [ ":mash_manifest" ]
   catalog_deps = [ "//chrome/app:catalog" ]
+  standalone_services = [ "//mash/example/views_examples:manifest" ]
 }
 
 catalog_cpp_source("chrome_mash_catalog") {
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index f8e7c26..e818389 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -2186,6 +2186,42 @@
     <message name="IDS_SETTINGS_PEOPLE_LOCK_SCREEN_ENABLE_FINGERPRINT_CHECKBOX_LABEL" desc="The text on the label of the checkbox which allows users to enable or disable fingerprint usage.">
       Enable fingerprint login and authentication
     </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_TITLE" desc="Title of the add fingerprint dialog popup.">
+      Add Fingerprint
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER" desc="Text in the add fingerprint dialog telling users what to do for step 1.">
+      Locate the fingerprint sensor on your device, then place the finger you would like to register on it.
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_MOVE_FINGER" desc="Text in the add fingerprint dialog telling users what to do for step 2.">
+      Now move your finger slightly to capture all the different parts of your fingerprint.
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_READY" desc="Text in the add fingerprint dialog telling users what to do for step 3.">
+      Fingerprint added!
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_LIFT_FINGER" desc="Warning text in the add fingerprint dialog to tell users to lift their finger and touch the sensor again.">
+      Lift finger, then touch sensor again
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_PARTIAL_DATA" desc="Warning text in the add fingerprint dialog to tell users partial data was captured.">
+      Partial data
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSUFFICIENT_DATA" desc="Warning text in the add fingerprint dialog to tell users insufficient data was captured.">
+      Insufficient data
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_SENSOR_DIRTY" desc="Warning text in the add fingerprint dialog to tell users the fingerprint sensor is dirty.">
+      Sensor dirty
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_FINGER_TOO_SLOW" desc="Warning text in the add fingerprint dialog to tell users they have moved their finger too slow.">
+      Finger moved too slowly
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_FINGER_TOO_FAST" desc="Warning text in the add fingerprint dialog to tell users they have moved their finger too fast.">
+      Finger moved too quickly
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_CANCEL_BUTTON" desc="Text on the button in the fingerprint setup dialog which allows users to cancel a current setup.">
+      Cancel
+    </message>
+    <message name="IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_DONE_BUTTON" desc="Text on the button in the fingerprint setup dialog which allows users to exit once a fingerprint has been setup.">
+      Done
+    </message>
     <message name="IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_TITLE" desc="Title of the password prompt dialog popup.">
       Confirm your password
     </message>
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index d0e72c03..12f028a 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -29,10 +29,6 @@
     "incognito.1x.icon",
     "incognito.icon",
     "laptop.icon",
-    "navigate_back.1x.icon",
-    "navigate_back.icon",
-    "navigate_forward.1x.icon",
-    "navigate_forward.icon",
     "navigate_home.1x.icon",
     "navigate_home.icon",
     "navigate_reload.1x.icon",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 703f89e23..28c4dad 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -799,6 +799,8 @@
     "page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer.h",
     "page_load_metrics/observers/service_worker_page_load_metrics_observer.cc",
     "page_load_metrics/observers/service_worker_page_load_metrics_observer.h",
+    "page_load_metrics/observers/subresource_filter_metrics_observer.cc",
+    "page_load_metrics/observers/subresource_filter_metrics_observer.h",
     "page_load_metrics/observers/ukm_page_load_metrics_observer.cc",
     "page_load_metrics/observers/ukm_page_load_metrics_observer.h",
     "page_load_metrics/page_load_metrics_embedder_interface.h",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index e10a03f..7a3d00c 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -107,10 +107,10 @@
   "+third_party/WebKit/public/platform/modules/budget_service/budget_service.mojom.h",
   "+third_party/WebKit/public/platform/modules/installation/installation.mojom.h",
   "+third_party/WebKit/public/platform/modules/notifications/WebNotificationConstants.h",
+  "+third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h",
   "+third_party/WebKit/public/platform/modules/push_messaging/WebPushPermissionStatus.h",
   "+third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackAvailability.h",
   "+third_party/WebKit/public/platform/modules/screen_orientation/WebScreenOrientationLockType.h",
-  "+third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h",
   "+third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h",
   "+third_party/WebKit/public/platform/site_engagement.mojom.h",
   "+third_party/WebKit/public/public_features.h",
@@ -119,5 +119,5 @@
   "+third_party/WebKit/public/web/WebMediaPlayerAction.h",
   "+third_party/WebKit/public/web/WebPluginAction.h",
   "+third_party/WebKit/public/web/WebTextDirection.h",
-  "+third_party/WebKit/public/web/WebWindowFeatures.h",
+  "+third_party/WebKit/public/web/window_features.mojom.h",
 ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 52fa4ee..855e4aeb 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -71,6 +71,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
 #include "content/public/common/features.h"
+#include "device/base/features.h"
 #include "extensions/features/features.h"
 #include "gin/public/gin_features.h"
 #include "gpu/config/gpu_switches.h"
@@ -670,6 +671,17 @@
      nullptr}};
 #endif  // OS_ANDROID
 
+const FeatureEntry::FeatureParam
+    kAutofillCreditCardLastUsedDateFeatureVariationExpDate[] = {
+        {"show_expiration_date", "true"}};
+
+const FeatureEntry::FeatureVariation
+    kAutofillCreditCardLastUsedDateFeatureVariations[] = {
+        {"Display expiration date",
+         kAutofillCreditCardLastUsedDateFeatureVariationExpDate,
+         arraysize(kAutofillCreditCardLastUsedDateFeatureVariationExpDate),
+         nullptr}};
+
 // RECORDING USER METRICS FOR FLAGS:
 // -----------------------------------------------------------------------------
 // The first line of the entry is the internal name.
@@ -1882,6 +1894,9 @@
     {"ntp-condensed-layout", IDS_FLAGS_NTP_CONDENSED_LAYOUT_NAME,
      IDS_FLAGS_NTP_CONDENSED_LAYOUT_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kNTPCondensedLayoutFeature)},
+    {"ntp-google-g-in-omnibox", IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_NAME,
+     IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::NTPShowGoogleGInOmniboxFeature)},
 #endif  // OS_ANDROID
 #if BUILDFLAG(ENABLE_WEBRTC) && BUILDFLAG(RTC_USE_H264) && \
     !defined(MEDIA_DISABLE_FFMPEG)
@@ -2155,7 +2170,13 @@
      IDS_NATIVE_ANDROID_HISTORY_MANAGER_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(features::kNativeAndroidHistoryManager)},
 #endif  // OS_ANDROID
-
+    {"enable-autofill-credit-card-last-used-date-display",
+     IDS_FLAGS_ENABLE_AUTOFILL_CREDIT_CARD_LAST_USED_DATE_DISPLAY,
+     IDS_FLAGS_ENABLE_AUTOFILL_CREDIT_CARD_LAST_USED_DATE_DISPLAY_DESCRIPTION,
+     kOsAll, FEATURE_WITH_VARIATIONS_VALUE_TYPE(
+                 autofill::kAutofillCreditCardLastUsedDateDisplay,
+                 kAutofillCreditCardLastUsedDateFeatureVariations,
+                 "AutofillCreditCardLastUsedDate")},
 #if defined(OS_WIN)
     {"windows10-custom-titlebar", IDS_FLAGS_WINDOWS10_CUSTOM_TITLEBAR_NAME,
      IDS_FLAGS_WINDOWS10_CUSTOM_TITLEBAR_DESCRIPTION, kOsWin,
@@ -2207,7 +2228,21 @@
     {"enable-midi-manager-dynamic-instantiation",
      IDS_FLAGS_ENABLE_MIDI_MANAGER_DYNAMIC_INSTANTIATION_NAME,
      IDS_FLAGS_ENABLE_MIDI_MANAGER_DYNAMIC_INSTANTIATION_DESCRIPTION, kOsAll,
-     FEATURE_VALUE_TYPE(midi::features::kMidiManagerDynamicInstantiation)}
+     FEATURE_VALUE_TYPE(midi::features::kMidiManagerDynamicInstantiation)},
+
+#if defined(OS_WIN)
+    {"new-usb-backend", IDS_FLAGS_NEW_USB_BACKEND_NAME,
+     IDS_FLAGS_NEW_USB_BACKEND_DESCRIPTION, kOsWin,
+     FEATURE_VALUE_TYPE(device::kNewUsbBackend)},
+#endif  // defined(OS_WIN)
+
+#if defined(OS_CHROMEOS)
+    {"enable-touch-support-for-screen-magnifier",
+     IDS_FLAGS_ENABLE_TOUCH_SUPPORT_FOR_SCREEN_MAGNIFIER_NAME,
+     IDS_FLAGS_ENABLE_TOUCH_SUPPORT_FOR_SCREEN_MAGNIFIER_DESCRIPTION, kOsCrOS,
+     SINGLE_VALUE_TYPE(
+         chromeos::switches::kEnableTouchSupportForScreenMagnifier)},
+#endif  // OS_CHROMEOS
 
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
index fdd258f..b2a9533 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -9,6 +9,7 @@
 #include "base/guid.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
+#include "base/timer/elapsed_timer.h"
 #include "chrome/browser/android/shortcut_helper.h"
 #include "chrome/browser/android/shortcut_info.h"
 #include "chrome/browser/android/tab_android.h"
@@ -326,6 +327,7 @@
 
   // If the WebAPK is not installed and the "Add to Home Screen" button is
   // clicked, install the WebAPK.
+  timer_.reset(new base::ElapsedTimer());
   install_state_ = INSTALLING;
   webapk::TrackInstallSource(webapk_install_source_);
 
@@ -390,6 +392,8 @@
   }
 
   UpdateStateForInstalledWebAPK(webapk_package_name);
+  webapk::TrackInstallDuration(timer_->Elapsed());
+  timer_.reset();
   webapk::TrackInstallEvent(webapk::INSTALL_COMPLETED);
 }
 
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
index a83b9c8..02a8d07 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
@@ -16,6 +16,10 @@
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "ui/gfx/image/image.h"
 
+namespace base {
+class ElapsedTimer;
+}
+
 namespace content {
 class WebContents;
 }
@@ -156,6 +160,9 @@
   // Indicates the current state of a WebAPK installation.
   InstallState install_state_;
 
+  // Tracks how long it takes to install a WebAPK.
+  std::unique_ptr<base::ElapsedTimer> timer_;
+
   // Indicates the way in which a WebAPK (if applicable) is installed: from the
   // menu or from an app banner.
   webapk::InstallSource webapk_install_source_;
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index efee6c6..1fb36b28 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -57,6 +57,7 @@
     &kNTPCondensedLayoutFeature,
     &kNTPFakeOmniboxTextFeature,
     &kNTPOfflinePagesFeature,
+    &NTPShowGoogleGInOmniboxFeature,
     &kNTPSuggestionsStandaloneUIFeature,
     &kPhysicalWebFeature,
     &kSpecialLocaleFeature,
@@ -139,6 +140,9 @@
 const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature NTPShowGoogleGInOmniboxFeature{
+    "NTPShowGoogleGInOmnibox", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kNTPSuggestionsStandaloneUIFeature{
     "NTPSuggestionsStandaloneUI", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 6a53a0d..9e7ec98b 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -29,6 +29,7 @@
 extern const base::Feature kNTPCondensedLayoutFeature;
 extern const base::Feature kNTPFakeOmniboxTextFeature;
 extern const base::Feature kNTPOfflinePagesFeature;
+extern const base::Feature NTPShowGoogleGInOmniboxFeature;
 extern const base::Feature kNTPSuggestionsStandaloneUIFeature;
 extern const base::Feature kPhysicalWebFeature;
 extern const base::Feature kSpecialLocaleFeature;
diff --git a/chrome/browser/android/offline_pages/background_loader_offliner.cc b/chrome/browser/android/offline_pages/background_loader_offliner.cc
index 89d11b6..732a4eca 100644
--- a/chrome/browser/android/offline_pages/background_loader_offliner.cc
+++ b/chrome/browser/android/offline_pages/background_loader_offliner.cc
@@ -13,6 +13,7 @@
 #include "components/offline_pages/core/client_namespace_constants.h"
 #include "components/offline_pages/core/offline_page_model.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 
 namespace offline_pages {
@@ -25,6 +26,7 @@
       offline_page_model_(offline_page_model),
       is_low_end_device_(base::SysInfo::IsLowEndDevice()),
       save_state_(NONE),
+      page_load_state_(SUCCESS),
       weak_ptr_factory_(this) {
   DCHECK(offline_page_model_);
   DCHECK(browser_context_);
@@ -127,8 +129,19 @@
     return;
   }
 
-  save_state_ = SAVING;
   SavePageRequest request(*pending_request_.get());
+  // If there was an error navigating to page, return loading failed.
+  if (page_load_state_ != SUCCESS) {
+    Offliner::RequestStatus status =
+        (page_load_state_ == RETRIABLE)
+            ? Offliner::RequestStatus::LOADING_FAILED
+            : Offliner::RequestStatus::LOADING_FAILED_NO_RETRY;
+    completion_callback_.Run(request, status);
+    ResetState();
+    return;
+  }
+
+  save_state_ = SAVING;
   content::WebContents* web_contents(
       content::WebContentsObserver::web_contents());
 
@@ -169,12 +182,50 @@
 void BackgroundLoaderOffliner::WebContentsDestroyed() {
   if (pending_request_) {
     SavePageRequest request(*pending_request_.get());
-    completion_callback_.Run(*pending_request_.get(),
-                             Offliner::RequestStatus::LOADING_FAILED);
+    completion_callback_.Run(request, Offliner::RequestStatus::LOADING_FAILED);
     ResetState();
   }
 }
 
+void BackgroundLoaderOffliner::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  // If there was an error of any kind (certificate, client, DNS, etc),
+  // Mark as error page. Resetting here causes RecordNavigationMetrics to crash.
+  if (navigation_handle->IsErrorPage()) {
+    // TODO(chili): we need to UMA this.
+    switch (navigation_handle->GetNetErrorCode()) {
+      case net::ERR_ACCESS_DENIED:
+      case net::ERR_ADDRESS_INVALID:
+      case net::ERR_ADDRESS_UNREACHABLE:
+      case net::ERR_CERT_COMMON_NAME_INVALID:
+      case net::ERR_CERT_AUTHORITY_INVALID:
+      case net::ERR_CERT_CONTAINS_ERRORS:
+      case net::ERR_CERT_INVALID:
+      case net::ERR_CONNECTION_FAILED:
+      case net::ERR_DISALLOWED_URL_SCHEME:
+      case net::ERR_DNS_SERVER_FAILED:
+      case net::ERR_FILE_NOT_FOUND:
+      case net::ERR_FILE_PATH_TOO_LONG:
+      case net::ERR_FILE_TOO_BIG:
+      case net::ERR_FILE_VIRUS_INFECTED:
+      case net::ERR_INVALID_HANDLE:
+      case net::ERR_INVALID_RESPONSE:
+      case net::ERR_INVALID_URL:
+      case net::ERR_MSG_TOO_BIG:
+      case net::ERR_NAME_NOT_RESOLVED:
+      case net::ERR_NAME_RESOLUTION_FAILED:
+      case net::ERR_SSL_PROTOCOL_ERROR:
+      case net::ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
+      case net::ERR_SSL_SERVER_CERT_BAD_FORMAT:
+      case net::ERR_UNKNOWN_URL_SCHEME:
+        page_load_state_ = NONRETRIABLE;
+        break;
+      default:
+        page_load_state_ = RETRIABLE;
+    }
+  }
+}
+
 void BackgroundLoaderOffliner::OnPageSaved(SavePageResult save_result,
                                            int64_t offline_id) {
   if (!pending_request_)
@@ -201,6 +252,7 @@
 
 void BackgroundLoaderOffliner::ResetState() {
   pending_request_.reset();
+  page_load_state_ = SUCCESS;
   // TODO(chili): Remove after RequestCoordinator can handle multiple offliners.
   // We reset the loader and observer after completion so loaders
   // will not be re-used across different requests/tries. This is a temporary
diff --git a/chrome/browser/android/offline_pages/background_loader_offliner.h b/chrome/browser/android/offline_pages/background_loader_offliner.h
index 0240e14..f9c9002c 100644
--- a/chrome/browser/android/offline_pages/background_loader_offliner.h
+++ b/chrome/browser/android/offline_pages/background_loader_offliner.h
@@ -43,6 +43,8 @@
   void DidStopLoading() override;
   void RenderProcessGone(base::TerminationStatus status) override;
   void WebContentsDestroyed() override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
 
  protected:
   // Called to reset internal loader and observer state.
@@ -52,6 +54,7 @@
   friend class TestBackgroundLoaderOffliner;
 
   enum SaveState { NONE, SAVING, DELETE_AFTER_SAVE };
+  enum PageLoadState { SUCCESS, RETRIABLE, NONRETRIABLE };
 
   // Called when the page has been saved.
   void OnPageSaved(SavePageResult save_result, int64_t offline_id);
@@ -75,6 +78,8 @@
   bool is_low_end_device_;
   // Save state.
   SaveState save_state_;
+  // Page load state.
+  PageLoadState page_load_state_;
 
   base::WeakPtrFactory<BackgroundLoaderOffliner> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(BackgroundLoaderOffliner);
diff --git a/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc b/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc
index 42369d36..b526e21 100644
--- a/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc
+++ b/chrome/browser/android/offline_pages/background_loader_offliner_unittest.cc
@@ -18,8 +18,11 @@
 #include "components/offline_pages/core/background/save_page_request.h"
 #include "components/offline_pages/core/stub_offline_page_model.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/web_contents_tester.h"
+#include "net/base/net_errors.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace offline_pages {
@@ -87,10 +90,12 @@
       const OfflinerPolicy* policy,
       OfflinePageModel* offline_page_model);
   ~TestBackgroundLoaderOffliner() override;
-  content::WebContentsTester* web_contents() {
+  content::WebContentsTester* web_contents_tester() {
     return content::WebContentsTester::For(stub_->web_contents());
   }
 
+  content::WebContents* web_contents() { return stub_->web_contents(); }
+
   bool is_loading() { return stub_->is_loading(); }
 
  protected:
@@ -137,7 +142,7 @@
   void CompleteLoading() {
     // For some reason, setting loading to True will call DidStopLoading
     // on the observers.
-    offliner()->web_contents()->TestSetIsLoading(true);
+    offliner()->web_contents_tester()->TestSetIsLoading(true);
   }
 
  private:
@@ -340,4 +345,27 @@
   EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED, request_status());
 }
 
+TEST_F(BackgroundLoaderOfflinerTest, FailsOnErrorPage) {
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time,
+                          kUserRequested);
+  EXPECT_TRUE(offliner()->LoadAndSave(request, callback()));
+
+  // Create handle with net error code.
+  // Called after calling LoadAndSave so we have web_contents to work with.
+  std::unique_ptr<content::NavigationHandle> handle(
+      content::NavigationHandle::CreateNavigationHandleForTesting(
+          kHttpUrl, offliner()->web_contents()->GetMainFrame(), true,
+          net::Error::ERR_NAME_NOT_RESOLVED));
+  // Call DidFinishNavigation with handle that contains error.
+  offliner()->DidFinishNavigation(handle.get());
+  // NavigationHandle is always destroyed after finishing navigation.
+  handle.reset();
+  offliner()->DidStopLoading();
+  PumpLoop();
+
+  EXPECT_TRUE(completion_callback_called());
+  EXPECT_EQ(Offliner::RequestStatus::LOADING_FAILED_NO_RETRY, request_status());
+}
+
 }  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/evaluation/evaluation_test_scheduler.cc b/chrome/browser/android/offline_pages/evaluation/evaluation_test_scheduler.cc
index 142b2e1..8393d4b 100644
--- a/chrome/browser/android/offline_pages/evaluation/evaluation_test_scheduler.cc
+++ b/chrome/browser/android/offline_pages/evaluation/evaluation_test_scheduler.cc
@@ -62,7 +62,8 @@
 }  // namespace
 
 EvaluationTestScheduler::EvaluationTestScheduler()
-    : device_conditions_(kPowerRequired,
+    : coordinator_(nullptr),
+      device_conditions_(kPowerRequired,
                          kBatteryPercentageHigh,
                          net::NetworkChangeNotifier::CONNECTION_2G) {}
 
@@ -70,8 +71,8 @@
 
 void EvaluationTestScheduler::Schedule(
     const TriggerConditions& trigger_conditions) {
-  Profile* profile = ProfileManager::GetLastUsedProfile();
   if (!coordinator_) {
+    Profile* profile = ProfileManager::GetLastUsedProfile();
     coordinator_ =
         RequestCoordinatorFactory::GetInstance()->GetForBrowserContext(profile);
     // It's not expected that the coordinator would be nullptr since this bridge
@@ -89,15 +90,17 @@
     long delay_in_seconds) {
   // This method is not expected to be called in test harness. Adding a log in
   // case we somehow get called here and need to implement the method.
-  coordinator_->GetLogger()->RecordActivity(std::string(kLogTag) +
-                                            " BackupSchedule called!");
+  if (coordinator_)
+    coordinator_->GetLogger()->RecordActivity(std::string(kLogTag) +
+                                              " BackupSchedule called!");
 }
 
 void EvaluationTestScheduler::Unschedule() {
   // This method is not expected to be called in test harness. Adding a log in
   // case we somehow get called here and need to implement the method.
-  coordinator_->GetLogger()->RecordActivity(std::string(kLogTag) +
-                                            " Unschedule called!");
+  if (coordinator_)
+    coordinator_->GetLogger()->RecordActivity(std::string(kLogTag) +
+                                              " Unschedule called!");
 }
 
 DeviceConditions& EvaluationTestScheduler::GetCurrentDeviceConditions() {
diff --git a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc
index b2074cf..992702b6 100644
--- a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc
+++ b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc
@@ -204,12 +204,11 @@
   return RegisterNativesImpl(env);
 }
 
-static ScopedJavaLocalRef<jobject> GetBridgeForProfile(
-    JNIEnv* env,
-    const JavaParamRef<jclass>& jcaller,
-    const JavaParamRef<jobject>& j_profile,
-    const jboolean j_use_evaluation_scheduler,
-    const jboolean j_use_background_loader) {
+static jlong CreateBridgeForProfile(JNIEnv* env,
+                                    const JavaParamRef<jobject>& obj,
+                                    const JavaParamRef<jobject>& j_profile,
+                                    const jboolean j_use_evaluation_scheduler,
+                                    const jboolean j_use_background_loader) {
   Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
 
   OfflinePageModel* offline_page_model =
@@ -220,25 +219,26 @@
       static_cast<bool>(j_use_background_loader));
 
   if (offline_page_model == nullptr || request_coordinator == nullptr)
-    return ScopedJavaLocalRef<jobject>();
+    return 0;
 
   OfflinePageEvaluationBridge* bridge = new OfflinePageEvaluationBridge(
-      env, profile, offline_page_model, request_coordinator);
+      env, obj, profile, offline_page_model, request_coordinator);
 
-  return ScopedJavaLocalRef<jobject>(bridge->java_ref());
+  return reinterpret_cast<jlong>(bridge);
 }
 
 OfflinePageEvaluationBridge::OfflinePageEvaluationBridge(
     JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
     content::BrowserContext* browser_context,
     OfflinePageModel* offline_page_model,
     RequestCoordinator* request_coordinator)
-    : browser_context_(browser_context),
+    : weak_java_ref_(env, obj),
+      browser_context_(browser_context),
       offline_page_model_(offline_page_model),
       request_coordinator_(request_coordinator) {
-  java_ref_.Reset(Java_OfflinePageEvaluationBridge_create(
-      env, reinterpret_cast<jlong>(this)));
-
+  DCHECK(offline_page_model_);
+  DCHECK(request_coordinator_);
   NotifyIfDoneLoading();
   offline_page_model_->AddObserver(this);
   request_coordinator_->AddObserver(this);
@@ -246,10 +246,13 @@
   request_coordinator_->GetLogger()->SetClient(this);
 }
 
-OfflinePageEvaluationBridge::~OfflinePageEvaluationBridge() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_OfflinePageEvaluationBridge_offlinePageEvaluationBridgeDestroyed(
-      env, java_ref_);
+OfflinePageEvaluationBridge::~OfflinePageEvaluationBridge() {}
+
+void OfflinePageEvaluationBridge::Destory(JNIEnv* env,
+                                          const JavaParamRef<jobject>&) {
+  offline_page_model_->RemoveObserver(this);
+  request_coordinator_->RemoveObserver(this);
+  delete this;
 }
 
 // Implement OfflinePageModel::Observer
@@ -270,28 +273,39 @@
 // Implement RequestCoordinator::Observer
 void OfflinePageEvaluationBridge::OnAdded(const SavePageRequest& request) {
   JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
+  if (obj.is_null())
+    return;
   Java_OfflinePageEvaluationBridge_savePageRequestAdded(
-      env, java_ref_, ToJavaSavePageRequest(env, request));
+      env, obj, ToJavaSavePageRequest(env, request));
 }
 
 void OfflinePageEvaluationBridge::OnCompleted(
     const SavePageRequest& request,
     RequestNotifier::BackgroundSavePageResult status) {
   JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
+  if (obj.is_null())
+    return;
   Java_OfflinePageEvaluationBridge_savePageRequestCompleted(
-      env, java_ref_, ToJavaSavePageRequest(env, request),
-      static_cast<int>(status));
+      env, obj, ToJavaSavePageRequest(env, request), static_cast<int>(status));
 }
 
 void OfflinePageEvaluationBridge::OnChanged(const SavePageRequest& request) {
   JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
+  if (obj.is_null())
+    return;
   Java_OfflinePageEvaluationBridge_savePageRequestChanged(
-      env, java_ref_, ToJavaSavePageRequest(env, request));
+      env, obj, ToJavaSavePageRequest(env, request));
 }
 
 void OfflinePageEvaluationBridge::CustomLog(const std::string& message) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  Java_OfflinePageEvaluationBridge_log(env, java_ref_,
+  ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
+  if (obj.is_null())
+    return;
+  Java_OfflinePageEvaluationBridge_log(env, obj,
                                        ConvertUTF8ToJavaString(env, kNativeTag),
                                        ConvertUTF8ToJavaString(env, message));
 }
@@ -365,7 +379,10 @@
   if (!offline_page_model_->is_loaded())
     return;
   JNIEnv* env = base::android::AttachCurrentThread();
-  Java_OfflinePageEvaluationBridge_offlinePageModelLoaded(env, java_ref_);
+  ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
+  if (obj.is_null())
+    return;
+  Java_OfflinePageEvaluationBridge_offlinePageModelLoaded(env, obj);
 }
 
 }  // namespace android
diff --git a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h
index ed92ee5..a15f2f09 100644
--- a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h
+++ b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.h
@@ -32,11 +32,13 @@
   static bool Register(JNIEnv* env);
 
   OfflinePageEvaluationBridge(JNIEnv* env,
+                              const base::android::JavaParamRef<jobject>& obj,
                               content::BrowserContext* browser_context,
                               OfflinePageModel* offline_page_model,
                               RequestCoordinator* request_coordinator);
 
   ~OfflinePageEvaluationBridge() override;
+  void Destory(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
   // OfflinePageModel::Observer implementation.
   void OfflinePageModelLoaded(OfflinePageModel* model) override;
@@ -87,8 +89,6 @@
                      const base::android::JavaParamRef<jstring>& j_client_id,
                      jboolean user_requested);
 
-  base::android::ScopedJavaGlobalRef<jobject> java_ref() { return java_ref_; }
-
  private:
   void NotifyIfDoneLoading() const;
 
@@ -96,7 +96,7 @@
       JNIEnv* env,
       const ClientId& clientId) const;
 
-  base::android::ScopedJavaGlobalRef<jobject> java_ref_;
+  JavaObjectWeakGlobalRef weak_java_ref_;
   // Not owned.
   content::BrowserContext* browser_context_;
   // Not owned.
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index 9074acf..9823dbcd7f 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -42,7 +42,6 @@
 #include "content/public/common/file_chooser_params.h"
 #include "jni/TabWebContentsDelegateAndroid_jni.h"
 #include "ppapi/features/features.h"
-#include "third_party/WebKit/public/web/WebWindowFeatures.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
 
@@ -331,7 +330,7 @@
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisablePopupBlocking)) {
     if (popup_blocker_helper->MaybeBlockPopup(nav_params,
-                                              blink::WebWindowFeatures())) {
+                                              blink::mojom::WindowFeatures())) {
       return nullptr;
     }
   }
diff --git a/chrome/browser/android/vr_shell/DEPS b/chrome/browser/android/vr_shell/DEPS
index f150d6a..3220215c 100644
--- a/chrome/browser/android/vr_shell/DEPS
+++ b/chrome/browser/android/vr_shell/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
-  "+third_party/gvr-android-sdk/src",
+  "+cc/layers",
   "+device/vr",
+  "+third_party/gvr-android-sdk/src",
 ]
diff --git a/chrome/browser/android/vr_shell/ui_interface.cc b/chrome/browser/android/vr_shell/ui_interface.cc
index 2ba6626..a61d448bd 100644
--- a/chrome/browser/android/vr_shell/ui_interface.cc
+++ b/chrome/browser/android/vr_shell/ui_interface.cc
@@ -14,10 +14,9 @@
 
 namespace vr_shell {
 
-UiInterface::UiInterface(Mode initial_mode, bool fullscreen)
+UiInterface::UiInterface(Mode initial_mode)
     : omnibox_(base::MakeUnique<VrOmnibox>(this)) {
   SetMode(initial_mode);
-  SetFullscreen(fullscreen);
 }
 
 UiInterface::~UiInterface() {}
diff --git a/chrome/browser/android/vr_shell/ui_interface.h b/chrome/browser/android/vr_shell/ui_interface.h
index e8c8a79..4bf7498 100644
--- a/chrome/browser/android/vr_shell/ui_interface.h
+++ b/chrome/browser/android/vr_shell/ui_interface.h
@@ -31,7 +31,7 @@
     WEB_VR
   };
 
-  explicit UiInterface(Mode initial_mode, bool fullscreen);
+  explicit UiInterface(Mode initial_mode);
   virtual ~UiInterface();
 
   // Set HTML UI state or pass events.
diff --git a/chrome/browser/android/vr_shell/vr_compositor.cc b/chrome/browser/android/vr_shell/vr_compositor.cc
index f22271a..de60da7 100644
--- a/chrome/browser/android/vr_shell/vr_compositor.cc
+++ b/chrome/browser/android/vr_shell/vr_compositor.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/android/vr_shell/vr_compositor.h"
 
+#include <utility>
+
 #include "cc/layers/layer.h"
+#include "cc/layers/solid_color_layer.h"
 #include "content/public/browser/android/compositor.h"
 #include "content/public/browser/web_contents.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -20,8 +23,7 @@
 }
 
 VrCompositor::~VrCompositor() {
-  if (layer_)
-    RestoreLayer();
+  RestoreLayer();
 }
 
 void VrCompositor::UpdateLayerTreeHost() {}
@@ -29,8 +31,13 @@
 void VrCompositor::OnSwapBuffersCompleted(int pending_swap_buffers) {}
 
 void VrCompositor::SetLayer(content::WebContents* web_contents) {
-  if (layer_)
-    RestoreLayer();
+  RestoreLayer();
+  if (!web_contents) {
+    scoped_refptr<cc::SolidColorLayer> layer = cc::SolidColorLayer::Create();
+    layer->SetBackgroundColor(SK_ColorTRANSPARENT);
+    compositor_->SetRootLayer(std::move(layer));
+    return;
+  }
   ui::ViewAndroid* view_android = web_contents->GetNativeView();
 
   // When we pass the layer for the ContentViewCore to the compositor it may be
@@ -48,10 +55,13 @@
 }
 
 void VrCompositor::RestoreLayer() {
+  if (!layer_)
+    return;
   layer_->SetBackgroundColor(background_color_);
   if (layer_parent_) {
     layer_parent_->AddChild(layer_);
   }
+  layer_ = nullptr;
 }
 
 void VrCompositor::SurfaceDestroyed() {
@@ -63,7 +73,6 @@
 }
 
 void VrCompositor::SurfaceChanged(jobject surface) {
-  DCHECK(surface);
   compositor_->SetSurface(surface);
 }
 
diff --git a/chrome/browser/android/vr_shell/vr_shell.cc b/chrome/browser/android/vr_shell/vr_shell.cc
index 956c7b694..2e8fba0 100644
--- a/chrome/browser/android/vr_shell/vr_shell.cc
+++ b/chrome/browser/android/vr_shell/vr_shell.cc
@@ -56,7 +56,7 @@
 static const char kVrShellUIURL[] = "chrome://vr-shell-ui";
 
 void SetIsInVR(content::WebContents* contents, bool is_in_vr) {
-  if (contents->GetRenderWidgetHostView())
+  if (contents && contents->GetRenderWidgetHostView())
     contents->GetRenderWidgetHostView()->SetIsInVR(is_in_vr);
 }
 
@@ -64,7 +64,6 @@
 
 VrShell::VrShell(JNIEnv* env,
                  jobject obj,
-                 content::WebContents* main_contents,
                  ui::WindowAndroid* content_window,
                  content::WebContents* ui_contents,
                  ui::WindowAndroid* ui_window,
@@ -74,13 +73,12 @@
                  bool reprojected_rendering)
     : WebContentsObserver(ui_contents),
       vr_shell_enabled_(base::FeatureList::IsEnabled(features::kVrShell)),
-      main_contents_(main_contents),
+      content_window_(content_window),
       content_compositor_(
-          base::MakeUnique<VrCompositor>(content_window, false)),
+          base::MakeUnique<VrCompositor>(content_window_, false)),
       ui_contents_(ui_contents),
       ui_compositor_(base::MakeUnique<VrCompositor>(ui_window, true)),
       delegate_provider_(delegate),
-      metrics_helper_(base::MakeUnique<VrMetricsHelper>(main_contents_)),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       reprojected_rendering_(reprojected_rendering),
       gvr_api_(gvr_api),
@@ -89,10 +87,7 @@
   g_instance = this;
   j_vr_shell_.Reset(env, obj);
 
-  content_input_manager_ = base::MakeUnique<VrInputManager>(main_contents_);
   ui_input_manager_ = base::MakeUnique<VrInputManager>(ui_contents_);
-
-  content_compositor_->SetLayer(main_contents_);
   ui_compositor_->SetLayer(ui_contents_);
 
   gl_thread_ = base::MakeUnique<VrGLThread>(
@@ -103,15 +98,8 @@
   options.priority = base::ThreadPriority::DISPLAY;
   gl_thread_->StartWithOptions(options);
 
-  if (for_web_vr)
-    metrics_helper_->SetWebVREnabled(true);
   html_interface_ = base::MakeUnique<UiInterface>(
-      for_web_vr ? UiInterface::Mode::WEB_VR : UiInterface::Mode::STANDARD,
-      main_contents_->IsFullscreen());
-  vr_web_contents_observer_ = base::MakeUnique<VrWebContentsObserver>(
-      main_contents_, html_interface_.get(), this);
-
-  SetIsInVR(main_contents_, true);
+      for_web_vr ? UiInterface::Mode::WEB_VR : UiInterface::Mode::STANDARD);
 }
 
 void VrShell::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
@@ -120,16 +108,28 @@
 
 void VrShell::SwapContents(JNIEnv* env, const JavaParamRef<jobject>& obj,
                            const JavaParamRef<jobject>& web_contents) {
-  SetIsInVR(main_contents_, false);
   content::WebContents* contents =
       content::WebContents::FromJavaWebContents(web_contents);
+  if (contents == main_contents_)
+    return;
+
+  SetIsInVR(main_contents_, false);
+
   main_contents_ = contents;
-  content_input_manager_ = base::MakeUnique<VrInputManager>(main_contents_);
   content_compositor_->SetLayer(main_contents_);
+  SetIsInVR(main_contents_, true);
+  ContentFrameWasResized(false /* unused */);
+  SetUiState();
+
+  if (!main_contents_) {
+    content_input_manager_ = nullptr;
+    vr_web_contents_observer_ = nullptr;
+    metrics_helper_ = nullptr;
+    return;
+  }
+  content_input_manager_ = base::MakeUnique<VrInputManager>(main_contents_);
   vr_web_contents_observer_ = base::MakeUnique<VrWebContentsObserver>(
       main_contents_, html_interface_.get(), this);
-  SetIsInVR(main_contents_, true);
-
   // TODO(billorr): Make VrMetricsHelper tab-aware and able to track multiple
   // tabs. crbug.com/684661
   metrics_helper_ = base::MakeUnique<VrMetricsHelper>(main_contents_);
@@ -137,6 +137,19 @@
   metrics_helper_->SetWebVREnabled(webvr_mode_);
 }
 
+void VrShell::SetUiState() {
+  if (!main_contents_) {
+    // TODO(mthiesse): Properly handle native page URLs.
+    html_interface_->SetURL(GURL());
+    html_interface_->SetLoading(false);
+    html_interface_->SetFullscreen(false);
+  } else {
+    html_interface_->SetURL(main_contents_->GetVisibleURL());
+    html_interface_->SetLoading(main_contents_->IsLoading());
+    html_interface_->SetFullscreen(main_contents_->IsFullscreen());
+  }
+}
+
 void VrShell::LoadUIContent(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   GURL url(kVrShellUIURL);
   ui_contents_->GetController().LoadURL(
@@ -204,7 +217,8 @@
       FROM_HERE, base::Bind(&VrShellGl::OnPause, gl_thread_->GetVrShellGl()));
 
   // exit vr session
-  metrics_helper_->SetVRActive(false);
+  if (metrics_helper_)
+    metrics_helper_->SetVRActive(false);
   SetIsInVR(main_contents_, false);
 }
 
@@ -212,7 +226,8 @@
   gl_thread_->task_runner()->PostTask(
       FROM_HERE, base::Bind(&VrShellGl::OnResume, gl_thread_->GetVrShellGl()));
 
-  metrics_helper_->SetVRActive(true);
+  if (metrics_helper_)
+    metrics_helper_->SetVRActive(true);
   SetIsInVR(main_contents_, true);
 }
 
@@ -237,8 +252,7 @@
 }
 
 void VrShell::OnDomContentsLoaded() {
-  html_interface_->SetURL(main_contents_->GetVisibleURL());
-  html_interface_->SetLoading(main_contents_->IsLoading());
+  SetUiState();
   html_interface_->OnDomContentsLoaded();
 }
 
@@ -246,7 +260,8 @@
                            const base::android::JavaParamRef<jobject>& obj,
                            bool enabled) {
   webvr_mode_ = enabled;
-  metrics_helper_->SetWebVREnabled(enabled);
+  if (metrics_helper_)
+    metrics_helper_->SetWebVREnabled(enabled);
   PostToGlThreadWhenReady(base::Bind(&VrShellGl::SetWebVrMode,
                                      gl_thread_->GetVrShellGl(), enabled));
   html_interface_->SetMode(
@@ -326,9 +341,30 @@
                                      callback, device_id));
 }
 
-void VrShell::SurfacesChanged(jobject content_surface, jobject ui_surface) {
-  content_compositor_->SurfaceChanged(content_surface);
-  ui_compositor_->SurfaceChanged(ui_surface);
+base::android::ScopedJavaGlobalRef<jobject> VrShell::TakeContentSurface(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  content_compositor_->SurfaceChanged(nullptr);
+  base::android::ScopedJavaGlobalRef<jobject> surface(env, content_surface_);
+  content_surface_ = nullptr;
+  return surface;
+}
+
+void VrShell::RestoreContentSurface(JNIEnv* env,
+                                    const JavaParamRef<jobject>& obj) {
+  PostToGlThreadWhenReady(
+      base::Bind(&VrShellGl::CreateContentSurface, gl_thread_->GetVrShellGl()));
+}
+
+void VrShell::UiSurfaceChanged(jobject surface) {
+  ui_compositor_->SurfaceChanged(surface);
+}
+
+void VrShell::ContentSurfaceChanged(jobject surface) {
+  content_surface_ = surface;
+  content_compositor_->SurfaceChanged(surface);
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_VrShellImpl_contentSurfaceChanged(env, j_vr_shell_.obj());
 }
 
 void VrShell::GvrDelegateReady() {
@@ -372,6 +408,22 @@
 
 void VrShell::DoUiAction(const UiAction action,
                          const base::DictionaryValue* arguments) {
+  switch (action) {
+    case OMNIBOX_CONTENT:
+      html_interface_->HandleOmniboxInput(*arguments);
+      return;
+    case SET_CONTENT_PAUSED: {
+      bool paused;
+      CHECK(arguments->GetBoolean("paused", &paused));
+      SetContentPaused(paused);
+      return;
+    }
+    default:
+      break;
+  }
+  // TODO(mthiesse): Handles these in java through the Tab.
+  if (!main_contents_)
+    return;
   content::NavigationController& controller = main_contents_->GetController();
   switch (action) {
     case HISTORY_BACK:
@@ -399,20 +451,11 @@
                          std::string(""));
       break;
     }
-    case OMNIBOX_CONTENT:
-      html_interface_->HandleOmniboxInput(*arguments);
-      break;
-    case SET_CONTENT_PAUSED: {
-      bool paused;
-      CHECK(arguments->GetBoolean("paused", &paused));
-      SetContentPaused(paused);
-      break;
-    }
 #if defined(ENABLE_VR_SHELL_UI_DEV)
     case RELOAD_UI:
       ui_contents_->GetController().Reload(content::ReloadType::NORMAL, false);
-      html_interface_.reset(new UiInterface(UiInterface::Mode::STANDARD,
-                                            main_contents_->IsFullscreen()));
+      html_interface_.reset(new UiInterface(UiInterface::Mode::STANDARD));
+      SetUiState();
       vr_web_contents_observer_->SetUiInterface(html_interface_.get());
       break;
 #endif
@@ -438,8 +481,8 @@
 }
 
 void VrShell::ContentFrameWasResized(bool width_changed) {
-  display::Display display = display::Screen::GetScreen()
-      ->GetDisplayNearestWindow(main_contents_->GetNativeView());
+  display::Display display =
+      display::Screen::GetScreen()->GetDisplayNearestWindow(content_window_);
   PostToGlThreadWhenReady(
       base::Bind(&VrShellGl::ContentBoundsChanged, gl_thread_->GetVrShellGl(),
                  display.size().width(), display.size().height()));
@@ -465,7 +508,8 @@
 }
 
 void VrShell::ContentWasShown() {
-  content_input_manager_ = base::MakeUnique<VrInputManager>(main_contents_);
+  if (main_contents_)
+    content_input_manager_ = base::MakeUnique<VrInputManager>(main_contents_);
 }
 
 void VrShell::ForceExitVr() {
@@ -596,19 +640,20 @@
 // Native JNI methods
 // ----------------------------------------------------------------------------
 
-jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj,
-           const JavaParamRef<jobject>& content_web_contents,
-           jlong content_window_android,
+jlong Init(JNIEnv* env,
+           const JavaParamRef<jobject>& obj,
            const JavaParamRef<jobject>& ui_web_contents,
-           jlong ui_window_android, jboolean for_web_vr,
+           jlong content_window_android,
+           jlong ui_window_android,
+           jboolean for_web_vr,
            const base::android::JavaParamRef<jobject>& delegate,
-           jlong gvr_api, jboolean reprojected_rendering) {
+           jlong gvr_api,
+           jboolean reprojected_rendering) {
   return reinterpret_cast<intptr_t>(new VrShell(
-      env, obj, content::WebContents::FromJavaWebContents(content_web_contents),
-      reinterpret_cast<ui::WindowAndroid*>(content_window_android),
+      env, obj, reinterpret_cast<ui::WindowAndroid*>(content_window_android),
       content::WebContents::FromJavaWebContents(ui_web_contents),
-      reinterpret_cast<ui::WindowAndroid*>(ui_window_android),
-      for_web_vr, VrShellDelegate::GetNativeVrShellDelegate(env, delegate),
+      reinterpret_cast<ui::WindowAndroid*>(ui_window_android), for_web_vr,
+      VrShellDelegate::GetNativeVrShellDelegate(env, delegate),
       reinterpret_cast<gvr_context*>(gvr_api), reprojected_rendering));
 }
 
diff --git a/chrome/browser/android/vr_shell/vr_shell.h b/chrome/browser/android/vr_shell/vr_shell.h
index f60efc7..cc09af9 100644
--- a/chrome/browser/android/vr_shell/vr_shell.h
+++ b/chrome/browser/android/vr_shell/vr_shell.h
@@ -65,7 +65,6 @@
 class VrShell : public device::GvrDelegate, content::WebContentsObserver {
  public:
   VrShell(JNIEnv* env, jobject obj,
-          content::WebContents* main_contents,
           ui::WindowAndroid* content_window,
           content::WebContents* ui_contents,
           ui::WindowAndroid* ui_window,
@@ -103,6 +102,11 @@
   void OnTabRemoved(JNIEnv* env,
                     const base::android::JavaParamRef<jobject>& obj,
                     jboolean incognito, jint id);
+  base::android::ScopedJavaGlobalRef<jobject> TakeContentSurface(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  void RestoreContentSurface(JNIEnv* env,
+                             const base::android::JavaParamRef<jobject>& obj);
 
   void ContentWebContentsDestroyed();
   // Called when our WebContents have been hidden. Usually a sign that something
@@ -117,7 +121,8 @@
   UiInterface* GetUiInterface();
   void OnDomContentsLoaded();
 
-  void SurfacesChanged(jobject content_surface, jobject ui_surface);
+  void UiSurfaceChanged(jobject surface);
+  void ContentSurfaceChanged(jobject surface);
   void GvrDelegateReady();
   void AppButtonPressed();
 
@@ -158,6 +163,7 @@
   ~VrShell() override;
   void PostToGlThreadWhenReady(const base::Closure& task);
   void SetContentPaused(bool paused);
+  void SetUiState();
 
   // content::WebContentsObserver implementation.
   void RenderViewHostChanged(content::RenderViewHost* old_host,
@@ -189,7 +195,8 @@
   bool content_paused_ = false;
   bool webvr_mode_ = false;
 
-  content::WebContents* main_contents_;
+  content::WebContents* main_contents_ = nullptr;
+  ui::WindowAndroid* content_window_;
   std::unique_ptr<VrCompositor> content_compositor_;
   content::WebContents* ui_contents_;
   std::unique_ptr<VrCompositor> ui_compositor_;
@@ -207,6 +214,8 @@
   std::unique_ptr<VrGLThread> gl_thread_;
   bool reprojected_rendering_;
 
+  jobject content_surface_ = nullptr;
+
   // TODO(mthiesse): Remove the need for this to be stored here.
   // crbug.com/674594
   gvr_context* gvr_api_;
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index 4564af01..ebad9609 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -242,24 +242,16 @@
   content_texture_id_ = textures[1];
   ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_);
   content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_);
-  ui_surface_.reset(new gl::ScopedJavaSurface(ui_surface_texture_.get()));
-  content_surface_.reset(new gl::ScopedJavaSurface(
-      content_surface_texture_.get()));
+  CreateUiSurface();
+  CreateContentSurface();
   ui_surface_texture_->SetFrameAvailableCallback(base::Bind(
-        &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr()));
+      &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr()));
   content_surface_texture_->SetFrameAvailableCallback(base::Bind(
         &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr()));
-
   content_surface_texture_->SetDefaultBufferSize(
       content_tex_physical_size_.width, content_tex_physical_size_.height);
   ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width,
                                             ui_tex_physical_size_.height);
-
-  main_thread_task_runner_->PostTask(FROM_HERE, base::Bind(
-      &VrShell::SurfacesChanged, weak_vr_shell_,
-      content_surface_->j_surface().obj(),
-      ui_surface_->j_surface().obj()));
-
   InitializeRenderer();
 
   vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this)));
@@ -268,6 +260,22 @@
   ready_to_draw_ = true;
 }
 
+void VrShellGl::CreateContentSurface() {
+  content_surface_ =
+      base::MakeUnique<gl::ScopedJavaSurface>(content_surface_texture_.get());
+  main_thread_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&VrShell::ContentSurfaceChanged, weak_vr_shell_,
+                            content_surface_->j_surface().obj()));
+}
+
+void VrShellGl::CreateUiSurface() {
+  ui_surface_ =
+      base::MakeUnique<gl::ScopedJavaSurface>(ui_surface_texture_.get());
+  main_thread_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&VrShell::UiSurfaceChanged, weak_vr_shell_,
+                            ui_surface_->j_surface().obj()));
+}
+
 void VrShellGl::OnUIFrameAvailable() {
   ui_surface_texture_->UpdateTexImage();
 }
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.h b/chrome/browser/android/vr_shell/vr_shell_gl.h
index 6ce20e70..2e76672 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.h
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.h
@@ -73,6 +73,7 @@
   void OnResume();
 
   void SetWebVrMode(bool enabled);
+  void CreateContentSurface();
   void ContentBoundsChanged(int width, int height);
   void ContentPhysicalBoundsChanged(int width, int height);
   void UIBoundsChanged(int width, int height);
@@ -114,7 +115,7 @@
                           int pixel_y);
   void SendGesture(InputTarget input_target,
                    std::unique_ptr<blink::WebInputEvent> event);
-
+  void CreateUiSurface();
   void OnUIFrameAvailable();
   void OnContentFrameAvailable();
   bool GetPixelEncodedFrameIndex(uint16_t* frame_index);
diff --git a/chrome/browser/android/webapk/webapk_installer.cc b/chrome/browser/android/webapk/webapk_installer.cc
index 2d17c84..059d85f 100644
--- a/chrome/browser/android/webapk/webapk_installer.cc
+++ b/chrome/browser/android/webapk/webapk_installer.cc
@@ -402,6 +402,8 @@
 
   if (!source->GetStatus().is_success() ||
       source->GetResponseCode() != net::HTTP_OK) {
+    LOG(WARNING) << base::StringPrintf(
+        "WebAPK server returned response code %d.", source->GetResponseCode());
     OnFailure();
     return;
   }
@@ -411,6 +413,7 @@
 
   std::unique_ptr<webapk::WebApkResponse> response(new webapk::WebApkResponse);
   if (!response->ParseFromString(response_string)) {
+    LOG(WARNING) << "WebAPK server did not return proto.";
     OnFailure();
     return;
   }
@@ -424,6 +427,7 @@
   }
 
   if (!signed_download_url.is_valid() || response->package_name().empty()) {
+    LOG(WARNING) << "WebAPK server returned incomplete proto.";
     OnFailure();
     return;
   }
diff --git a/chrome/browser/android/webapk/webapk_metrics.cc b/chrome/browser/android/webapk/webapk_metrics.cc
index 5abd6a7..7a9aff7 100644
--- a/chrome/browser/android/webapk/webapk_metrics.cc
+++ b/chrome/browser/android/webapk/webapk_metrics.cc
@@ -5,14 +5,20 @@
 #include "chrome/browser/android/webapk/webapk_metrics.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
 
 namespace webapk {
 
+const char kInstallDurationHistogram[] = "WebApk.Install.InstallDuration";
 const char kInstallEventHistogram[] = "WebApk.Install.InstallEvent";
 const char kInstallSourceHistogram[] = "WebApk.Install.InstallSource";
 const char kInfoBarShownHistogram[] = "WebApk.Install.InfoBarShown";
 const char kUserActionHistogram[] = "WebApk.Install.UserAction";
 
+void TrackInstallDuration(base::TimeDelta delta) {
+  UMA_HISTOGRAM_MEDIUM_TIMES(kInstallDurationHistogram, delta);
+}
+
 void TrackInstallEvent(InstallEvent event) {
   UMA_HISTOGRAM_ENUMERATION(kInstallEventHistogram, event, INSTALL_EVENT_MAX);
 }
diff --git a/chrome/browser/android/webapk/webapk_metrics.h b/chrome/browser/android/webapk/webapk_metrics.h
index 35e3279..d859c13 100644
--- a/chrome/browser/android/webapk/webapk_metrics.h
+++ b/chrome/browser/android/webapk/webapk_metrics.h
@@ -5,6 +5,10 @@
 #ifndef CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_METRICS_H_
 #define CHROME_BROWSER_ANDROID_WEBAPK_WEBAPK_METRICS_H_
 
+namespace base {
+class TimeDelta;
+}
+
 namespace webapk {
 
 // Keep these enums up to date with tools/metrics/histograms/histograms.xml.
@@ -52,6 +56,7 @@
   USER_ACTION_MAX,
 };
 
+void TrackInstallDuration(base::TimeDelta delta);
 void TrackInstallEvent(InstallEvent event);
 void TrackInstallSource(InstallSource event);
 void TrackInstallInfoBarShown(InfoBarShown event);
diff --git a/chrome/browser/autocomplete/OWNERS b/chrome/browser/autocomplete/OWNERS
index 7f8e95d..1077c58 100644
--- a/chrome/browser/autocomplete/OWNERS
+++ b/chrome/browser/autocomplete/OWNERS
@@ -1,3 +1,5 @@
 pkasting@chromium.org
 sky@chromium.org
 mpearson@chromium.org
+
+# COMPONENT: UI>Browser>Omnibox
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 88d393b..0d08173 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -291,8 +291,6 @@
             <include name="IDR_MD_HISTORY_APP_JS" file="resources\md_history\app.js" type="BINDATA" />
             <include name="IDR_MD_HISTORY_BROWSER_SERVICE_HTML" file="resources\md_history\browser_service.html" type="BINDATA" />
             <include name="IDR_MD_HISTORY_BROWSER_SERVICE_JS" file="resources\md_history\browser_service.js" type="BINDATA" />
-            <include name="IDR_MD_HISTORY_GROUPED_LIST_HTML" file="resources\md_history\grouped_list.html" type="BINDATA" />
-            <include name="IDR_MD_HISTORY_GROUPED_LIST_JS" file="resources\md_history\grouped_list.js" type="BINDATA" />
             <include name="IDR_MD_HISTORY_HISTORY_ITEM_HTML" file="resources\md_history\history_item.html" type="BINDATA" />
             <include name="IDR_MD_HISTORY_HISTORY_ITEM_JS" file="resources\md_history\history_item.js" type="BINDATA" />
             <include name="IDR_MD_HISTORY_HISTORY_LIST_BEHAVIOR_HTML" file="resources\md_history\history_list_behavior.html" type="BINDATA" />
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 0cbbdd0..8dfbb51f 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -472,19 +472,14 @@
 #endif  // defined(OS_MACOSX)
 
 void RegisterComponentsForUpdate() {
-  component_updater::ComponentUpdateService* cus =
-      g_browser_process->component_updater();
+  const auto cus = g_browser_process->component_updater();
 
-  // Registration can be before or after cus->Start() so it is ok to post
-  // a task to the UI thread to do registration once you done the necessary
-  // file IO to know you existing component version.
-#if !defined(OS_ANDROID)
-#if !defined(OS_CHROMEOS)
   if (base::FeatureList::IsEnabled(features::kImprovedRecoveryComponent))
     RegisterRecoveryImprovedComponent(cus, g_browser_process->local_state());
   else
     RegisterRecoveryComponent(cus, g_browser_process->local_state());
-#endif  // !defined(OS_CHROMEOS)
+
+#if !defined(OS_ANDROID)
   RegisterPepperFlashComponent(cus);
 #if !defined(OS_CHROMEOS)
   RegisterSwiftShaderComponent(cus);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index fa37b77..9b0b2bb 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -380,7 +380,6 @@
 #endif
 
 using base::FileDescriptor;
-using blink::WebWindowFeatures;
 using content::BrowserThread;
 using content::BrowserURLHandler;
 using content::BrowsingDataFilterBuilder;
@@ -2319,7 +2318,7 @@
     const content::Referrer& referrer,
     const std::string& frame_name,
     WindowOpenDisposition disposition,
-    const WebWindowFeatures& features,
+    const blink::mojom::WindowFeatures& features,
     bool user_gesture,
     bool opener_suppressed,
     content::ResourceContext* context,
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 303e6a2b..1859a673 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -27,6 +27,12 @@
 class CommandLine;
 }
 
+namespace blink {
+namespace mojom {
+class WindowFeatures;
+}
+}
+
 namespace content {
 class BrowserContext;
 class QuotaPermissionContext;
@@ -201,7 +207,7 @@
                        const content::Referrer& referrer,
                        const std::string& frame_name,
                        WindowOpenDisposition disposition,
-                       const blink::WebWindowFeatures& features,
+                       const blink::mojom::WindowFeatures& features,
                        bool user_gesture,
                        bool opener_suppressed,
                        content::ResourceContext* context,
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 18ad8c99..5c5f76d 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1191,10 +1191,10 @@
     "printing/ppd_provider_factory.cc",
     "printing/ppd_provider_factory.h",
     "printing/printer_discoverer.h",
-    "printing/printer_pref_manager.cc",
-    "printing/printer_pref_manager.h",
-    "printing/printer_pref_manager_factory.cc",
-    "printing/printer_pref_manager_factory.h",
+    "printing/printers_manager.cc",
+    "printing/printers_manager.h",
+    "printing/printers_manager_factory.cc",
+    "printing/printers_manager_factory.h",
     "printing/printers_sync_bridge.cc",
     "printing/printers_sync_bridge.h",
     "printing/specifics_translation.cc",
@@ -1654,7 +1654,7 @@
     "power/renderer_freezer_unittest.cc",
     "preferences_unittest.cc",
     "printer_detector/printer_detector_unittest.cc",
-    "printing/printer_pref_manager_unittest.cc",
+    "printing/printers_manager_unittest.cc",
     "printing/specifics_translation_unittest.cc",
     "profiles/profile_list_chromeos_unittest.cc",
     "proxy_config_service_impl_unittest.cc",
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index c79aced..c1245fb 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/devtools/devtools_window.h"
-#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
 #include "chrome/browser/extensions/devtools_util.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
@@ -50,6 +49,7 @@
 #include "components/zoom/page_zoom.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/page_zoom.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "google_apis/drive/auth_service.h"
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
index 99c1c8cc..96e20a5 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
@@ -14,12 +14,12 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
-#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
-#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
 #include "chrome/common/extensions/api/file_manager_private_internal.h"
 #include "content/public/browser/browser_thread.h"
+#include "extensions/browser/api/file_handlers/directory_util.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/entry_info.h"
 #include "net/base/filename_util.h"
 #include "storage/browser/fileapi/file_system_context.h"
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc
index e24a84e..fe086cd0 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/chromeos/file_manager/file_browser_handlers.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/file_manager/open_util.h"
-#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -36,6 +35,7 @@
 #include "components/mime_util/mime_util.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/entry_info.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/extension_registry.h"
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.h b/chrome/browser/chromeos/file_manager/file_tasks.h
index 0e4b9c0..74a270ed 100644
--- a/chrome/browser/chromeos/file_manager/file_tasks.h
+++ b/chrome/browser/chromeos/file_manager/file_tasks.h
@@ -117,8 +117,8 @@
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 #include "chrome/common/extensions/api/file_manager_private.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 #include "url/gurl.h"
 
 class PrefService;
diff --git a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
index fc88bfb4..37b98cf 100644
--- a/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/gallery_browsertest.cc
@@ -250,7 +250,8 @@
 }
 
 // http://crbug.com/508949
-#if defined(MEMORY_SANITIZER)
+// http://crbug.com/690983 (Chrome OS debug build)
+#if defined(MEMORY_SANITIZER) || (defined(OS_CHROMEOS) && !defined(NDEBUG))
 #define MAYBE_RotateImageOnDrive DISABLED_RotateImageOnDrive
 #else
 #define MAYBE_RotateImageOnDrive RotateImageOnDrive
diff --git a/chrome/browser/chromeos/file_manager/open_util.cc b/chrome/browser/chromeos/file_manager/open_util.cc
index 770a5aec..6ba5eeb 100644
--- a/chrome/browser/chromeos/file_manager/open_util.cc
+++ b/chrome/browser/chromeos/file_manager/open_util.cc
@@ -18,10 +18,11 @@
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/file_manager/path_util.h"
 #include "chrome/browser/chromeos/file_manager/url_util.h"
-#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
-#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
+#include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/user_metrics.h"
+#include "extensions/browser/api/file_handlers/directory_util.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 #include "extensions/browser/entry_info.h"
 #include "storage/browser/fileapi/file_system_backend.h"
 #include "storage/browser/fileapi/file_system_context.h"
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc b/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc
index b88192b..e6c515c 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc
+++ b/chrome/browser/chromeos/fileapi/external_file_url_request_job.cc
@@ -16,12 +16,12 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
 #include "chrome/browser/chromeos/fileapi/external_file_url_util.h"
-#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/drive/file_system_core_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/url_constants.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 #include "net/http/http_byte_range.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_info.h"
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
index 493781e..bfce397 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -279,26 +279,6 @@
   chromeos::AccessibilityManager::Get()->EnableSystemSounds(true);
 }
 
-// A login implementation of WidgetDelegate.
-class LoginWidgetDelegate : public views::WidgetDelegate {
- public:
-  explicit LoginWidgetDelegate(views::Widget* widget) : widget_(widget) {
-  }
-  ~LoginWidgetDelegate() override {}
-
-  // Overridden from WidgetDelegate:
-  void DeleteDelegate() override { delete this; }
-  views::Widget* GetWidget() override { return widget_; }
-  const views::Widget* GetWidget() const override { return widget_; }
-  bool CanActivate() const override { return true; }
-  bool ShouldAdvanceFocusToTopLevelWidget() const override { return true; }
-
- private:
-  views::Widget* widget_;
-
-  DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate);
-};
-
 // Disables virtual keyboard overscroll. Login UI will scroll user pods
 // into view on JS side when virtual keyboard is shown.
 void DisableKeyboardOverscroll() {
@@ -318,6 +298,39 @@
 // static
 const int LoginDisplayHostImpl::kShowLoginWebUIid = 0x1111;
 
+// A login implementation of WidgetDelegate.
+class LoginDisplayHostImpl::LoginWidgetDelegate : public views::WidgetDelegate {
+ public:
+  LoginWidgetDelegate(views::Widget* widget, LoginDisplayHostImpl* host)
+      : widget_(widget), login_display_host_(host) {
+    DCHECK(widget_);
+    DCHECK(login_display_host_);
+  }
+  ~LoginWidgetDelegate() override {}
+
+  // Overridden from WidgetDelegate:
+  void WindowClosing() override {
+    // Reset the cached Widget and View pointers. The Widget may close due to:
+    // * Login completion
+    // * Ash crash at the login screen on mustash
+    // In the latter case the mash root process will trigger a clean restart
+    // of content_browser.
+    if (chrome::IsRunningInMash())
+      login_display_host_->ResetLoginWindowAndView();
+  }
+  void DeleteDelegate() override { delete this; }
+  views::Widget* GetWidget() override { return widget_; }
+  const views::Widget* GetWidget() const override { return widget_; }
+  bool CanActivate() const override { return true; }
+  bool ShouldAdvanceFocusToTopLevelWidget() const override { return true; }
+
+ private:
+  views::Widget* widget_;
+  LoginDisplayHostImpl* login_display_host_;
+
+  DISALLOW_COPY_AND_ASSIGN(LoginWidgetDelegate);
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // LoginDisplayHostImpl, public
 
@@ -1206,7 +1219,7 @@
             ash::kShellWindowId_LockScreenContainer);
   }
   login_window_ = new views::Widget;
-  params.delegate = new LoginWidgetDelegate(login_window_);
+  params.delegate = new LoginWidgetDelegate(login_window_, this);
   login_window_->Init(params);
 
   login_view_ = new WebUILoginView(WebUILoginView::WebViewSettings());
@@ -1350,6 +1363,7 @@
           ? session_manager::SessionState::LOGIN_PRIMARY
           : session_manager::SessionState::OOBE);
 
+  // Manages its own lifetime. See ShutdownDisplayHost().
   LoginDisplayHostImpl* display_host = new LoginDisplayHostImpl(screen_bounds);
 
   bool show_app_launch_splash_screen =
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.h b/chrome/browser/chromeos/login/ui/login_display_host_impl.h
index 008ee91..5a16edd 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_impl.h
+++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.h
@@ -140,6 +140,8 @@
   void OnUserSwitchAnimationFinished() override;
 
  private:
+  class LoginWidgetDelegate;
+
   // Way to restore if renderer have crashed.
   enum RestorePath {
     RESTORE_UNKNOWN,
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
index 472e3b0..11bf9fd 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
@@ -627,7 +627,12 @@
   DISALLOW_COPY_AND_ASSIGN(TestObserver);
 };
 
-IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, DisplayChange) {
+#if defined(OS_CHROMEOS) && defined(USE_OZONE)
+#define MAYBE_DisplayChange DISABLED_DisplayChange
+#else
+#define MAYBE_DisplayChange DisplayChange
+#endif
+IN_PROC_BROWSER_TEST_F(WallpaperManagerBrowserTest, MAYBE_DisplayChange) {
   TestObserver observer(WallpaperManager::Get());
 
   // Set the wallpaper to ensure that UpdateWallpaper() will be called when the
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index fc8d785..ffdc6e4 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -901,6 +901,7 @@
   geolocation_provider_->RequestGeolocation(
       base::TimeDelta::FromSeconds(kResolveTimeZoneTimeoutSeconds),
       false /* send_wifi_geolocation_data */,
+      false /* send_cellular_geolocation_data */,
       base::Bind(&WizardController::OnLocationResolved,
                  weak_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
index 736b163..0539482 100644
--- a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
+++ b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
@@ -259,6 +259,7 @@
     DISABLED = 1;
     IP_ONLY = 2;
     SEND_WIFI_ACCESS_POINTS = 3;
+    SEND_ALL_LOCATION_INFO = 4;
   };
 
   optional AutomaticTimezoneDetectionType timezone_detection_type = 2;
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_factory.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_factory.cc
index 679efb37..6a8ce57 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_factory.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_factory.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/chromeos/printing/cups_print_job_manager_factory.h"
 
 #include "chrome/browser/chromeos/printing/cups_print_job_manager.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
@@ -39,7 +39,7 @@
     : BrowserContextKeyedServiceFactory(
           "CupsPrintJobManagerFactory",
           BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(chromeos::PrinterPrefManagerFactory::GetInstance());
+  DependsOn(chromeos::PrintersManagerFactory::GetInstance());
 }
 
 CupsPrintJobManagerFactory::~CupsPrintJobManagerFactory() {}
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
index e08a80c9..6651a36 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
@@ -17,8 +17,8 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/printing/cups_print_job.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/printing/print_job.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_context.h"
@@ -148,7 +148,7 @@
   }
 
   auto printer =
-      chromeos::PrinterPrefManagerFactory::GetForBrowserContext(profile_)
+      chromeos::PrintersManagerFactory::GetForBrowserContext(profile_)
           ->GetPrinter(printer_name);
   if (!printer) {
     LOG(WARNING) << "Printer was removed while job was in progress.  It cannot "
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
index 1cc58d9e..04f0cdb 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
@@ -14,7 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/printing/cups_print_job.h"
 #include "chrome/browser/chromeos/printing/cups_print_job_manager.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "printing/backend/cups_connection.h"
diff --git a/chrome/browser/chromeos/printing/printer_pref_manager_factory.h b/chrome/browser/chromeos/printing/printer_pref_manager_factory.h
deleted file mode 100644
index f10c2f8..0000000
--- a/chrome/browser/chromeos/printing/printer_pref_manager_factory.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_PREF_MANAGER_FACTORY_H_
-#define CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_PREF_MANAGER_FACTORY_H_
-
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-
-namespace content {
-class BrowserContext;
-}
-
-namespace chromeos {
-
-class PrinterPrefManagerFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static PrinterPrefManager* GetForBrowserContext(
-      content::BrowserContext* context);
-
-  static PrinterPrefManagerFactory* GetInstance();
-
- protected:
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-
- private:
-  friend struct base::DefaultLazyInstanceTraits<PrinterPrefManagerFactory>;
-
-  PrinterPrefManagerFactory();
-  ~PrinterPrefManagerFactory() override;
-
-  // BrowserContextKeyedServiceFactory implementation:
-  PrinterPrefManager* BuildServiceInstanceFor(
-      content::BrowserContext* browser_context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(PrinterPrefManagerFactory);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_PREF_MANAGER_FACTORY_H_
diff --git a/chrome/browser/chromeos/printing/printer_pref_manager.cc b/chrome/browser/chromeos/printing/printers_manager.cc
similarity index 86%
rename from chrome/browser/chromeos/printing/printer_pref_manager.cc
rename to chrome/browser/chromeos/printing/printers_manager.cc
index 748fe569..0cded68 100644
--- a/chrome/browser/chromeos/printing/printer_pref_manager.cc
+++ b/chrome/browser/chromeos/printing/printers_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
 
 #include <memory>
 #include <string>
@@ -51,29 +51,29 @@
 
 }  // anonymous namespace
 
-PrinterPrefManager::PrinterPrefManager(
+PrintersManager::PrintersManager(
     Profile* profile,
     std::unique_ptr<PrintersSyncBridge> sync_bridge)
     : profile_(profile), sync_bridge_(std::move(sync_bridge)) {
   pref_change_registrar_.Init(profile->GetPrefs());
   pref_change_registrar_.Add(
       prefs::kRecommendedNativePrinters,
-      base::Bind(&PrinterPrefManager::UpdateRecommendedPrinters,
+      base::Bind(&PrintersManager::UpdateRecommendedPrinters,
                  base::Unretained(this)));
   UpdateRecommendedPrinters();
 }
 
-PrinterPrefManager::~PrinterPrefManager() {}
+PrintersManager::~PrintersManager() {}
 
 // static
-void PrinterPrefManager::RegisterProfilePrefs(
+void PrintersManager::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterListPref(prefs::kPrintingDevices,
                              user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   registry->RegisterListPref(prefs::kRecommendedNativePrinters);
 }
 
-std::vector<std::unique_ptr<Printer>> PrinterPrefManager::GetPrinters() const {
+std::vector<std::unique_ptr<Printer>> PrintersManager::GetPrinters() const {
   std::vector<std::unique_ptr<Printer>> printers;
 
   std::vector<sync_pb::PrinterSpecifics> values =
@@ -85,8 +85,8 @@
   return printers;
 }
 
-std::vector<std::unique_ptr<Printer>>
-PrinterPrefManager::GetRecommendedPrinters() const {
+std::vector<std::unique_ptr<Printer>> PrintersManager::GetRecommendedPrinters()
+    const {
   std::vector<std::unique_ptr<Printer>> printers;
 
   for (const std::string& key : recommended_printer_ids_) {
@@ -103,7 +103,7 @@
   return printers;
 }
 
-std::unique_ptr<Printer> PrinterPrefManager::GetPrinter(
+std::unique_ptr<Printer> PrintersManager::GetPrinter(
     const std::string& printer_id) const {
   // check for a policy printer first
   const auto& policy_printers = recommended_printers_;
@@ -116,7 +116,7 @@
   return printer.has_value() ? printing::SpecificsToPrinter(*printer) : nullptr;
 }
 
-void PrinterPrefManager::RegisterPrinter(std::unique_ptr<Printer> printer) {
+void PrintersManager::RegisterPrinter(std::unique_ptr<Printer> printer) {
   if (printer->id().empty()) {
     printer->set_id(base::GenerateGUID());
   }
@@ -136,7 +136,7 @@
   }
 }
 
-bool PrinterPrefManager::RemovePrinter(const std::string& printer_id) {
+bool PrintersManager::RemovePrinter(const std::string& printer_id) {
   DCHECK(!printer_id.empty());
 
   base::Optional<sync_pb::PrinterSpecifics> printer =
@@ -157,21 +157,21 @@
   return success;
 }
 
-void PrinterPrefManager::AddObserver(Observer* observer) {
+void PrintersManager::AddObserver(Observer* observer) {
   observers_.AddObserver(observer);
 }
 
-void PrinterPrefManager::RemoveObserver(Observer* observer) {
+void PrintersManager::RemoveObserver(Observer* observer) {
   observers_.RemoveObserver(observer);
 }
 
-PrintersSyncBridge* PrinterPrefManager::GetSyncBridge() {
+PrintersSyncBridge* PrintersManager::GetSyncBridge() {
   return sync_bridge_.get();
 }
 
 // This method is not thread safe and could interact poorly with readers of
 // |recommended_printers_|.
-void PrinterPrefManager::UpdateRecommendedPrinters() {
+void PrintersManager::UpdateRecommendedPrinters() {
   const PrefService* prefs = profile_->GetPrefs();
 
   const base::ListValue* values =
diff --git a/chrome/browser/chromeos/printing/printer_pref_manager.h b/chrome/browser/chromeos/printing/printers_manager.h
similarity index 80%
rename from chrome/browser/chromeos/printing/printer_pref_manager.h
rename to chrome/browser/chromeos/printing/printers_manager.h
index 867ac737..04eb0dda 100644
--- a/chrome/browser/chromeos/printing/printer_pref_manager.h
+++ b/chrome/browser/chromeos/printing/printers_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_PREF_MANAGER_H_
-#define CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_PREF_MANAGER_H_
+#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_PRINTERS_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_PRINTING_PRINTERS_MANAGER_H_
 
 #include <map>
 #include <memory>
@@ -26,7 +26,10 @@
 
 namespace chromeos {
 
-class PrinterPrefManager : public KeyedService {
+// Manages printer information.  Provides an interface to a user's printers and
+// printers provided by policy.  User printers are backed by the
+// PrintersSyncBridge.
+class PrintersManager : public KeyedService {
  public:
   class Observer {
    public:
@@ -35,9 +38,9 @@
     virtual void OnPrinterRemoved(const Printer& printer) = 0;
   };
 
-  PrinterPrefManager(Profile* profile,
-                     std::unique_ptr<PrintersSyncBridge> sync_bridge);
-  ~PrinterPrefManager() override;
+  PrintersManager(Profile* profile,
+                  std::unique_ptr<PrintersSyncBridge> sync_bridge);
+  ~PrintersManager() override;
 
   // Register the printing preferences with the |registry|.
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
@@ -63,11 +66,11 @@
   // live on the same thread (UI) as this object.  OnPrinter* methods are
   // invoked inline so calling RegisterPrinter in response to OnPrinterAdded is
   // forbidden.
-  void AddObserver(PrinterPrefManager::Observer* observer);
+  void AddObserver(PrintersManager::Observer* observer);
 
   // Remove |observer| so that it no longer receives notifications.  After the
   // completion of this method, the |observer| can be safely destroyed.
-  void RemoveObserver(PrinterPrefManager::Observer* observer);
+  void RemoveObserver(PrintersManager::Observer* observer);
 
   // Returns a ModelTypeSyncBridge for the sync client.
   PrintersSyncBridge* GetSyncBridge();
@@ -90,9 +93,9 @@
 
   base::ObserverList<Observer> observers_;
 
-  DISALLOW_COPY_AND_ASSIGN(PrinterPrefManager);
+  DISALLOW_COPY_AND_ASSIGN(PrintersManager);
 };
 
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_PRINTER_PREF_MANAGER_H_
+#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_PRINTERS_MANAGER_H_
diff --git a/chrome/browser/chromeos/printing/printer_pref_manager_factory.cc b/chrome/browser/chromeos/printing/printers_manager_factory.cc
similarity index 71%
rename from chrome/browser/chromeos/printing/printer_pref_manager_factory.cc
rename to chrome/browser/chromeos/printing/printers_manager_factory.cc
index f8f0078..acfe074 100644
--- a/chrome/browser/chromeos/printing/printer_pref_manager_factory.cc
+++ b/chrome/browser/chromeos/printing/printers_manager_factory.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 "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 
 #include <memory>
 #include <utility>
@@ -21,36 +21,36 @@
 
 namespace {
 
-base::LazyInstance<PrinterPrefManagerFactory> g_printer_pref_manager =
+base::LazyInstance<PrintersManagerFactory> g_printers_manager =
     LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
 // static
-PrinterPrefManager* PrinterPrefManagerFactory::GetForBrowserContext(
+PrintersManager* PrintersManagerFactory::GetForBrowserContext(
     content::BrowserContext* context) {
-  return static_cast<PrinterPrefManager*>(
+  return static_cast<PrintersManager*>(
       GetInstance()->GetServiceForBrowserContext(context, true));
 }
 
 // static
-PrinterPrefManagerFactory* PrinterPrefManagerFactory::GetInstance() {
-  return g_printer_pref_manager.Pointer();
+PrintersManagerFactory* PrintersManagerFactory::GetInstance() {
+  return g_printers_manager.Pointer();
 }
 
-content::BrowserContext* PrinterPrefManagerFactory::GetBrowserContextToUse(
+content::BrowserContext* PrintersManagerFactory::GetBrowserContextToUse(
     content::BrowserContext* context) const {
   return chrome::GetBrowserContextRedirectedInIncognito(context);
 }
 
-PrinterPrefManagerFactory::PrinterPrefManagerFactory()
+PrintersManagerFactory::PrintersManagerFactory()
     : BrowserContextKeyedServiceFactory(
-          "PrinterPrefManager",
+          "PrintersManager",
           BrowserContextDependencyManager::GetInstance()) {}
 
-PrinterPrefManagerFactory::~PrinterPrefManagerFactory() {}
+PrintersManagerFactory::~PrintersManagerFactory() {}
 
-PrinterPrefManager* PrinterPrefManagerFactory::BuildServiceInstanceFor(
+PrintersManager* PrintersManagerFactory::BuildServiceInstanceFor(
     content::BrowserContext* browser_context) const {
   Profile* profile = Profile::FromBrowserContext(browser_context);
 
@@ -67,7 +67,7 @@
           base::BindRepeating(
               base::IgnoreResult(&base::debug::DumpWithoutCrashing)));
 
-  return new PrinterPrefManager(profile, std::move(sync_bridge));
+  return new PrintersManager(profile, std::move(sync_bridge));
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/printers_manager_factory.h b/chrome/browser/chromeos/printing/printers_manager_factory.h
new file mode 100644
index 0000000..fab4b339
--- /dev/null
+++ b/chrome/browser/chromeos/printing/printers_manager_factory.h
@@ -0,0 +1,45 @@
+// 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 CHROME_BROWSER_CHROMEOS_PRINTING_PRINTERS_MANAGER_FACTORY_H_
+#define CHROME_BROWSER_CHROMEOS_PRINTING_PRINTERS_MANAGER_FACTORY_H_
+
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace chromeos {
+
+class PrintersManagerFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static PrintersManager* GetForBrowserContext(
+      content::BrowserContext* context);
+
+  static PrintersManagerFactory* GetInstance();
+
+ protected:
+  content::BrowserContext* GetBrowserContextToUse(
+      content::BrowserContext* context) const override;
+
+ private:
+  friend struct base::DefaultLazyInstanceTraits<PrintersManagerFactory>;
+
+  PrintersManagerFactory();
+  ~PrintersManagerFactory() override;
+
+  // BrowserContextKeyedServiceFactory implementation:
+  PrintersManager* BuildServiceInstanceFor(
+      content::BrowserContext* browser_context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(PrintersManagerFactory);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_PRINTERS_MANAGER_FACTORY_H_
diff --git a/chrome/browser/chromeos/printing/printer_pref_manager_unittest.cc b/chrome/browser/chromeos/printing/printers_manager_unittest.cc
similarity index 88%
rename from chrome/browser/chromeos/printing/printer_pref_manager_unittest.cc
rename to chrome/browser/chromeos/printing/printers_manager_unittest.cc
index ea3bcad..616cb85 100644
--- a/chrome/browser/chromeos/printing/printer_pref_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/printers_manager_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
 
 #include <memory>
 #include <utility>
@@ -12,7 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/chromeos/printing/printers_sync_bridge.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
@@ -42,7 +42,7 @@
       } )json";
 
 // Helper class to record observed events.
-class LoggingObserver : public PrinterPrefManager::Observer {
+class LoggingObserver : public PrintersManager::Observer {
  public:
   void OnPrinterAdded(const Printer& printer) override {
     last_added_ = printer;
@@ -83,9 +83,9 @@
 
 }  // namespace
 
-class PrinterPrefManagerTest : public testing::Test {
+class PrintersManagerTest : public testing::Test {
  protected:
-  PrinterPrefManagerTest() : profile_(base::MakeUnique<TestingProfile>()) {
+  PrintersManagerTest() : profile_(base::MakeUnique<TestingProfile>()) {
     thread_bundle_ = base::MakeUnique<content::TestBrowserThreadBundle>();
 
     auto sync_bridge = base::MakeUnique<PrintersSyncBridge>(
@@ -94,13 +94,13 @@
         base::BindRepeating(
             base::IgnoreResult(&base::debug::DumpWithoutCrashing)));
 
-    manager_ = base::MakeUnique<PrinterPrefManager>(profile_.get(),
-                                                    std::move(sync_bridge));
+    manager_ = base::MakeUnique<PrintersManager>(profile_.get(),
+                                                 std::move(sync_bridge));
 
     base::RunLoop().RunUntilIdle();
   }
 
-  ~PrinterPrefManagerTest() override {
+  ~PrintersManagerTest() override {
     manager_.reset();
 
     // Explicitly release the profile before the thread_bundle.  Otherwise, the
@@ -110,13 +110,13 @@
   }
 
   std::unique_ptr<TestingProfile> profile_;
-  std::unique_ptr<PrinterPrefManager> manager_;
+  std::unique_ptr<PrintersManager> manager_;
 
  private:
   std::unique_ptr<content::TestBrowserThreadBundle> thread_bundle_;
 };
 
-TEST_F(PrinterPrefManagerTest, AddPrinter) {
+TEST_F(PrintersManagerTest, AddPrinter) {
   LoggingObserver observer;
   manager_->AddObserver(&observer);
   manager_->RegisterPrinter(base::MakeUnique<Printer>(kPrinterId));
@@ -130,7 +130,7 @@
   EXPECT_FALSE(observer.UpdateCalled());
 }
 
-TEST_F(PrinterPrefManagerTest, UpdatePrinterAssignsId) {
+TEST_F(PrintersManagerTest, UpdatePrinterAssignsId) {
   manager_->RegisterPrinter(base::MakeUnique<Printer>());
 
   auto printers = manager_->GetPrinters();
@@ -138,7 +138,7 @@
   EXPECT_FALSE(printers[0]->id().empty());
 }
 
-TEST_F(PrinterPrefManagerTest, UpdatePrinter) {
+TEST_F(PrintersManagerTest, UpdatePrinter) {
   manager_->RegisterPrinter(base::MakeUnique<Printer>(kPrinterId));
   auto updated_printer = base::MakeUnique<Printer>(kPrinterId);
   updated_printer->set_uri(kUri);
@@ -157,7 +157,7 @@
   EXPECT_FALSE(observer.AddCalled());
 }
 
-TEST_F(PrinterPrefManagerTest, RemovePrinter) {
+TEST_F(PrintersManagerTest, RemovePrinter) {
   manager_->RegisterPrinter(base::MakeUnique<Printer>("OtherUUID"));
   manager_->RegisterPrinter(base::MakeUnique<Printer>(kPrinterId));
   manager_->RegisterPrinter(base::MakeUnique<Printer>());
@@ -172,7 +172,7 @@
 
 // Tests for policy printers
 
-TEST_F(PrinterPrefManagerTest, RecommendedPrinters) {
+TEST_F(PrintersManagerTest, RecommendedPrinters) {
   std::string first_printer =
       R"json({
       "display_name": "Color Laser",
@@ -205,7 +205,7 @@
   EXPECT_EQ(Printer::Source::SRC_POLICY, printers[1]->source());
 }
 
-TEST_F(PrinterPrefManagerTest, GetRecommendedPrinter) {
+TEST_F(PrintersManagerTest, GetRecommendedPrinter) {
   std::string printer = kLexJson;
   auto value = base::MakeUnique<base::ListValue>();
   value->AppendString(printer);
diff --git a/chrome/browser/chromeos/system/timezone_resolver_manager.cc b/chrome/browser/chromeos/system/timezone_resolver_manager.cc
index ac9f358..2288cff 100644
--- a/chrome/browser/chromeos/system/timezone_resolver_manager.cc
+++ b/chrome/browser/chromeos/system/timezone_resolver_manager.cc
@@ -54,6 +54,8 @@
       return SHOULD_START;
     case enterprise_management::SystemTimezoneProto::SEND_WIFI_ACCESS_POINTS:
       return SHOULD_START;
+    case enterprise_management::SystemTimezoneProto::SEND_ALL_LOCATION_INFO:
+      return SHOULD_START;
   }
   // Default for unknown policy value.
   NOTREACHED() << "Unrecognized policy value: " << policy_value;
@@ -128,6 +130,20 @@
 }
 
 bool TimeZoneResolverManager::ShouldSendWiFiGeolocationData() {
+  int timezone_setting = GetTimezoneManagementSetting();
+  return (
+      (timezone_setting ==
+       enterprise_management::SystemTimezoneProto::SEND_WIFI_ACCESS_POINTS) ||
+      (timezone_setting ==
+       enterprise_management::SystemTimezoneProto::SEND_ALL_LOCATION_INFO));
+}
+
+bool TimeZoneResolverManager::ShouldSendCellularGeolocationData() {
+  return (GetTimezoneManagementSetting() ==
+          enterprise_management::SystemTimezoneProto::SEND_ALL_LOCATION_INFO);
+}
+
+int TimeZoneResolverManager::GetTimezoneManagementSetting() {
   PrefService* local_state = g_browser_process->local_state();
   const bool is_managed = local_state->IsManagedPreference(
       prefs::kSystemTimezoneAutomaticDetectionPolicy);
@@ -140,8 +156,7 @@
   DCHECK(policy_value <= enterprise_management::SystemTimezoneProto::
                              AutomaticTimezoneDetectionType_MAX);
 
-  return policy_value ==
-         enterprise_management::SystemTimezoneProto::SEND_WIFI_ACCESS_POINTS;
+  return policy_value;
 }
 
 void TimeZoneResolverManager::UpdateTimezoneResolver() {
diff --git a/chrome/browser/chromeos/system/timezone_resolver_manager.h b/chrome/browser/chromeos/system/timezone_resolver_manager.h
index f900c05..4db43af8 100644
--- a/chrome/browser/chromeos/system/timezone_resolver_manager.h
+++ b/chrome/browser/chromeos/system/timezone_resolver_manager.h
@@ -25,6 +25,9 @@
   // TimeZoneResolver::Delegate overrides:
   bool ShouldSendWiFiGeolocationData() override;
 
+  // TimeZoneResolver::Delegate overrides:
+  bool ShouldSendCellularGeolocationData() override;
+
   // Starts or stops TimezoneResolver according to currect settings.
   void UpdateTimezoneResolver();
 
@@ -40,6 +43,8 @@
   // all configuration data.
   bool TimeZoneResolverShouldBeRunning();
 
+  int GetTimezoneManagementSetting();
+
   // This is non-null only after user logs in.
   PrefService* primary_user_prefs_;
 
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc
index 868e5c7e..8ced201a 100644
--- a/chrome/browser/component_updater/recovery_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -44,6 +44,9 @@
 
 namespace component_updater {
 
+#if defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) || defined(OS_MACOSX)
+
 namespace {
 
 // CRX hash. The extension id is: npdjjkjlcidkjlamlmmdelcjbcpdjocm.
@@ -88,14 +91,12 @@
   UMA_HISTOGRAM_ENUMERATION("RecoveryComponent.Event", event, RCE_COUNT);
 }
 
-#if !defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
 // Checks if elevated recovery simulation switch was present on the command
 // line. This is for testing purpose.
 bool SimulatingElevatedRecovery() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kSimulateElevatedRecovery);
 }
-#endif  // !defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
 
 std::vector<std::string> GetRecoveryInstallArguments(
     const base::DictionaryValue& manifest,
@@ -137,7 +138,6 @@
   return command_line;
 }
 
-#if defined(OS_WIN) || defined(OS_MACOSX)
 std::unique_ptr<base::DictionaryValue> ReadManifest(
     const base::FilePath& manifest) {
   JSONFileValueDeserializer deserializer(manifest);
@@ -243,7 +243,6 @@
                      .MayBlock(),
       base::Bind(&DoElevatedInstallRecoveryComponent, installer_path));
 }
-#endif  // defined(OS_WIN)
 
 }  // namespace
 
@@ -332,7 +331,6 @@
   NOTREACHED() << "Recovery component update error: " << error;
 }
 
-#if defined(OS_WIN) || defined(OS_MACOSX)
 void WaitForInstallToComplete(base::Process process,
                               const base::FilePath& installer_folder,
                               PrefService* prefs) {
@@ -387,13 +385,6 @@
   // install later.
   return true;
 }
-#else
-bool RecoveryComponentInstaller::RunInstallCommand(
-    const base::CommandLine& cmdline,
-    const base::FilePath&) const {
-  return base::LaunchProcess(cmdline, base::LaunchOptions()).IsValid();
-}
-#endif  // defined(OS_WIN)
 
 #if defined(OS_POSIX)
 // Sets the POSIX executable permissions on a file
@@ -491,9 +482,13 @@
   return false;
 }
 
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
+#endif  // defined(GOOGLE_CHROME_BUILD)
+
 void RegisterRecoveryComponent(ComponentUpdateService* cus,
                                PrefService* prefs) {
-#if !defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
+#if defined(GOOGLE_CHROME_BUILD)
+#if defined(OS_WIN) || defined(OS_MACOSX)
   if (SimulatingElevatedRecovery()) {
     BrowserThread::PostTask(
         BrowserThread::UI,
@@ -508,7 +503,8 @@
       FROM_HERE,
       base::Bind(&RecoveryRegisterHelper, cus, prefs),
       base::TimeDelta::FromSeconds(6));
-#endif  // !defined(OS_CHROMEOS) && defined(GOOGLE_CHROME_BUILD)
+#endif
+#endif
 }
 
 void RegisterPrefsForRecoveryComponent(PrefRegistrySimple* registry) {
@@ -521,10 +517,13 @@
 void AcceptedElevatedRecoveryInstall(PrefService* prefs) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
+#if defined(GOOGLE_CHROME_BUILD)
 #if defined(OS_WIN) || defined(OS_MACOSX)
   ElevatedInstallRecoveryComponent(
       prefs->GetFilePath(prefs::kRecoveryComponentUnpackPath));
-#endif  // OS_WIN
+#endif
+#endif
+
   prefs->SetBoolean(prefs::kRecoveryComponentNeedsElevation, false);
 }
 
diff --git a/chrome/browser/downgrade/user_data_downgrade_browsertest.cc b/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
index 252b4d6e..b06c24d4 100644
--- a/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
+++ b/chrome/browser/downgrade/user_data_downgrade_browsertest.cc
@@ -24,7 +24,7 @@
   // content::BrowserTestBase:
   void SetUpInProcessBrowserTestFixture() override {
     HKEY root = HKEY_CURRENT_USER;
-    registry_override_manager_.OverrideRegistry(root);
+    ASSERT_NO_FATAL_FAILURE(registry_override_manager_.OverrideRegistry(root));
     key_.Create(root,
                 BrowserDistribution::GetDistribution()->GetStateKey().c_str(),
                 KEY_SET_VALUE | KEY_WOW64_32KEY);
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index e8f3650..98193c9 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -1083,7 +1083,9 @@
     : public safe_browsing::TestSafeBrowsingService,
       public safe_browsing::ServicesDelegate::ServicesCreator {
  public:
-  FakeSafeBrowsingService() {
+  FakeSafeBrowsingService()
+      : TestSafeBrowsingService(
+            safe_browsing::V4FeatureList::V4UsageStatus::V4_DISABLED) {
     services_delegate_ =
         safe_browsing::ServicesDelegate::CreateForTest(this, this);
   }
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 20e6d59..30aacdc 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -212,12 +212,6 @@
     "api/feedback_private/feedback_private_api.h",
     "api/feedback_private/feedback_service.cc",
     "api/feedback_private/feedback_service.h",
-    "api/file_handlers/app_file_handler_util.cc",
-    "api/file_handlers/app_file_handler_util.h",
-    "api/file_handlers/directory_util.cc",
-    "api/file_handlers/directory_util.h",
-    "api/file_handlers/mime_util.cc",
-    "api/file_handlers/mime_util.h",
     "api/file_handlers/non_native_file_system_delegate_chromeos.cc",
     "api/file_handlers/non_native_file_system_delegate_chromeos.h",
     "api/file_system/file_system_api.cc",
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index 49392c4..0facfa1 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/extensions/api/developer_private/extension_info_generator.h"
 #include "chrome/browser/extensions/api/developer_private/show_permissions_dialog_helper.h"
 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
-#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 #include "chrome/browser/extensions/devtools_util.h"
 #include "chrome/browser/extensions/extension_commands_global_registry.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -54,6 +53,7 @@
 #include "content/public/browser/site_instance.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/error_map.h"
diff --git a/chrome/browser/extensions/api/file_system/file_system_api.cc b/chrome/browser/extensions/api/file_system/file_system_api.cc
index 0a6d793..2591cd97 100644
--- a/chrome/browser/extensions/api/file_system/file_system_api.cc
+++ b/chrome/browser/extensions/api/file_system/file_system_api.cc
@@ -26,7 +26,6 @@
 #include "base/value_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/path_util.h"
@@ -43,6 +42,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #include "extensions/browser/extension_prefs.h"
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
index 1e39db9..14aef77a 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/logging.h"
-#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
-#include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
 #include "chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h"
+
+#include "base/logging.h"
+#include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 
 namespace image_writer_api = extensions::api::image_writer_private;
 
diff --git a/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc b/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc
index 4d6598d9..7ede50f 100644
--- a/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc
+++ b/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc
@@ -18,7 +18,6 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_prefs.h"
-#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
 #include "chrome/browser/extensions/api/log_private/filter_handler.h"
 #include "chrome/browser/extensions/api/log_private/log_parser.h"
 #include "chrome/browser/extensions/api/log_private/syslog_parser.h"
@@ -31,6 +30,7 @@
 #include "components/net_log/chrome_net_log.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_function.h"
 #include "extensions/browser/extension_registry.h"
diff --git a/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc b/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
index 085f6c1d..783b0b65 100644
--- a/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
+++ b/chrome/browser/extensions/api/messaging/native_messaging_test_util.cc
@@ -77,7 +77,7 @@
 
 #if defined(OS_WIN)
   HKEY root_key = user_level ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
-  registry_override_.OverrideRegistry(root_key);
+  ASSERT_NO_FATAL_FAILURE(registry_override_.OverrideRegistry(root_key));
 #else
   path_override_.reset(new base::ScopedPathOverride(
       user_level ? chrome::DIR_USER_NATIVE_MESSAGING
diff --git a/chrome/browser/extensions/api/notifications/notifications_apitest.cc b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
index 39abdd9..3d372df 100644
--- a/chrome/browser/extensions/api/notifications/notifications_apitest.cc
+++ b/chrome/browser/extensions/api/notifications/notifications_apitest.cc
@@ -188,7 +188,13 @@
 
 }  // namespace
 
-IN_PROC_BROWSER_TEST_F(NotificationsApiTest, TestBasicUsage) {
+// http://crbug.com/691913
+#if defined(OS_LINUX) && !defined(NDEBUG)
+#define MAYBE_TestBasicUsage DISABLED_TestBasicUsage
+#else
+#define MAYBE_TestBasicUsage TestBasicUsage
+#endif
+IN_PROC_BROWSER_TEST_F(NotificationsApiTest, MAYBE_TestBasicUsage) {
   ASSERT_TRUE(RunExtensionTest("notifications/api/basic_usage")) << message_;
 }
 
diff --git a/chrome/browser/google/OWNERS b/chrome/browser/google/OWNERS
index 2c1c5e2..558e550 100644
--- a/chrome/browser/google/OWNERS
+++ b/chrome/browser/google/OWNERS
@@ -1,2 +1,4 @@
 isherman@chromium.org
-pkasting@chromium.org
\ No newline at end of file
+pkasting@chromium.org
+
+# COMPONENT: Internals
diff --git a/chrome/browser/google/google_update_win_unittest.cc b/chrome/browser/google/google_update_win_unittest.cc
index ef886ff..2ea70c0 100644
--- a/chrome/browser/google/google_update_win_unittest.cc
+++ b/chrome/browser/google/google_update_win_unittest.cc
@@ -560,8 +560,10 @@
         new base::ScopedPathOverride(base::DIR_LOCAL_APP_DATA, temp));
 
     // Override the registry so that tests can freely push state to it.
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
-    registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
 
     // Chrome is installed.
     const HKEY root =
diff --git a/chrome/browser/infobars/OWNERS b/chrome/browser/infobars/OWNERS
index bf426d6..550d854f 100644
--- a/chrome/browser/infobars/OWNERS
+++ b/chrome/browser/infobars/OWNERS
@@ -1 +1,3 @@
 pkasting@chromium.org
+
+# COMPONENT: UI>Browser>Infobars
diff --git a/chrome/browser/loader/safe_browsing_resource_throttle.cc b/chrome/browser/loader/safe_browsing_resource_throttle.cc
index e1688c7..1610659 100644
--- a/chrome/browser/loader/safe_browsing_resource_throttle.cc
+++ b/chrome/browser/loader/safe_browsing_resource_throttle.cc
@@ -57,13 +57,10 @@
     const net::URLRequest* request,
     content::ResourceType resource_type,
     safe_browsing::SafeBrowsingService* sb_service)
-    : safe_browsing::BaseResourceThrottle(
-          request,
-          resource_type,
-          safe_browsing::V4FeatureList::IsV4HybridEnabled()
-              ? sb_service->v4_local_database_manager()
-              : sb_service->database_manager(),
-          sb_service->ui_manager()) {}
+    : safe_browsing::BaseResourceThrottle(request,
+                                          resource_type,
+                                          sb_service->database_manager(),
+                                          sb_service->ui_manager()) {}
 
 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {}
 
diff --git a/chrome/browser/media_galleries/media_galleries_test_util.cc b/chrome/browser/media_galleries/media_galleries_test_util.cc
index 55b82c8..437e897 100644
--- a/chrome/browser/media_galleries/media_galleries_test_util.cc
+++ b/chrome/browser/media_galleries/media_galleries_test_util.cc
@@ -193,7 +193,8 @@
   local_app_data_override_.reset(new base::ScopedPathOverride(
       base::DIR_LOCAL_APP_DATA, GetFakeLocalAppDataPath()));
   // Picasa also looks in the registry for an alternate path.
-  registry_override_.OverrideRegistry(HKEY_CURRENT_USER);
+  ASSERT_NO_FATAL_FAILURE(
+      registry_override_.OverrideRegistry(HKEY_CURRENT_USER));
 #endif  // OS_WIN
 
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/metrics/metrics_service_browsertest.cc b/chrome/browser/metrics/metrics_service_browsertest.cc
index 2167d5a..a51ede4 100644
--- a/chrome/browser/metrics/metrics_service_browsertest.cc
+++ b/chrome/browser/metrics/metrics_service_browsertest.cc
@@ -12,6 +12,8 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/path_service.h"
+#include "base/process/memory.h"
+#include "base/test/histogram_tester.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/browser.h"
@@ -28,6 +30,34 @@
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 
+#if defined(OS_POSIX)
+#include <sys/wait.h>
+#endif
+
+#if defined(OS_WIN)
+#include "sandbox/win/src/sandbox_types.h"
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+namespace {
+
+// Check CrashExitCodes.Renderer histogram for a single bucket entry and then
+// verify that the bucket entry contains a signal and the signal is |signal|.
+void VerifyRendererExitCodeIsSignal(
+    const base::HistogramTester& histogram_tester,
+    int signal) {
+  const auto buckets =
+      histogram_tester.GetAllSamples("CrashExitCodes.Renderer");
+  ASSERT_EQ(1UL, buckets.size());
+  EXPECT_EQ(1, buckets[0].count);
+  int32_t exit_code = buckets[0].min;
+  EXPECT_TRUE(WIFSIGNALED(exit_code));
+  EXPECT_EQ(signal, WTERMSIG(exit_code));
+}
+
+}  // namespace
+#endif  // OS_MACOSX || OS_LINUX
+
 class MetricsServiceBrowserTest : public InProcessBrowserTest {
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -79,6 +109,7 @@
 #define MAYBE_CrashRenderers CrashRenderers
 #endif
 IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, MAYBE_CrashRenderers) {
+  base::HistogramTester histogram_tester;
   OpenTabs();
 
   // Kill the process for one of the tabs.
@@ -101,11 +132,70 @@
 
   // Verify that the expected stability metrics were recorded.
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityLaunchCount));
+  // Expect four page loads:
+  // 1. title2.html
+  // 2. iframe.html
+  // 3. title1.html (iframed by iframe.html)
+  // 4. chrome://crash
   EXPECT_EQ(4, prefs->GetInteger(metrics::prefs::kStabilityPageLoadCount));
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
   // TODO(isherman): We should also verify that
   // metrics::prefs::kStabilityExitedCleanly
   // is set to true, but this preference isn't set until the browser
   // exits... it's not clear to me how to test that.
+
+#if defined(OS_WIN)
+  histogram_tester.ExpectUniqueSample(
+      "CrashExitCodes.Renderer",
+      std::abs(static_cast<int32_t>(STATUS_ACCESS_VIOLATION)), 1);
+#elif defined(OS_MACOSX) || defined(OS_LINUX)
+  VerifyRendererExitCodeIsSignal(histogram_tester, SIGSEGV);
+#endif
+  histogram_tester.ExpectUniqueSample("Tabs.SadTab.CrashCreated", 1, 1);
 }
 
+// OOM code only works on Windows.
+#if defined(OS_WIN) && !defined(ADDRESS_SANITIZER)
+IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, OOMRenderers) {
+  base::HistogramTester histogram_tester;
+  OpenTabs();
+
+  // Kill the process for one of the tabs.
+  content::RenderProcessHostWatcher observer(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  ui_test_utils::NavigateToURL(browser(),
+                               GURL(content::kChromeUIMemoryExhaustURL));
+  observer.Wait();
+
+  // The MetricsService listens for the same notification, so the |observer|
+  // might finish waiting before the MetricsService has a chance to process the
+  // notification.  To avoid racing here, we repeatedly run the message loop
+  // until the MetricsService catches up.  This should happen "real soon now",
+  // since the notification is posted to all observers essentially
+  // simultaneously... so busy waiting here shouldn't be too bad.
+  const PrefService* prefs = g_browser_process->local_state();
+  while (!prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount)) {
+    content::RunAllPendingInMessageLoop();
+  }
+
+  // Verify that the expected stability metrics were recorded.
+  EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityLaunchCount));
+  EXPECT_EQ(4, prefs->GetInteger(metrics::prefs::kStabilityPageLoadCount));
+  EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
+
+// On 64-bit, the Job object should terminate the renderer on an OOM.
+#if defined(ARCH_CPU_64_BITS)
+  const int expected_exit_code = sandbox::SBOX_FATAL_MEMORY_EXCEEDED;
+#else
+  const int expected_exit_code = base::win::kOomExceptionCode;
+#endif
+
+  // Exit codes are recorded after being passed through std::abs see
+  // MapCrashExitCodeForHistogram.
+  histogram_tester.ExpectUniqueSample("CrashExitCodes.Renderer",
+                                      std::abs(expected_exit_code), 1);
+
+  histogram_tester.ExpectUniqueSample("Tabs.SadTab.OomCreated", 1, 1);
+}
+#endif  // OS_WIN && !ADDRESS_SANITIZER
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
index 9b6e76c..2732110 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -207,13 +207,20 @@
 const char kHistogramNetworkBytes[] = "PageLoad.Experimental.Bytes.Network";
 const char kHistogramCacheBytes[] = "PageLoad.Experimental.Bytes.Cache";
 
+const char kHistogramTotalCompletedResources[] =
+    "PageLoad.Experimental.CompletedResources.Total";
+const char kHistogramNetworkCompletedResources[] =
+    "PageLoad.Experimental.CompletedResources.Network";
+const char kHistogramCacheCompletedResources[] =
+    "PageLoad.Experimental.CompletedResources.Cache";
+
 }  // namespace internal
 
 CorePageLoadMetricsObserver::CorePageLoadMetricsObserver()
     : transition_(ui::PAGE_TRANSITION_LINK),
       was_no_store_main_resource_(false),
-      num_cache_requests_(0),
-      num_network_requests_(0),
+      num_cache_resources_(0),
+      num_network_resources_(0),
       cache_bytes_(0),
       network_bytes_(0) {}
 
@@ -502,15 +509,15 @@
         timing.parse_blocked_on_script_execution_from_document_write_duration
             .value());
 
-    int total_requests = num_cache_requests_ + num_network_requests_;
-    if (total_requests) {
-      int percent_cached = (100 * num_cache_requests_) / total_requests;
+    int total_resources = num_cache_resources_ + num_network_resources_;
+    if (total_resources) {
+      int percent_cached = (100 * num_cache_resources_) / total_resources;
       UMA_HISTOGRAM_PERCENTAGE(internal::kHistogramCacheRequestPercentParseStop,
                                percent_cached);
       UMA_HISTOGRAM_COUNTS(internal::kHistogramCacheTotalRequestsParseStop,
-                           num_cache_requests_);
+                           num_cache_resources_);
       UMA_HISTOGRAM_COUNTS(internal::kHistogramTotalRequestsParseStop,
-                           num_cache_requests_ + num_network_requests_);
+                           num_cache_resources_ + num_network_resources_);
 
       // Separate out parse duration based on cache percent.
       if (percent_cached <= 50) {
@@ -539,21 +546,23 @@
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
   RecordTimingHistograms(timing, info);
+  RecordByteAndResourceHistograms(timing, info);
   RecordRappor(timing, info);
+}
 
-  int64_t total_kb = (network_bytes_ + cache_bytes_) / 1024;
-  int64_t network_kb = network_bytes_ / 1024;
-  int64_t cache_kb = cache_bytes_ / 1024;
-  DCHECK_LE(network_kb, total_kb);
-  DCHECK_LE(cache_kb, total_kb);
-  DCHECK_LE(total_kb, std::numeric_limits<int>::max());
-
-  UMA_HISTOGRAM_CUSTOM_COUNTS(internal::kHistogramNetworkBytes,
-                              static_cast<int>(network_kb), 1, 500 * 1024, 50);
-  UMA_HISTOGRAM_CUSTOM_COUNTS(internal::kHistogramCacheBytes,
-                              static_cast<int>(cache_kb), 1, 500 * 1024, 50);
-  UMA_HISTOGRAM_CUSTOM_COUNTS(internal::kHistogramTotalBytes,
-                              static_cast<int>(total_kb), 1, 500 * 1024, 50);
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+CorePageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  // FlushMetricsOnAppEnterBackground is invoked on Android in cases where the
+  // app is about to be backgrounded, as part of the Activity.onPause()
+  // flow. After this method is invoked, Chrome may be killed without further
+  // notification, so we record final metrics collected up to this point.
+  if (!info.committed_url.is_empty()) {
+    RecordTimingHistograms(timing, info);
+    RecordByteAndResourceHistograms(timing, info);
+  }
+  return STOP_OBSERVING;
 }
 
 void CorePageLoadMetricsObserver::OnFailedProvisionalLoad(
@@ -610,10 +619,10 @@
 void CorePageLoadMetricsObserver::OnLoadedResource(
     const page_load_metrics::ExtraRequestInfo& extra_request_info) {
   if (extra_request_info.was_cached) {
-    ++num_cache_requests_;
+    ++num_cache_resources_;
     cache_bytes_ += extra_request_info.raw_body_bytes;
   } else {
-    ++num_network_requests_;
+    ++num_network_resources_;
     network_bytes_ += extra_request_info.raw_body_bytes;
   }
 }
@@ -661,6 +670,25 @@
   }
 }
 
+void CorePageLoadMetricsObserver::RecordByteAndResourceHistograms(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  DCHECK_GE(network_bytes_, 0);
+  DCHECK_GE(cache_bytes_, 0);
+  int64_t total_bytes = network_bytes_ + cache_bytes_;
+
+  PAGE_BYTES_HISTOGRAM(internal::kHistogramNetworkBytes, network_bytes_);
+  PAGE_BYTES_HISTOGRAM(internal::kHistogramCacheBytes, cache_bytes_);
+  PAGE_BYTES_HISTOGRAM(internal::kHistogramTotalBytes, total_bytes);
+
+  PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramNetworkCompletedResources,
+                                num_network_resources_);
+  PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramCacheCompletedResources,
+                                num_cache_resources_);
+  PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramTotalCompletedResources,
+                                num_cache_resources_ + num_network_resources_);
+}
+
 void CorePageLoadMetricsObserver::RecordRappor(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
index ff9a8d66..ee4a86f 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
@@ -51,6 +51,10 @@
 extern const char kHistogramNetworkBytes[];
 extern const char kHistogramCacheBytes[];
 
+extern const char kHistogramTotalCompletedResources[];
+extern const char kHistogramNetworkCompletedResources[];
+extern const char kHistogramCacheCompletedResources[];
+
 enum FirstMeaningfulPaintStatus {
   FIRST_MEANINGFUL_PAINT_RECORDED,
   FIRST_MEANINGFUL_PAINT_BACKGROUNDED,
@@ -108,6 +112,9 @@
   void OnFailedProvisionalLoad(
       const page_load_metrics::FailedProvisionalLoadInfo& failed_load_info,
       const page_load_metrics::PageLoadExtraInfo& extra_info) override;
+  ObservePolicy FlushMetricsOnAppEnterBackground(
+      const page_load_metrics::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& info) override;
   void OnUserInput(const blink::WebInputEvent& event) override;
   void OnLoadedResource(
       const page_load_metrics::ExtraRequestInfo& extra_request_info) override;
@@ -115,6 +122,9 @@
  private:
   void RecordTimingHistograms(const page_load_metrics::PageLoadTiming& timing,
                               const page_load_metrics::PageLoadExtraInfo& info);
+  void RecordByteAndResourceHistograms(
+      const page_load_metrics::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& info);
   void RecordRappor(const page_load_metrics::PageLoadTiming& timing,
                     const page_load_metrics::PageLoadExtraInfo& info);
 
@@ -124,8 +134,8 @@
   // Note: these are only approximations, based on WebContents attribution from
   // ResourceRequestInfo objects while this is the currently committed load in
   // the WebContents.
-  int num_cache_requests_;
-  int num_network_requests_;
+  int num_cache_resources_;
+  int num_network_resources_;
 
   // The number of body (not header) prefilter bytes consumed by requests for
   // the page.
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
index 47f3cd7..e8a7178 100644
--- a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -482,12 +482,18 @@
       timing.parse_start.value().InMilliseconds(), 1);
 }
 
-TEST_F(CorePageLoadMetricsObserverTest, BytesCounted) {
+TEST_F(CorePageLoadMetricsObserverTest, BytesAndResourcesCounted) {
   NavigateAndCommit(GURL(kDefaultTestUrl));
   NavigateAndCommit(GURL(kDefaultTestUrl2));
   histogram_tester().ExpectTotalCount(internal::kHistogramTotalBytes, 1);
   histogram_tester().ExpectTotalCount(internal::kHistogramNetworkBytes, 1);
   histogram_tester().ExpectTotalCount(internal::kHistogramCacheBytes, 1);
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramTotalCompletedResources, 1);
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramNetworkCompletedResources, 1);
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramCacheCompletedResources, 1);
 }
 
 TEST_F(CorePageLoadMetricsObserverTest, FirstMeaningfulPaint) {
diff --git a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.cc
index d627499..602be0e 100644
--- a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.cc
@@ -53,11 +53,15 @@
     }                                                                          \
   } while (false)
 
-// Records the kilobytes (i.e., bytes / 1024) to |histogram_name| in a histogram
-// with 50 buckets capped at 500 MB.
-#define RECORD_KILOBYTES_HISTOGRAM(histogram_name, bytes) \
-  UMA_HISTOGRAM_CUSTOM_COUNTS(                            \
-      histogram_name, static_cast<int>((bytes) / 1024), 1, 500 * 1024, 50)
+// Like RECORD_HISTOGRAMS_FOR_SUFFIX, but only records histograms if the event
+// occurred while the page was in the foreground.
+#define RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(info, data, timing,         \
+                                                histogram_suffix)           \
+  do {                                                                      \
+    if (WasStartedInForegroundOptionalEventInForeground(timing, info)) {    \
+      RECORD_HISTOGRAMS_FOR_SUFFIX(data, timing.value(), histogram_suffix); \
+    }                                                                       \
+  } while (false)
 
 }  // namespace
 
@@ -87,16 +91,18 @@
     "ParseTiming.ParseBlockedOnScriptLoad";
 const char kHistogramParseDurationSuffix[] = "ParseTiming.ParseDuration";
 
-const char kRequestsPercentProxied[] =
-    "Experimental.Requests.Network.PercentProxied";
+const char kResourcesPercentProxied[] =
+    "Experimental.CompletedResources.Network.PercentProxied";
 const char kBytesPercentProxied[] = "Experimental.Bytes.Network.PercentProxied";
 const char kBytesCompressionRatio[] =
     "Experimental.Bytes.Network.CompressionRatio";
 const char kBytesInflationPercent[] =
     "Experimental.Bytes.Network.InflationPercent";
-const char kNetworkRequests[] = "Experimental.Requests.Network";
-const char kRequestsProxied[] = "Experimental.Requests.Network.Proxied";
-const char kRequestsNotProxied[] = "Experimental.Requests.Network.NonProxied";
+const char kNetworkResources[] = "Experimental.CompletedResources.Network";
+const char kResourcesProxied[] =
+    "Experimental.CompletedResources.Network.Proxied";
+const char kResourcesNotProxied[] =
+    "Experimental.CompletedResources.Network.NonProxied";
 const char kNetworkBytes[] = "Experimental.Bytes.Network";
 const char kBytesProxied[] = "Experimental.Bytes.Network.Proxied";
 const char kBytesNotProxied[] = "Experimental.Bytes.Network.NonProxied";
@@ -108,8 +114,8 @@
 
 DataReductionProxyMetricsObserver::DataReductionProxyMetricsObserver()
     : browser_context_(nullptr),
-      num_data_reduction_proxy_requests_(0),
-      num_network_requests_(0),
+      num_data_reduction_proxy_resources_(0),
+      num_network_resources_(0),
       original_network_bytes_(0),
       network_bytes_proxied_(0),
       network_bytes_(0) {}
@@ -159,15 +165,6 @@
 }
 
 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
-DataReductionProxyMetricsObserver::OnHidden(
-    const page_load_metrics::PageLoadTiming& timing,
-    const page_load_metrics::PageLoadExtraInfo& info) {
-  RecordPageSizeUMA();
-  SendPingback(timing, info);
-  return STOP_OBSERVING;
-}
-
-page_load_metrics::PageLoadMetricsObserver::ObservePolicy
 DataReductionProxyMetricsObserver::FlushMetricsOnAppEnterBackground(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
@@ -175,8 +172,10 @@
   // app is about to be backgrounded, as part of the Activity.onPause()
   // flow. After this method is invoked, Chrome may be killed without further
   // notification, so we send a pingback with data collected up to this point.
-  RecordPageSizeUMA();
-  SendPingback(timing, info);
+  if (!info.committed_url.is_empty()) {
+    RecordPageSizeUMA();
+    SendPingback(timing, info);
+  }
   return STOP_OBSERVING;
 }
 
@@ -188,17 +187,20 @@
 }
 
 void DataReductionProxyMetricsObserver::RecordPageSizeUMA() const {
+  if (!data_)
+    return;
+
   // If the first request didn't complete, don't record UMA.
-  if (num_network_requests_ == 0)
+  if (num_network_resources_ == 0)
     return;
 
   // TODO(ryansturm): Evaluate if any of the below histograms are unncessary
   // once data is available. crbug.com/682782
 
-  // The percent of requests that went through the data reduction proxy.
+  // The percent of resources that went through the data reduction proxy.
   UMA_HISTOGRAM_PERCENTAGE(
-      GetConstHistogramWithSuffix(internal::kRequestsPercentProxied),
-      (100 * num_data_reduction_proxy_requests_) / num_network_requests_);
+      GetConstHistogramWithSuffix(internal::kResourcesPercentProxied),
+      (100 * num_data_reduction_proxy_resources_) / num_network_resources_);
 
   // The percent of bytes that went through the data reduction proxy.
   if (network_bytes_ > 0) {
@@ -222,53 +224,48 @@
                          100));
   }
 
-  // Record the number of network requests seen.
-  UMA_HISTOGRAM_COUNTS_10000(
-      GetConstHistogramWithSuffix(internal::kNetworkRequests),
-      num_network_requests_);
+  // Record the number of network resources seen.
+  PAGE_RESOURCE_COUNT_HISTOGRAM(
+      GetConstHistogramWithSuffix(internal::kNetworkResources),
+      num_network_resources_);
 
-  // Record the number of requests that used data reduction proxy.
-  UMA_HISTOGRAM_COUNTS_10000(
-      GetConstHistogramWithSuffix(internal::kRequestsProxied),
-      num_data_reduction_proxy_requests_);
+  // Record the number of resources that used data reduction proxy.
+  PAGE_RESOURCE_COUNT_HISTOGRAM(
+      GetConstHistogramWithSuffix(internal::kResourcesProxied),
+      num_data_reduction_proxy_resources_);
 
-  // Record the number of requests that did not use data reduction proxy.
-  UMA_HISTOGRAM_COUNTS_10000(
-      GetConstHistogramWithSuffix(internal::kRequestsNotProxied),
-      num_network_requests_ - num_data_reduction_proxy_requests_);
+  // Record the number of resources that did not use data reduction proxy.
+  PAGE_RESOURCE_COUNT_HISTOGRAM(
+      GetConstHistogramWithSuffix(internal::kResourcesNotProxied),
+      num_network_resources_ - num_data_reduction_proxy_resources_);
 
   // Record the total KB of network bytes.
-  RECORD_KILOBYTES_HISTOGRAM(
-      GetConstHistogramWithSuffix(internal::kNetworkBytes), network_bytes_);
+  PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kNetworkBytes),
+                       network_bytes_);
 
   // Record the total amount of bytes that went through the data reduction
   // proxy.
-  RECORD_KILOBYTES_HISTOGRAM(
-      GetConstHistogramWithSuffix(internal::kBytesProxied),
-      network_bytes_proxied_);
+  PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kBytesProxied),
+                       network_bytes_proxied_);
 
   // Record the total amount of bytes that did not go through the data reduction
   // proxy.
-  RECORD_KILOBYTES_HISTOGRAM(
-      GetConstHistogramWithSuffix(internal::kBytesNotProxied),
-      network_bytes_ - network_bytes_proxied_);
+  PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kBytesNotProxied),
+                       network_bytes_ - network_bytes_proxied_);
 
   // Record the total KB of network bytes that the user would have seen without
   // using data reduction proxy.
-  RECORD_KILOBYTES_HISTOGRAM(
-      GetConstHistogramWithSuffix(internal::kBytesOriginal),
-      original_network_bytes_);
+  PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kBytesOriginal),
+                       original_network_bytes_);
 
   // Record the savings the user saw by using data reduction proxy. If there was
   // inflation instead, record that.
   if (network_bytes_ <= original_network_bytes_) {
-    RECORD_KILOBYTES_HISTOGRAM(
-        GetConstHistogramWithSuffix(internal::kBytesSavings),
-        original_network_bytes_ - network_bytes_);
+    PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kBytesSavings),
+                         original_network_bytes_ - network_bytes_);
   } else {
-    RECORD_KILOBYTES_HISTOGRAM(
-        GetConstHistogramWithSuffix(internal::kBytesInflation),
-        network_bytes_proxied_ - original_network_bytes_);
+    PAGE_BYTES_HISTOGRAM(GetConstHistogramWithSuffix(internal::kBytesInflation),
+                         network_bytes_proxied_ - original_network_bytes_);
   }
 }
 
@@ -277,7 +274,7 @@
     const page_load_metrics::PageLoadExtraInfo& info) {
   // TODO(ryansturm): Move to OnFirstBackgroundEvent to handle some fast
   // shutdown cases. crbug.com/618072
-  if (!browser_context_)
+  if (!browser_context_ || !data_)
     return;
   if (data_reduction_proxy::params::IsIncludedInHoldbackFieldTrial() ||
       data_reduction_proxy::params::IsIncludedInTamperDetectionExperiment()) {
@@ -334,70 +331,78 @@
 void DataReductionProxyMetricsObserver::OnDomContentLoadedEventStart(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(
-      data_, timing.dom_content_loaded_event_start.value(),
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
+      info, data_, timing.dom_content_loaded_event_start,
       internal::kHistogramDOMContentLoadedEventFiredSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnLoadEventStart(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(data_, timing.load_event_start.value(),
-                               internal::kHistogramLoadEventFiredSuffix);
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
+      info, data_, timing.load_event_start,
+      internal::kHistogramLoadEventFiredSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnFirstLayout(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(data_, timing.first_layout.value(),
-                               internal::kHistogramFirstLayoutSuffix);
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
+      info, data_, timing.first_layout, internal::kHistogramFirstLayoutSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnFirstPaint(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(data_, timing.first_paint.value(),
-                               internal::kHistogramFirstPaintSuffix);
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(info, data_, timing.first_paint,
+                                          internal::kHistogramFirstPaintSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnFirstTextPaint(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(data_, timing.first_text_paint.value(),
-                               internal::kHistogramFirstTextPaintSuffix);
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
+      info, data_, timing.first_text_paint,
+      internal::kHistogramFirstTextPaintSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnFirstImagePaint(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(data_, timing.first_image_paint.value(),
-                               internal::kHistogramFirstImagePaintSuffix);
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
+      info, data_, timing.first_image_paint,
+      internal::kHistogramFirstImagePaintSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnFirstContentfulPaint(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(data_, timing.first_contentful_paint.value(),
-                               internal::kHistogramFirstContentfulPaintSuffix);
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
+      info, data_, timing.first_contentful_paint,
+      internal::kHistogramFirstContentfulPaintSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnFirstMeaningfulPaint(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(data_, timing.first_meaningful_paint.value(),
-                               internal::kHistogramFirstMeaningfulPaintSuffix);
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(
+      info, data_, timing.first_meaningful_paint,
+      internal::kHistogramFirstMeaningfulPaintSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnParseStart(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
-  RECORD_HISTOGRAMS_FOR_SUFFIX(data_, timing.parse_start.value(),
-                               internal::kHistogramParseStartSuffix);
+  RECORD_FOREGROUND_HISTOGRAMS_FOR_SUFFIX(info, data_, timing.parse_start,
+                                          internal::kHistogramParseStartSuffix);
 }
 
 void DataReductionProxyMetricsObserver::OnParseStop(
     const page_load_metrics::PageLoadTiming& timing,
     const page_load_metrics::PageLoadExtraInfo& info) {
+  if (!WasStartedInForegroundOptionalEventInForeground(timing.parse_stop, info))
+    return;
+
   base::TimeDelta parse_duration =
       timing.parse_stop.value() - timing.parse_start.value();
   RECORD_HISTOGRAMS_FOR_SUFFIX(data_, parse_duration,
@@ -413,10 +418,10 @@
     return;
   original_network_bytes_ += extra_request_info.original_network_content_length;
   network_bytes_ += extra_request_info.raw_body_bytes;
-  num_network_requests_++;
+  num_network_resources_++;
   if (!extra_request_info.data_reduction_proxy_used)
     return;
-  num_data_reduction_proxy_requests_++;
+  num_data_reduction_proxy_resources_++;
   network_bytes_proxied_ += extra_request_info.raw_body_bytes;
 }
 
diff --git a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.h b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.h
index 5dca62a4..19b92c1 100644
--- a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer.h
@@ -44,13 +44,13 @@
 extern const char kHistogramParseDurationSuffix[];
 
 // Byte and request specific histogram suffixes.
-extern const char kRequestsPercentProxied[];
+extern const char kResourcesPercentProxied[];
 extern const char kBytesPercentProxied[];
 extern const char kBytesCompressionRatio[];
 extern const char kBytesInflationPercent[];
-extern const char kNetworkRequests[];
-extern const char kRequestsProxied[];
-extern const char kRequestsNotProxied[];
+extern const char kNetworkResources[];
+extern const char kResourcesProxied[];
+extern const char kResourcesNotProxied[];
 extern const char kNetworkBytes[];
 extern const char kBytesProxied[];
 extern const char kBytesNotProxied[];
@@ -73,9 +73,6 @@
                         const GURL& currently_committed_url,
                         bool started_in_foreground) override;
   ObservePolicy OnCommit(content::NavigationHandle* navigation_handle) override;
-  ObservePolicy OnHidden(
-      const page_load_metrics::PageLoadTiming& timing,
-      const page_load_metrics::PageLoadExtraInfo& info) override;
   ObservePolicy FlushMetricsOnAppEnterBackground(
       const page_load_metrics::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& info) override;
@@ -127,11 +124,11 @@
   // The browser context this navigation is operating in.
   content::BrowserContext* browser_context_;
 
-  // The number of requests that used data reduction proxy.
-  int num_data_reduction_proxy_requests_;
+  // The number of resources that used data reduction proxy.
+  int num_data_reduction_proxy_resources_;
 
-  // The number of request that did not come from cache.
-  int num_network_requests_;
+  // The number of resources that did not come from cache.
+  int num_network_resources_;
 
   // The total content network bytes that the user would have downloaded if they
   // were not using data reduction proxy.
diff --git a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
index 8888a94..81203cf 100644
--- a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
@@ -30,7 +30,6 @@
 namespace {
 
 const char kDefaultTestUrl[] = "http://google.com";
-const char kDefaultTestUrl2[] = "http://example.com";
 
 data_reduction_proxy::DataReductionProxyData* DataForNavigationHandle(
     content::WebContents* web_contents,
@@ -151,21 +150,18 @@
     PopulateRequiredTimingFields(&timing_);
   }
 
-  void RunTest(
-      bool data_reduction_proxy_used,
-      bool is_using_lofi,
-      std::function<void(page_load_metrics::PageLoadTracker*)> extra_steps) {
+  void RunTest(bool data_reduction_proxy_used, bool is_using_lofi) {
     data_reduction_proxy_used_ = data_reduction_proxy_used;
     is_using_lofi_ = is_using_lofi;
     NavigateAndCommit(GURL(kDefaultTestUrl));
     SimulateTimingUpdate(timing_);
     pingback_client_->Reset();
+  }
 
-    extra_steps(recent_tracker_);
-
-    // Navigate again to force OnComplete, which happens when a new navigation
-    // occurs.
-    NavigateAndCommit(GURL(kDefaultTestUrl2));
+  void RunTestAndNavigateToUntrackedUrl(bool data_reduction_proxy_used,
+                                        bool is_using_lofi) {
+    RunTest(data_reduction_proxy_used, is_using_lofi);
+    NavigateToUntrackedUrl();
   }
 
   // Verify that, if expected and actual are set, their values are equal.
@@ -252,15 +248,15 @@
         event.value().InMilliseconds(), is_using_lofi_ ? 1 : 0);
   }
 
-  void ValidateDataHistograms(int network_requests,
-                              int drp_requests,
+  void ValidateDataHistograms(int network_resources,
+                              int drp_resources,
                               int64_t network_bytes,
                               int64_t drp_bytes,
                               int64_t ocl_bytes) {
     histogram_tester().ExpectUniqueSample(
         std::string(internal::kHistogramDataReductionProxyPrefix)
-            .append(internal::kRequestsPercentProxied),
-        100 * drp_requests / network_requests, 1);
+            .append(internal::kResourcesPercentProxied),
+        100 * drp_resources / network_resources, 1);
 
     histogram_tester().ExpectUniqueSample(
         std::string(internal::kHistogramDataReductionProxyPrefix)
@@ -269,18 +265,18 @@
 
     histogram_tester().ExpectUniqueSample(
         std::string(internal::kHistogramDataReductionProxyPrefix)
-            .append(internal::kNetworkRequests),
-        network_requests, 1);
+            .append(internal::kNetworkResources),
+        network_resources, 1);
 
     histogram_tester().ExpectUniqueSample(
         std::string(internal::kHistogramDataReductionProxyPrefix)
-            .append(internal::kRequestsProxied),
-        drp_requests, 1);
+            .append(internal::kResourcesProxied),
+        drp_resources, 1);
 
     histogram_tester().ExpectUniqueSample(
         std::string(internal::kHistogramDataReductionProxyPrefix)
-            .append(internal::kRequestsNotProxied),
-        network_requests - drp_requests, 1);
+            .append(internal::kResourcesNotProxied),
+        network_resources - drp_resources, 1);
 
     histogram_tester().ExpectUniqueSample(
         std::string(internal::kHistogramDataReductionProxyPrefix)
@@ -326,7 +322,6 @@
 
  protected:
   void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
-    recent_tracker_ = tracker;
     tracker->AddObserver(
         base::MakeUnique<TestDataReductionProxyMetricsObserver>(
             web_contents(), pingback_client_.get(), data_reduction_proxy_used_,
@@ -337,7 +332,6 @@
   page_load_metrics::PageLoadTiming timing_;
 
  private:
-  page_load_metrics::PageLoadTracker* recent_tracker_;
   bool data_reduction_proxy_used_;
   bool is_using_lofi_;
 
@@ -347,7 +341,7 @@
 TEST_F(DataReductionProxyMetricsObserverTest, DataReductionProxyOff) {
   ResetTest();
   // Verify that when the data reduction proxy was not used, no UMA is reported.
-  RunTest(false, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTest(false, false);
   ValidateHistograms();
 }
 
@@ -355,7 +349,7 @@
   ResetTest();
   // Verify that when the data reduction proxy was used, but lofi was not used,
   // the correpsonding UMA is reported.
-  RunTest(true, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTest(true, false);
   ValidateHistograms();
 }
 
@@ -363,7 +357,7 @@
   ResetTest();
   // Verify that when the data reduction proxy was used and lofi was used, both
   // histograms are reported.
-  RunTest(true, true, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTest(true, true);
   ValidateHistograms();
 }
 
@@ -371,41 +365,41 @@
   ResetTest();
   // Verify that when data reduction proxy was used the correct timing
   // information is sent to SendPingback.
-  RunTest(true, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTestAndNavigateToUntrackedUrl(true, false);
   ValidateTimes();
 
   ResetTest();
   // Verify that when data reduction proxy was used but first image paint is
   // unset, the correct timing information is sent to SendPingback.
   timing_.first_image_paint = base::nullopt;
-  RunTest(true, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTestAndNavigateToUntrackedUrl(true, false);
   ValidateTimes();
 
   ResetTest();
   // Verify that when data reduction proxy was used but first contentful paint
   // is unset, SendPingback is not called.
   timing_.first_contentful_paint = base::nullopt;
-  RunTest(true, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTestAndNavigateToUntrackedUrl(true, false);
   ValidateTimes();
 
   ResetTest();
   // Verify that when data reduction proxy was used but first meaningful paint
   // is unset, SendPingback is not called.
   timing_.first_meaningful_paint = base::nullopt;
-  RunTest(true, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTestAndNavigateToUntrackedUrl(true, false);
   ValidateTimes();
 
   ResetTest();
   // Verify that when data reduction proxy was used but load event start is
   // unset, SendPingback is not called.
   timing_.load_event_start = base::nullopt;
-  RunTest(true, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTestAndNavigateToUntrackedUrl(true, false);
   ValidateTimes();
 
   ResetTest();
   // Verify that when data reduction proxy was not used, SendPingback is not
   // called.
-  RunTest(false, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTestAndNavigateToUntrackedUrl(false, false);
   EXPECT_FALSE(pingback_client_->send_pingback_called());
 
   ResetTest();
@@ -413,115 +407,105 @@
   base::FieldTrialList field_trial_list(nullptr);
   ASSERT_TRUE(base::FieldTrialList::CreateFieldTrial(
       "DataCompressionProxyHoldback", "Enabled"));
-  RunTest(true, false, [](page_load_metrics::PageLoadTracker* tracker) {});
+  RunTestAndNavigateToUntrackedUrl(true, false);
   EXPECT_FALSE(pingback_client_->send_pingback_called());
 }
 
 TEST_F(DataReductionProxyMetricsObserverTest, ByteInformationCompression) {
   ResetTest();
 
-  int network_requests = 0;
-  int drp_requests = 0;
+  RunTest(true, false);
+
+  // Prepare 4 resources of varying size and configurations.
+  page_load_metrics::ExtraRequestInfo resources[] = {
+      // Cached request.
+      {true /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+       false /* data_reduction_proxy_used*/,
+       0 /* original_network_content_length */},
+      // Uncached non-proxied request.
+      {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+       false /* data_reduction_proxy_used*/,
+       1024 * 40 /* original_network_content_length */},
+      // Uncached proxied request with .1 compression ratio.
+      {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+       true /* data_reduction_proxy_used*/,
+       1024 * 40 * 10 /* original_network_content_length */},
+      // Uncached proxied request with .5 compression ratio.
+      {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+       true /* data_reduction_proxy_used*/,
+       1024 * 40 * 5 /* original_network_content_length */},
+  };
+
+  int network_resources = 0;
+  int drp_resources = 0;
   int64_t network_bytes = 0;
   int64_t drp_bytes = 0;
   int64_t ocl_bytes = 0;
+  for (auto request : resources) {
+    SimulateLoadedResource(request);
+    if (!request.was_cached) {
+      network_bytes += request.raw_body_bytes;
+      ocl_bytes += request.original_network_content_length;
+      ++network_resources;
+    }
+    if (request.data_reduction_proxy_used) {
+      drp_bytes += request.raw_body_bytes;
+      ++drp_resources;
+    }
+  }
 
-  std::function<void(page_load_metrics::PageLoadTracker*)> extra_steps =
-      [&network_requests, &drp_requests, &network_bytes, &drp_bytes,
-       &ocl_bytes](page_load_metrics::PageLoadTracker* tracker) {
-        // Prepare 4 requests of varying size and configurations.
-        page_load_metrics::ExtraRequestInfo requests[] = {
-            // Cached request.
-            {true /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
-             false /* data_reduction_proxy_used*/,
-             0 /* original_network_content_length */},
-            // Uncached non-proxied request.
-            {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
-             false /* data_reduction_proxy_used*/,
-             1024 * 40 /* original_network_content_length */},
-            // Uncached proxied request with .1 compression ratio.
-            {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
-             true /* data_reduction_proxy_used*/,
-             1024 * 40 * 10 /* original_network_content_length */},
-            // Uncached proxied request with .5 compression ratio.
-            {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
-             true /* data_reduction_proxy_used*/,
-             1024 * 40 * 5 /* original_network_content_length */},
+  NavigateToUntrackedUrl();
 
-        };
-
-        for (auto request : requests) {
-          tracker->OnLoadedResource(request);
-          if (!request.was_cached) {
-            network_bytes += request.raw_body_bytes;
-            ocl_bytes += request.original_network_content_length;
-            ++network_requests;
-          }
-          if (request.data_reduction_proxy_used) {
-            drp_bytes += request.raw_body_bytes;
-            ++drp_requests;
-          }
-        }
-      };
-
-  RunTest(true, false, extra_steps);
-
-  ValidateDataHistograms(network_requests, drp_requests, network_bytes,
+  ValidateDataHistograms(network_resources, drp_resources, network_bytes,
                          drp_bytes, ocl_bytes);
 }
 
 TEST_F(DataReductionProxyMetricsObserverTest, ByteInformationInflation) {
   ResetTest();
 
-  int network_requests = 0;
-  int drp_requests = 0;
+  RunTest(true, false);
+
+  // Prepare 4 resources of varying size and configurations.
+  page_load_metrics::ExtraRequestInfo resources[] = {
+      // Cached request.
+      {true /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+       false /* data_reduction_proxy_used*/,
+       0 /* original_network_content_length */},
+      // Uncached non-proxied request.
+      {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
+       false /* data_reduction_proxy_used*/,
+       1024 * 40 /* original_network_content_length */},
+      // Uncached proxied request with .1 compression ratio.
+      {false /*was_cached*/, 1024 * 40 * 10 /* raw_body_bytes */,
+       true /* data_reduction_proxy_used*/,
+       1024 * 40 /* original_network_content_length */},
+      // Uncached proxied request with .5 compression ratio.
+      {false /*was_cached*/, 1024 * 40 * 5 /* raw_body_bytes */,
+       true /* data_reduction_proxy_used*/,
+       1024 * 40 /* original_network_content_length */},
+  };
+
+  int network_resources = 0;
+  int drp_resources = 0;
   int64_t network_bytes = 0;
   int64_t drp_bytes = 0;
   int64_t ocl_bytes = 0;
+  for (auto request : resources) {
+    SimulateLoadedResource(request);
+    if (!request.was_cached) {
+      network_bytes += request.raw_body_bytes;
+      ocl_bytes += request.original_network_content_length;
+      ++network_resources;
+    }
+    if (request.data_reduction_proxy_used) {
+      drp_bytes += request.raw_body_bytes;
+      ++drp_resources;
+    }
+  }
 
-  std::function<void(page_load_metrics::PageLoadTracker*)> extra_steps =
-      [&network_requests, &drp_requests, &network_bytes, &drp_bytes,
-       &ocl_bytes](page_load_metrics::PageLoadTracker* tracker) {
-        // Prepare 4 requests of varying size and configurations.
+  NavigateToUntrackedUrl();
 
-        // Prepare 4 requests of varying size and configurations.
-        page_load_metrics::ExtraRequestInfo requests[] = {
-            // Cached request.
-            {true /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
-             false /* data_reduction_proxy_used*/,
-             0 /* original_network_content_length */},
-            // Uncached non-proxied request.
-            {false /*was_cached*/, 1024 * 40 /* raw_body_bytes */,
-             false /* data_reduction_proxy_used*/,
-             1024 * 40 /* original_network_content_length */},
-            // Uncached proxied request with .1 compression ratio.
-            {false /*was_cached*/, 1024 * 40 * 10 /* raw_body_bytes */,
-             true /* data_reduction_proxy_used*/,
-             1024 * 40 /* original_network_content_length */},
-            // Uncached proxied request with .5 compression ratio.
-            {false /*was_cached*/, 1024 * 40 * 5 /* raw_body_bytes */,
-             true /* data_reduction_proxy_used*/,
-             1024 * 40 /* original_network_content_length */},
-
-        };
-
-        for (auto request : requests) {
-          tracker->OnLoadedResource(request);
-          if (!request.was_cached) {
-            network_bytes += request.raw_body_bytes;
-            ocl_bytes += request.original_network_content_length;
-            ++network_requests;
-          }
-          if (request.data_reduction_proxy_used) {
-            drp_bytes += request.raw_body_bytes;
-            ++drp_requests;
-          }
-        }
-      };
-
-  RunTest(true, false, extra_steps);
-
-  ValidateDataHistograms(network_requests, drp_requests, network_bytes,
+  ValidateDataHistograms(network_resources, drp_resources, network_bytes,
                          drp_bytes, ocl_bytes);
 }
 
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
index 9a87792..48cc20a 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
 
 #include <memory>
+#include <string>
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -40,6 +41,18 @@
   DISALLOW_COPY_AND_ASSIGN(TestPageLoadMetricsEmbedderInterface);
 };
 
+base::Optional<base::TimeDelta> OptionalMin(
+    const base::Optional<base::TimeDelta>& a,
+    const base::Optional<base::TimeDelta>& b) {
+  if (a && !b)
+    return a;
+  if (b && !a)
+    return b;
+  if (!a && !b)
+    return a;  // doesn't matter which
+  return base::Optional<base::TimeDelta>(std::min(a.value(), b.value()));
+}
+
 }  // namespace
 
 PageLoadMetricsObserverTestHarness::PageLoadMetricsObserverTestHarness()
@@ -50,17 +63,17 @@
 // static
 void PageLoadMetricsObserverTestHarness::PopulateRequiredTimingFields(
     PageLoadTiming* inout_timing) {
-  if (inout_timing->first_meaningful_paint && !inout_timing->first_paint) {
-    inout_timing->first_paint = inout_timing->first_meaningful_paint;
+  if (inout_timing->first_meaningful_paint &&
+      !inout_timing->first_contentful_paint) {
+    inout_timing->first_contentful_paint = inout_timing->first_meaningful_paint;
   }
-  if (inout_timing->first_contentful_paint && !inout_timing->first_paint) {
-    inout_timing->first_paint = inout_timing->first_contentful_paint;
-  }
-  if (inout_timing->first_text_paint && !inout_timing->first_paint) {
-    inout_timing->first_paint = inout_timing->first_text_paint;
-  }
-  if (inout_timing->first_image_paint && !inout_timing->first_paint) {
-    inout_timing->first_paint = inout_timing->first_image_paint;
+  if ((inout_timing->first_text_paint || inout_timing->first_image_paint ||
+       inout_timing->first_contentful_paint) &&
+      !inout_timing->first_paint) {
+    inout_timing->first_paint =
+        OptionalMin(OptionalMin(inout_timing->first_text_paint,
+                                inout_timing->first_image_paint),
+                    inout_timing->first_contentful_paint);
   }
   if (inout_timing->first_paint && !inout_timing->first_layout) {
     inout_timing->first_layout = inout_timing->first_paint;
@@ -133,6 +146,14 @@
                                web_contents()->GetMainFrame());
 }
 
+void PageLoadMetricsObserverTestHarness::SimulateLoadedResource(
+    const ExtraRequestInfo& info) {
+  observer_->OnRequestComplete(
+      content::GlobalRequestID(), content::RESOURCE_TYPE_SCRIPT,
+      info.was_cached, info.data_reduction_proxy_used, info.raw_body_bytes,
+      info.original_network_content_length, base::TimeTicks::Now());
+}
+
 void PageLoadMetricsObserverTestHarness::SimulateInputEvent(
     const blink::WebInputEvent& event) {
   observer_->OnInputEvent(event);
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
index 5ff0447..4df6470f 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
@@ -9,6 +9,7 @@
 #include "base/test/histogram_tester.h"
 #include "chrome/browser/page_load_metrics/metrics_web_contents_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "content/public/test/web_contents_tester.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
@@ -42,6 +43,12 @@
   void NavigateWithPageTransitionAndCommit(const GURL& url,
                                            ui::PageTransition transition);
 
+  // Navigates to a URL that is not tracked by page_load_metrics. Useful for
+  // forcing the OnComplete method of a PageLoadMetricsObserver to run.
+  void NavigateToUntrackedUrl() {
+    NavigateAndCommit(GURL(url::kAboutBlankURL));
+  }
+
   // Call this to simulate sending a PageLoadTiming IPC from the render process
   // to the browser process. These will update the timing information for the
   // most recently committed navigation.
@@ -49,6 +56,9 @@
   void SimulateTimingAndMetadataUpdate(const PageLoadTiming& timing,
                                        const PageLoadMetadata& metadata);
 
+  // Simulates a loaded resource.
+  void SimulateLoadedResource(const ExtraRequestInfo& info);
+
   // Simulates a user input.
   void SimulateInputEvent(const blink::WebInputEvent& event);
 
diff --git a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc
new file mode 100644
index 0000000..5e5fa29
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.cc
@@ -0,0 +1,179 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h"
+
+#include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
+#include "third_party/WebKit/public/platform/WebLoadingBehaviorFlag.h"
+
+namespace internal {
+
+const char kHistogramSubresourceFilterFirstContentfulPaint[] =
+    "PageLoad.Clients.SubresourceFilter.PaintTiming."
+    "NavigationToFirstContentfulPaint";
+const char kHistogramSubresourceFilterParseStartToFirstContentfulPaint[] =
+    "PageLoad.Clients.SubresourceFilter.PaintTiming."
+    "ParseStartToFirstContentfulPaint";
+const char kHistogramSubresourceFilterFirstMeaningfulPaint[] =
+    "PageLoad.Clients.SubresourceFilter.Experimental.PaintTiming."
+    "NavigationToFirstMeaningfulPaint";
+const char kHistogramSubresourceFilterParseStartToFirstMeaningfulPaint[] =
+    "PageLoad.Clients.SubresourceFilter.Experimental.PaintTiming."
+    "ParseStartToFirstMeaningfulPaint";
+
+const char kHistogramSubresourceFilterDomContentLoaded[] =
+    "PageLoad.Clients.SubresourceFilter.DocumentTiming."
+    "NavigationToDOMContentLoadedEventFired";
+const char kHistogramSubresourceFilterLoad[] =
+    "PageLoad.Clients.SubresourceFilter.DocumentTiming."
+    "NavigationToLoadEventFired";
+
+const char kHistogramSubresourceFilterTotalResources[] =
+    "PageLoad.Clients.SubresourceFilter.Experimental.CompletedResources.Total";
+const char kHistogramSubresourceFilterNetworkResources[] =
+    "PageLoad.Clients.SubresourceFilter.Experimental.CompletedResources."
+    "Network";
+const char kHistogramSubresourceFilterCacheResources[] =
+    "PageLoad.Clients.SubresourceFilter.Experimental.CompletedResources.Cache";
+
+const char kHistogramSubresourceFilterTotalBytes[] =
+    "PageLoad.Clients.SubresourceFilter.Experimental.Bytes.Total";
+const char kHistogramSubresourceFilterNetworkBytes[] =
+    "PageLoad.Clients.SubresourceFilter.Experimental.Bytes.Network";
+const char kHistogramSubresourceFilterCacheBytes[] =
+    "PageLoad.Clients.SubresourceFilter.Experimental.Bytes.Cache";
+
+const char kHistogramSubresourceFilterCount[] =
+    "PageLoad.Clients.SubresourceFilter.Count";
+
+}  // namespace internal
+
+page_load_metrics::PageLoadMetricsObserver::ObservePolicy
+SubresourceFilterMetricsObserver::FlushMetricsOnAppEnterBackground(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  // FlushMetricsOnAppEnterBackground is invoked on Android in cases where the
+  // app is about to be backgrounded, as part of the Activity.onPause()
+  // flow. After this method is invoked, Chrome may be killed without further
+  // notification, so we record final metrics collected up to this point.
+  if (!info.committed_url.is_empty())
+    OnGoingAway(timing, info);
+  return STOP_OBSERVING;
+}
+
+void SubresourceFilterMetricsObserver::OnComplete(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  OnGoingAway(timing, info);
+}
+
+void SubresourceFilterMetricsObserver::OnLoadedResource(
+    const page_load_metrics::ExtraRequestInfo& extra_request_info) {
+  if (extra_request_info.was_cached) {
+    ++num_cache_resources_;
+    cache_bytes_ += extra_request_info.raw_body_bytes;
+  } else {
+    ++num_network_resources_;
+    network_bytes_ += extra_request_info.raw_body_bytes;
+  }
+}
+
+void SubresourceFilterMetricsObserver::OnFirstContentfulPaint(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  if (!subresource_filter_observed_)
+    return;
+
+  if (WasStartedInForegroundOptionalEventInForeground(
+          timing.first_contentful_paint, info)) {
+    PAGE_LOAD_HISTOGRAM(
+        internal::kHistogramSubresourceFilterFirstContentfulPaint,
+        timing.first_contentful_paint.value());
+    PAGE_LOAD_HISTOGRAM(
+        internal::kHistogramSubresourceFilterParseStartToFirstContentfulPaint,
+        timing.first_contentful_paint.value() - timing.parse_start.value());
+  }
+}
+
+void SubresourceFilterMetricsObserver::OnFirstMeaningfulPaint(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  if (!subresource_filter_observed_)
+    return;
+
+  if (WasStartedInForegroundOptionalEventInForeground(
+          timing.first_meaningful_paint, info)) {
+    PAGE_LOAD_HISTOGRAM(
+        internal::kHistogramSubresourceFilterFirstMeaningfulPaint,
+        timing.first_meaningful_paint.value());
+    PAGE_LOAD_HISTOGRAM(
+        internal::kHistogramSubresourceFilterParseStartToFirstMeaningfulPaint,
+        timing.first_meaningful_paint.value() - timing.parse_start.value());
+  }
+}
+
+void SubresourceFilterMetricsObserver::OnDomContentLoadedEventStart(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  if (!subresource_filter_observed_)
+    return;
+
+  if (WasStartedInForegroundOptionalEventInForeground(
+          timing.dom_content_loaded_event_start, info)) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramSubresourceFilterDomContentLoaded,
+                        timing.dom_content_loaded_event_start.value());
+  }
+}
+
+void SubresourceFilterMetricsObserver::OnLoadEventStart(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  if (!subresource_filter_observed_)
+    return;
+
+  if (WasStartedInForegroundOptionalEventInForeground(timing.load_event_start,
+                                                      info)) {
+    PAGE_LOAD_HISTOGRAM(internal::kHistogramSubresourceFilterLoad,
+                        timing.load_event_start.value());
+  }
+}
+
+void SubresourceFilterMetricsObserver::OnLoadingBehaviorObserved(
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  if (subresource_filter_observed_)
+    return;
+
+  subresource_filter_observed_ =
+      (info.metadata.behavior_flags &
+       blink::WebLoadingBehaviorFlag::
+           WebLoadingBehaviorSubresourceFilterMatch) != 0;
+
+  if (subresource_filter_observed_) {
+    UMA_HISTOGRAM_BOOLEAN(internal::kHistogramSubresourceFilterCount, true);
+  }
+}
+
+void SubresourceFilterMetricsObserver::OnGoingAway(
+    const page_load_metrics::PageLoadTiming& timing,
+    const page_load_metrics::PageLoadExtraInfo& info) {
+  if (!subresource_filter_observed_)
+    return;
+
+  PAGE_RESOURCE_COUNT_HISTOGRAM(
+      internal::kHistogramSubresourceFilterNetworkResources,
+      num_network_resources_);
+  PAGE_RESOURCE_COUNT_HISTOGRAM(
+      internal::kHistogramSubresourceFilterCacheResources,
+      num_cache_resources_);
+  PAGE_RESOURCE_COUNT_HISTOGRAM(
+      internal::kHistogramSubresourceFilterTotalResources,
+      num_cache_resources_ + num_network_resources_);
+
+  PAGE_BYTES_HISTOGRAM(internal::kHistogramSubresourceFilterNetworkBytes,
+                       network_bytes_);
+  PAGE_BYTES_HISTOGRAM(internal::kHistogramSubresourceFilterCacheBytes,
+                       cache_bytes_);
+  PAGE_BYTES_HISTOGRAM(internal::kHistogramSubresourceFilterTotalBytes,
+                       cache_bytes_ + network_bytes_);
+}
diff --git a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h
new file mode 100644
index 0000000..27b0128
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h
@@ -0,0 +1,76 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_SUBRESOURCE_FILTER_METRICS_OBSERVER_H_
+#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_SUBRESOURCE_FILTER_METRICS_OBSERVER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/page_load_metrics/page_load_metrics_observer.h"
+
+namespace internal {
+
+extern const char kHistogramSubresourceFilterFirstContentfulPaint[];
+extern const char kHistogramSubresourceFilterParseStartToFirstContentfulPaint[];
+extern const char kHistogramSubresourceFilterFirstMeaningfulPaint[];
+extern const char kHistogramSubresourceFilterParseStartToFirstMeaningfulPaint[];
+
+extern const char kHistogramSubresourceFilterTotalResources[];
+extern const char kHistogramSubresourceFilterNetworkResources[];
+extern const char kHistogramSubresourceFilterCacheResources[];
+extern const char kHistogramSubresourceFilterTotalBytes[];
+extern const char kHistogramSubresourceFilterNetworkBytes[];
+extern const char kHistogramSubresourceFilterCacheBytes[];
+
+extern const char kHistogramSubresourceFilterDomContentLoaded[];
+extern const char kHistogramSubresourceFilterLoad[];
+
+extern const char kHistogramSubresourceFilterCount[];
+
+}  // namespace internal
+
+class SubresourceFilterMetricsObserver
+    : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+  SubresourceFilterMetricsObserver() = default;
+  ~SubresourceFilterMetricsObserver() override = default;
+
+  // page_load_metrics::PageLoadMetricsObserver:
+  ObservePolicy FlushMetricsOnAppEnterBackground(
+      const page_load_metrics::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& info) override;
+  void OnComplete(const page_load_metrics::PageLoadTiming& timing,
+                  const page_load_metrics::PageLoadExtraInfo& info) override;
+  void OnLoadedResource(
+      const page_load_metrics::ExtraRequestInfo& extra_request_info) override;
+  void OnFirstContentfulPaint(
+      const page_load_metrics::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& info) override;
+  void OnFirstMeaningfulPaint(
+      const page_load_metrics::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& info) override;
+  void OnDomContentLoadedEventStart(
+      const page_load_metrics::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
+  void OnLoadEventStart(
+      const page_load_metrics::PageLoadTiming& timing,
+      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
+  void OnLoadingBehaviorObserved(
+      const page_load_metrics::PageLoadExtraInfo& extra_info) override;
+
+ private:
+  void OnGoingAway(const page_load_metrics::PageLoadTiming& timing,
+                   const page_load_metrics::PageLoadExtraInfo& info);
+
+  int64_t network_bytes_ = 0;
+  int64_t cache_bytes_ = 0;
+
+  int num_network_resources_ = 0;
+  int num_cache_resources_ = 0;
+
+  bool subresource_filter_observed_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(SubresourceFilterMetricsObserver);
+};
+
+#endif  // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_SUBRESOURCE_FILTER_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc
new file mode 100644
index 0000000..1ca4638
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h"
+
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
+
+namespace {
+const char kDefaultTestUrl[] = "https://example.com/";
+}  // namespace
+
+class SubresourceFilterMetricsObserverTest
+    : public page_load_metrics::PageLoadMetricsObserverTestHarness {
+ public:
+  void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
+    tracker->AddObserver(base::MakeUnique<SubresourceFilterMetricsObserver>());
+  }
+
+  bool AnyMetricsRecorded() {
+    return !histogram_tester()
+                .GetTotalCountsForPrefix("PageLoad.Clients.SubresourceFilter.")
+                .empty();
+  }
+
+  void InitializePageLoadTiming(page_load_metrics::PageLoadTiming* timing) {
+    timing->navigation_start = base::Time::FromDoubleT(1);
+    timing->parse_start = base::TimeDelta::FromMilliseconds(100);
+    timing->first_contentful_paint = base::TimeDelta::FromMilliseconds(300);
+    timing->first_meaningful_paint = base::TimeDelta::FromMilliseconds(400);
+    timing->dom_content_loaded_event_start =
+        base::TimeDelta::FromMilliseconds(1200);
+    timing->load_event_start = base::TimeDelta::FromMilliseconds(1500);
+    PopulateRequiredTimingFields(timing);
+  }
+};
+
+TEST_F(SubresourceFilterMetricsObserverTest,
+       NoMetricsForNonSubresourceFilteredNavigation) {
+  NavigateAndCommit(GURL(kDefaultTestUrl));
+
+  page_load_metrics::PageLoadTiming timing;
+  InitializePageLoadTiming(&timing);
+  SimulateTimingUpdate(timing);
+
+  // Navigate away from the current page to force logging of request and byte
+  // metrics.
+  NavigateToUntrackedUrl();
+
+  ASSERT_FALSE(AnyMetricsRecorded());
+}
+
+TEST_F(SubresourceFilterMetricsObserverTest, Basic) {
+  NavigateAndCommit(GURL(kDefaultTestUrl));
+
+  page_load_metrics::PageLoadTiming timing;
+  InitializePageLoadTiming(&timing);
+  page_load_metrics::PageLoadMetadata metadata;
+  metadata.behavior_flags |=
+      blink::WebLoadingBehaviorFlag::WebLoadingBehaviorSubresourceFilterMatch;
+  SimulateTimingAndMetadataUpdate(timing, metadata);
+
+  ASSERT_TRUE(AnyMetricsRecorded());
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterCount, 1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterFirstContentfulPaint, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterFirstContentfulPaint,
+      timing.first_contentful_paint.value().InMilliseconds(), 1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterParseStartToFirstContentfulPaint, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterParseStartToFirstContentfulPaint,
+      (timing.first_contentful_paint.value() - timing.parse_start.value())
+          .InMilliseconds(),
+      1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterFirstMeaningfulPaint, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterFirstMeaningfulPaint,
+      timing.first_meaningful_paint.value().InMilliseconds(), 1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterParseStartToFirstMeaningfulPaint, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterParseStartToFirstMeaningfulPaint,
+      (timing.first_meaningful_paint.value() - timing.parse_start.value())
+          .InMilliseconds(),
+      1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterDomContentLoaded, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterDomContentLoaded,
+      timing.dom_content_loaded_event_start.value().InMilliseconds(), 1);
+
+  histogram_tester().ExpectTotalCount(internal::kHistogramSubresourceFilterLoad,
+                                      1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterLoad,
+      timing.load_event_start.value().InMilliseconds(), 1);
+}
+
+TEST_F(SubresourceFilterMetricsObserverTest, Subresources) {
+  NavigateAndCommit(GURL(kDefaultTestUrl));
+
+  SimulateLoadedResource({false /* was_cached */,
+                          1024 * 40 /* raw_body_bytes */,
+                          false /* data_reduction_proxy_used */,
+                          0 /* original_network_content_length */});
+
+  page_load_metrics::PageLoadTiming timing;
+  timing.navigation_start = base::Time::FromDoubleT(1);
+  page_load_metrics::PageLoadMetadata metadata;
+  metadata.behavior_flags |=
+      blink::WebLoadingBehaviorFlag::WebLoadingBehaviorSubresourceFilterMatch;
+  SimulateTimingAndMetadataUpdate(timing, metadata);
+
+  SimulateLoadedResource({false /* was_cached */,
+                          1024 * 20 /* raw_body_bytes */,
+                          false /* data_reduction_proxy_used */,
+                          0 /* original_network_content_length */});
+
+  SimulateLoadedResource({true /* was_cached */, 1024 * 10 /* raw_body_bytes */,
+                          false /* data_reduction_proxy_used */,
+                          0 /* original_network_content_length */});
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterCount, 1);
+
+  // Navigate away from the current page to force logging of request and byte
+  // metrics.
+  NavigateToUntrackedUrl();
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterTotalResources, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterTotalResources, 3, 1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterNetworkResources, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterNetworkResources, 2, 1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterCacheResources, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterCacheResources, 1, 1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterTotalBytes, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterTotalBytes, 70, 1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterNetworkBytes, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterNetworkBytes, 60, 1);
+
+  histogram_tester().ExpectTotalCount(
+      internal::kHistogramSubresourceFilterCacheBytes, 1);
+  histogram_tester().ExpectBucketCount(
+      internal::kHistogramSubresourceFilterCacheBytes, 10, 1);
+}
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 9eea0c7..a409b5e 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/page_load_metrics/observers/protocol_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/service_worker_page_load_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface.h"
 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
@@ -81,6 +82,7 @@
         base::WrapUnique(new previews::PreviewsPageLoadMetricsObserver()));
     tracker->AddObserver(
         base::MakeUnique<ServiceWorkerPageLoadMetricsObserver>());
+    tracker->AddObserver(base::MakeUnique<SubresourceFilterMetricsObserver>());
     tracker->AddObserver(
         base::MakeUnique<HttpsEngagementPageLoadMetricsObserver>(
             web_contents_->GetBrowserContext()));
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_util.h b/chrome/browser/page_load_metrics/page_load_metrics_util.h
index a8abf7ef..3babd6a 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_util.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_util.h
@@ -14,6 +14,13 @@
                              base::TimeDelta::FromMilliseconds(10), \
                              base::TimeDelta::FromMinutes(10), 100)
 
+// Records |bytes| to |histogram_name| in kilobytes (i.e., bytes / 1024).
+#define PAGE_BYTES_HISTOGRAM(histogram_name, bytes) \
+  UMA_HISTOGRAM_CUSTOM_COUNTS(                      \
+      histogram_name, static_cast<int>((bytes) / 1024), 1, 500 * 1024, 50)
+
+#define PAGE_RESOURCE_COUNT_HISTOGRAM UMA_HISTOGRAM_COUNTS_10000
+
 namespace page_load_metrics {
 
 struct PageLoadExtraInfo;
diff --git a/chrome/browser/page_load_metrics/page_load_tracker.cc b/chrome/browser/page_load_metrics/page_load_tracker.cc
index 6f161e9f..26c591db 100644
--- a/chrome/browser/page_load_metrics/page_load_tracker.cc
+++ b/chrome/browser/page_load_metrics/page_load_tracker.cc
@@ -254,6 +254,8 @@
                                      const PageLoadTiming& new_timing,
                                      const PageLoadMetadata& last_metadata,
                                      const PageLoadExtraInfo& extra_info) {
+  if (extra_info.metadata.behavior_flags != last_metadata.behavior_flags)
+    observer->OnLoadingBehaviorObserved(extra_info);
   if (last_timing != new_timing)
     observer->OnTimingUpdate(new_timing, extra_info);
   if (new_timing.dom_content_loaded_event_start &&
@@ -277,8 +279,6 @@
     observer->OnParseStart(new_timing, extra_info);
   if (new_timing.parse_stop && !last_timing.parse_stop)
     observer->OnParseStop(new_timing, extra_info);
-  if (extra_info.metadata.behavior_flags != last_metadata.behavior_flags)
-    observer->OnLoadingBehaviorObserved(extra_info);
 }
 
 }  // namespace
diff --git a/chrome/browser/permissions/permission_context_base.cc b/chrome/browser/permissions/permission_context_base.cc
index c00f3e7a..895589ed 100644
--- a/chrome/browser/permissions/permission_context_base.cc
+++ b/chrome/browser/permissions/permission_context_base.cc
@@ -146,13 +146,14 @@
     bool permission_blocked) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (permission_blocked) {
-    // TODO(meredithl): Add UMA metrics here.
     web_contents->GetMainFrame()->AddMessageToConsole(
         content::CONSOLE_MESSAGE_LEVEL_INFO,
         base::StringPrintf(
             "%s permission has been auto-blocked.",
             PermissionUtil::GetPermissionString(permission_type_).c_str()));
     // Permission has been automatically blocked.
+    PermissionUmaUtil::RecordPermissionEmbargoStatus(
+        PermissionEmbargoStatus::PERMISSIONS_BLACKLISTING);
     callback.Run(CONTENT_SETTING_BLOCK);
     return;
   }
@@ -295,6 +296,8 @@
     PermissionRequestGestureType gesture_type =
         user_gesture ? PermissionRequestGestureType::GESTURE
                      : PermissionRequestGestureType::NO_GESTURE;
+    PermissionEmbargoStatus embargo_status =
+        PermissionEmbargoStatus::NOT_EMBARGOED;
     DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
            content_setting == CONTENT_SETTING_BLOCK ||
            content_setting == CONTENT_SETTING_DEFAULT);
@@ -307,15 +310,13 @@
     } else {
       PermissionUmaUtil::PermissionDismissed(permission_type_, gesture_type,
                                              requesting_origin, profile_);
-    }
-  }
 
-  if (content_setting == CONTENT_SETTING_DEFAULT &&
-      PermissionDecisionAutoBlocker::GetForProfile(profile_)
-          ->RecordDismissAndEmbargo(requesting_origin, permission_type_)) {
-    // The permission has been embargoed, so it is blocked for this permission
-    // request, but not persisted.
-    content_setting = CONTENT_SETTING_BLOCK;
+      if (PermissionDecisionAutoBlocker::GetForProfile(profile_)
+              ->RecordDismissAndEmbargo(requesting_origin, permission_type_)) {
+        embargo_status = PermissionEmbargoStatus::REPEATED_DISMISSALS;
+      }
+    }
+    PermissionUmaUtil::RecordPermissionEmbargoStatus(embargo_status);
   }
 
   NotifyPermissionSet(id, requesting_origin, embedding_origin, callback,
diff --git a/chrome/browser/permissions/permission_context_base_unittest.cc b/chrome/browser/permissions/permission_context_base_unittest.cc
index 888e537e..bc030de 100644
--- a/chrome/browser/permissions/permission_context_base_unittest.cc
+++ b/chrome/browser/permissions/permission_context_base_unittest.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/permissions/permission_decision_auto_blocker.h"
 #include "chrome/browser/permissions/permission_queue_controller.h"
 #include "chrome/browser/permissions/permission_request_id.h"
+#include "chrome/browser/permissions/permission_uma_util.h"
 #include "chrome/browser/permissions/permission_util.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
@@ -319,6 +320,9 @@
       EXPECT_EQ(CONTENT_SETTING_ASK,
                 permission_context.GetContentSettingFromMap(url, url));
     }
+
+    histograms.ExpectUniqueSample("Permissions.AutoBlocker.EmbargoStatus",
+                                  PermissionEmbargoStatus::NOT_EMBARGOED, 1);
   }
 
   void DismissMultipleTimesAndExpectBlock(
@@ -356,8 +360,20 @@
           "Permissions.Prompt.Dismissed.PriorDismissCount." +
               PermissionUtil::GetPermissionString(permission_type),
           i, 1);
+      histograms.ExpectTotalCount("Permissions.AutoBlocker.EmbargoStatus",
+                                  i + 1);
+      if (i < 2) {
+        histograms.ExpectUniqueSample("Permissions.AutoBlocker.EmbargoStatus",
+                                      PermissionEmbargoStatus::NOT_EMBARGOED,
+                                      i + 1);
+      } else {
+        histograms.ExpectBucketCount(
+            "Permissions.AutoBlocker.EmbargoStatus",
+            PermissionEmbargoStatus::REPEATED_DISMISSALS, 1);
+      }
+
       ASSERT_EQ(1u, permission_context.decisions().size());
-      EXPECT_EQ(expected, permission_context.decisions()[0]);
+      EXPECT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]);
       EXPECT_TRUE(permission_context.tab_context_updated());
       EXPECT_EQ(expected, permission_context.GetPermissionStatus(url, url));
     }
@@ -410,6 +426,10 @@
           i + 1);
       histograms.ExpectBucketCount(
           "Permissions.Prompt.Dismissed.PriorDismissCount.Geolocation", i, 1);
+      histograms.ExpectUniqueSample("Permissions.AutoBlocker.EmbargoStatus",
+                                    PermissionEmbargoStatus::NOT_EMBARGOED,
+                                    i + 1);
+
       ASSERT_EQ(1u, permission_context.decisions().size());
       EXPECT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]);
       EXPECT_TRUE(permission_context.tab_context_updated());
@@ -492,7 +512,7 @@
                      base::Unretained(&permission_context)));
 
       EXPECT_EQ(1u, permission_context.decisions().size());
-      ASSERT_EQ(expected, permission_context.decisions()[0]);
+      ASSERT_EQ(CONTENT_SETTING_ASK, permission_context.decisions()[0]);
       EXPECT_TRUE(permission_context.tab_context_updated());
       EXPECT_EQ(expected, permission_context.GetPermissionStatus(url, url));
 
@@ -500,6 +520,18 @@
           "Permissions.Prompt.Dismissed.PriorDismissCount.MidiSysEx", i + 1);
       histograms.ExpectBucketCount(
           "Permissions.Prompt.Dismissed.PriorDismissCount.MidiSysEx", i, 1);
+
+      histograms.ExpectTotalCount("Permissions.AutoBlocker.EmbargoStatus",
+                                  i + 1);
+      if (i < 4) {
+        histograms.ExpectUniqueSample("Permissions.AutoBlocker.EmbargoStatus",
+                                      PermissionEmbargoStatus::NOT_EMBARGOED,
+                                      i + 1);
+      } else {
+        histograms.ExpectBucketCount(
+            "Permissions.AutoBlocker.EmbargoStatus",
+            PermissionEmbargoStatus::REPEATED_DISMISSALS, 1);
+      }
     }
 
     // Ensure that we finish in the block state.
@@ -646,8 +678,10 @@
       scoped_refptr<safe_browsing::SafeBrowsingDatabaseManager> db_manager,
       const GURL& url,
       int timeout,
-      ContentSetting expected_permission_status) {
+      ContentSetting expected_permission_status,
+      PermissionEmbargoStatus expected_embargo_reason) {
     NavigateAndCommit(url);
+    base::HistogramTester histograms;
     base::test::ScopedFeatureList scoped_feature_list;
     scoped_feature_list.InitAndEnableFeature(features::kPermissionsBlacklist);
     TestPermissionContext permission_context(profile(), permission_type,
@@ -680,6 +714,8 @@
       ASSERT_EQ(1u, permission_context.decisions().size());
       EXPECT_EQ(expected_permission_status, permission_context.decisions()[0]);
     }
+    histograms.ExpectUniqueSample("Permissions.AutoBlocker.EmbargoStatus",
+                                  expected_embargo_reason, 1);
   }
 
  private:
@@ -845,9 +881,10 @@
   const GURL url("https://www.example.com");
   std::set<std::string> blacklisted_permissions{"GEOLOCATION"};
   db_manager->BlacklistUrlPermissions(url, blacklisted_permissions);
-  TestPermissionsBlacklisting(content::PermissionType::GEOLOCATION,
-                              CONTENT_SETTINGS_TYPE_GEOLOCATION, db_manager,
-                              url, 2000 /* timeout */, CONTENT_SETTING_BLOCK);
+  TestPermissionsBlacklisting(
+      content::PermissionType::GEOLOCATION, CONTENT_SETTINGS_TYPE_GEOLOCATION,
+      db_manager, url, 2000 /* timeout */, CONTENT_SETTING_BLOCK,
+      PermissionEmbargoStatus::PERMISSIONS_BLACKLISTING);
 }
 
 // Tests that a URL that is blacklisted for one permission can still request
@@ -860,5 +897,6 @@
   db_manager->BlacklistUrlPermissions(url, blacklisted_permissions);
   TestPermissionsBlacklisting(content::PermissionType::NOTIFICATIONS,
                               CONTENT_SETTINGS_TYPE_NOTIFICATIONS, db_manager,
-                              url, 2000 /* timeout */, CONTENT_SETTING_ALLOW);
+                              url, 2000 /* timeout */, CONTENT_SETTING_ALLOW,
+                              PermissionEmbargoStatus::NOT_EMBARGOED);
 }
diff --git a/chrome/browser/permissions/permission_decision_auto_blocker.cc b/chrome/browser/permissions/permission_decision_auto_blocker.cc
index 9bf499f..f8ab89c 100644
--- a/chrome/browser/permissions/permission_decision_auto_blocker.cc
+++ b/chrome/browser/permissions/permission_decision_auto_blocker.cc
@@ -271,11 +271,7 @@
     const GURL& request_origin,
     content::WebContents* web_contents,
     base::Callback<void(bool)> callback) {
-  // Check if origin is currently under embargo for the requested permission.
-  if (IsUnderEmbargo(permission, request_origin)) {
-    callback.Run(true /* permission_blocked */);
-    return;
-  }
+  DCHECK(!IsUnderEmbargo(permission, request_origin));
 
   if (base::FeatureList::IsEnabled(features::kPermissionsBlacklist) &&
       db_manager_) {
diff --git a/chrome/browser/permissions/permission_queue_controller.cc b/chrome/browser/permissions/permission_queue_controller.cc
index 4a12662..6f12eb47 100644
--- a/chrome/browser/permissions/permission_queue_controller.cc
+++ b/chrome/browser/permissions/permission_queue_controller.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/permissions/permission_decision_auto_blocker.h"
 #include "chrome/browser/permissions/permission_dialog_delegate.h"
 #include "chrome/browser/permissions/permission_infobar_delegate.h"
 #include "chrome/browser/permissions/permission_request.h"
@@ -228,16 +229,28 @@
                                            requesting_frame, profile_);
       PermissionUmaUtil::RecordPermissionPromptAccepted(request_type,
                                                         gesture_type);
+      PermissionUmaUtil::RecordPermissionEmbargoStatus(
+          PermissionEmbargoStatus::NOT_EMBARGOED);
       break;
     case DENIED:
       PermissionUmaUtil::PermissionDenied(permission_type_, gesture_type,
                                           requesting_frame, profile_);
       PermissionUmaUtil::RecordPermissionPromptDenied(request_type,
                                                       gesture_type);
+      PermissionUmaUtil::RecordPermissionEmbargoStatus(
+          PermissionEmbargoStatus::NOT_EMBARGOED);
       break;
     case DISMISSED:
       PermissionUmaUtil::PermissionDismissed(permission_type_, gesture_type,
                                              requesting_frame, profile_);
+      if (PermissionDecisionAutoBlocker::GetForProfile(profile_)
+              ->RecordDismissAndEmbargo(requesting_frame, permission_type_)) {
+        PermissionUmaUtil::RecordPermissionEmbargoStatus(
+            PermissionEmbargoStatus::REPEATED_DISMISSALS);
+      } else {
+        PermissionUmaUtil::RecordPermissionEmbargoStatus(
+            PermissionEmbargoStatus::NOT_EMBARGOED);
+      }
       break;
     default:
       NOTREACHED();
diff --git a/chrome/browser/permissions/permission_request_impl.cc b/chrome/browser/permissions/permission_request_impl.cc
index 62cf0d94..f5a277a 100644
--- a/chrome/browser/permissions/permission_request_impl.cc
+++ b/chrome/browser/permissions/permission_request_impl.cc
@@ -38,6 +38,8 @@
   if (!action_taken_) {
     PermissionUmaUtil::PermissionIgnored(permission_type_, GetGestureType(),
                                          request_origin_, profile_);
+    PermissionUmaUtil::RecordPermissionEmbargoStatus(
+        PermissionEmbargoStatus::NOT_EMBARGOED);
   }
 }
 
diff --git a/chrome/browser/permissions/permission_uma_util.cc b/chrome/browser/permissions/permission_uma_util.cc
index ebc8810..4a40418 100644
--- a/chrome/browser/permissions/permission_uma_util.cc
+++ b/chrome/browser/permissions/permission_uma_util.cc
@@ -358,6 +358,13 @@
   }
 }
 
+void PermissionUmaUtil::RecordPermissionEmbargoStatus(
+    PermissionEmbargoStatus embargo_status) {
+  UMA_HISTOGRAM_ENUMERATION("Permissions.AutoBlocker.EmbargoStatus",
+                            embargo_status,
+                            PermissionEmbargoStatus::STATUS_NUM);
+}
+
 void PermissionUmaUtil::RecordSafeBrowsingResponse(
     base::TimeDelta response_time,
     SafeBrowsingResponse response) {
diff --git a/chrome/browser/permissions/permission_uma_util.h b/chrome/browser/permissions/permission_uma_util.h
index 8a603ef2..e486c84 100644
--- a/chrome/browser/permissions/permission_uma_util.h
+++ b/chrome/browser/permissions/permission_uma_util.h
@@ -76,6 +76,15 @@
   int num_prior_ignores;
 };
 
+enum PermissionEmbargoStatus {
+  NOT_EMBARGOED = 0,
+  PERMISSIONS_BLACKLISTING = 1,
+  REPEATED_DISMISSALS = 2,
+
+  // Keep this at the end.
+  STATUS_NUM,
+};
+
 // Provides a convenient way of logging UMA for permission related operations.
 class PermissionUmaUtil {
  public:
@@ -125,8 +134,13 @@
                                 PermissionSourceUI source_ui,
                                 const GURL& revoked_origin,
                                 Profile* profile);
+
+  static void RecordPermissionEmbargoStatus(
+      PermissionEmbargoStatus embargo_status);
+
   static void RecordSafeBrowsingResponse(base::TimeDelta response_time,
                                          SafeBrowsingResponse response);
+
   // UMA specifically for when permission prompts are shown. This should be
   // roughly equivalent to the metrics above, however it is
   // useful to have separate UMA to a few reasons:
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 388df93ee..292b004 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -4381,6 +4381,11 @@
   EXPECT_TRUE(CheckResolveTimezoneByGeolocation(true, true));
   EXPECT_TRUE(manager->TimeZoneResolverShouldBeRunningForTests());
 
+  policy_value = 4 /* SEND_ALL_LOCATION_INFO */;
+  SetAndTestSystemTimezoneAutomaticDetectionPolicy(policy_value);
+  EXPECT_TRUE(CheckResolveTimezoneByGeolocation(true, true));
+  EXPECT_TRUE(manager->TimeZoneResolverShouldBeRunningForTests());
+
   policy_value = 1 /* DISABLED */;
   SetAndTestSystemTimezoneAutomaticDetectionPolicy(policy_value);
   EXPECT_TRUE(CheckResolveTimezoneByGeolocation(false, true));
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 96558e3..b732a247 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -201,7 +201,7 @@
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/chromeos/power/power_prefs.h"
 #include "chrome/browser/chromeos/preferences.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
 #include "chrome/browser/chromeos/resource_reporter/resource_reporter.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 #include "chrome/browser/chromeos/settings/device_settings_cache.h"
@@ -239,6 +239,7 @@
 #if defined(OS_WIN)
 #include "chrome/browser/apps/app_launch_for_metro_restart_win.h"
 #include "chrome/browser/component_updater/sw_reporter_installer_win.h"
+#include "chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.h"
 #endif
 
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
@@ -429,6 +430,7 @@
 #if defined(OS_WIN)
   app_metro_launch::RegisterPrefs(registry);
   component_updater::RegisterPrefsForSwReporter(registry);
+  desktop_ios_promotion::RegisterLocalPrefs(registry);
   password_manager::PasswordManager::RegisterLocalPrefs(registry);
 #endif
 
@@ -580,7 +582,7 @@
   chromeos::MultiProfileUserController::RegisterProfilePrefs(registry);
   chromeos::PinStorage::RegisterProfilePrefs(registry);
   chromeos::Preferences::RegisterProfilePrefs(registry);
-  chromeos::PrinterPrefManager::RegisterProfilePrefs(registry);
+  chromeos::PrintersManager::RegisterProfilePrefs(registry);
   chromeos::RegisterQuickUnlockProfilePrefs(registry);
   chromeos::SAMLOfflineSigninLimiter::RegisterProfilePrefs(registry);
   chromeos::ServicesCustomizationDocument::RegisterProfilePrefs(registry);
@@ -597,6 +599,7 @@
 
 #if defined(OS_WIN)
   component_updater::RegisterProfilePrefsForSwReporter(registry);
+  desktop_ios_promotion::RegisterProfilePrefs(registry);
   NetworkProfileBubble::RegisterProfilePrefs(registry);
 #endif
 
diff --git a/chrome/browser/profile_resetter/triggered_profile_resetter_win_unittest.cc b/chrome/browser/profile_resetter/triggered_profile_resetter_win_unittest.cc
index a2cc1b9..464c114 100644
--- a/chrome/browser/profile_resetter/triggered_profile_resetter_win_unittest.cc
+++ b/chrome/browser/profile_resetter/triggered_profile_resetter_win_unittest.cc
@@ -27,7 +27,8 @@
 class TriggeredProfileResetterTest : public testing::Test {
  protected:
   void SetUp() override {
-    override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
 
     // Activate the triggered reset field trial for these tests.
     field_trial_list_.reset(
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 141e2aa5..d775c529 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -64,7 +64,6 @@
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/thumbnails/thumbnail_service_factory.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
-#include "chrome/browser/ui/desktop_ios_promotion/sms_service_factory.h"
 #include "chrome/browser/ui/find_bar/find_bar_state_factory.h"
 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
 #include "chrome/browser/ui/tabs/pinned_tab_service_factory.h"
@@ -123,7 +122,7 @@
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/printer_detector/printer_detector_factory.h"
 #include "chrome/browser/chromeos/printing/cups_print_job_manager_factory.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/extensions/api/platform_keys/verify_trust_api.h"
 #endif
 
@@ -137,6 +136,7 @@
 
 #if defined(OS_WIN)
 #include "chrome/browser/profile_resetter/triggered_profile_resetter_factory.h"
+#include "chrome/browser/ui/desktop_ios_promotion/sms_service_factory.h"
 #endif
 
 #if BUILDFLAG(ENABLE_SPELLCHECK)
@@ -224,7 +224,7 @@
 #endif
   NotifierStateTrackerFactory::GetInstance();
   data_use_measurement::ChromeDataUseAscriberServiceFactory::GetInstance();
-#if !defined(OS_ANDROID)
+#if defined(OS_WIN)
   SMSServiceFactory::GetInstance();
 #endif
   dom_distiller::DomDistillerServiceFactory::GetInstance();
@@ -237,7 +237,7 @@
 #if defined(OS_CHROMEOS)
   chromeos::PrinterDetectorFactory::GetInstance();
   chromeos::CupsPrintJobManagerFactory::GetInstance();
-  chromeos::PrinterPrefManagerFactory::GetInstance();
+  chromeos::PrintersManagerFactory::GetInstance();
   extensions::VerifyTrustAPI::GetFactoryInstance();
 #endif
   FaviconServiceFactory::GetInstance();
diff --git a/chrome/browser/renderer_host/pepper/device_id_fetcher.cc b/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
index ddca7f8..2e441d0 100644
--- a/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
+++ b/chrome/browser/renderer_host/pepper/device_id_fetcher.cc
@@ -7,11 +7,12 @@
 #include "base/files/file_util.h"
 #include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
-#include "components/prefs/pref_service.h"
 #include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_ppapi_host.h"
 #include "content/public/browser/browser_thread.h"
@@ -125,12 +126,11 @@
 #if defined(OS_CHROMEOS)
   // Try the legacy path first for ChromeOS. We pass the new salt in as well
   // in case the legacy id doesn't exist.
-  BrowserThread::PostBlockingPoolTask(
-      FROM_HERE,
-      base::Bind(&DeviceIDFetcher::LegacyComputeOnBlockingPool,
-                 this,
-                 profile->GetPath(),
-                 salt));
+  base::PostTaskWithTraits(FROM_HERE,
+                           base::TaskTraits().MayBlock().WithPriority(
+                               base::TaskPriority::BACKGROUND),
+                           base::Bind(&DeviceIDFetcher::LegacyComputeAsync,
+                                      this, profile->GetPath(), salt));
 #else
   // Get the machine ID and call ComputeOnUIThread with salt + machine_id.
   GetMachineIDAsync(
@@ -179,9 +179,8 @@
 // TODO(raymes): This is temporary code to migrate ChromeOS devices to the new
 // scheme for generating device IDs. Delete this once we are sure most ChromeOS
 // devices have been migrated.
-void DeviceIDFetcher::LegacyComputeOnBlockingPool(
-    const base::FilePath& profile_path,
-    const std::string& salt) {
+void DeviceIDFetcher::LegacyComputeAsync(const base::FilePath& profile_path,
+                                         const std::string& salt) {
   std::string id;
   // First check if the legacy device ID file exists on ChromeOS. If it does, we
   // should just return that.
diff --git a/chrome/browser/renderer_host/pepper/device_id_fetcher.h b/chrome/browser/renderer_host/pepper/device_id_fetcher.h
index 2cd71c1..48276a84 100644
--- a/chrome/browser/renderer_host/pepper/device_id_fetcher.h
+++ b/chrome/browser/renderer_host/pepper/device_id_fetcher.h
@@ -54,8 +54,8 @@
                          const std::string& machine_id);
 
   // Legacy method used to get the device ID for ChromeOS.
-  void LegacyComputeOnBlockingPool(const base::FilePath& profile_path,
-                                   const std::string& salt);
+  void LegacyComputeAsync(const base::FilePath& profile_path,
+                          const std::string& salt);
 
   // Runs the callback passed into Start() on the IO thread with the device ID
   // or the empty string on failure.
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/active_indicator.js b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/active_indicator.js
index c945194..4db51b4 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/active_indicator.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/active_indicator.js
@@ -149,11 +149,11 @@
     '  visibility: hidden !important;' +
     '}' +
     '.cvox_indicator_pulsing {' +
-    '  -webkit-animation: ' +
+    '  animation: ' +
     // NOTE(deboer): This animation is 0 seconds long to work around
     // http://crbug.com/128993.  Revert it to 2s when the bug is fixed.
     '      cvox_indicator_pulsing_animation 0s 2 alternate !important;' +
-    '  -webkit-animation-timing-function: ease-in-out !important;' +
+    '  animation-timing-function: ease-in-out !important;' +
     '}' +
     '.cvox_indicator_region {' +
     '  opacity: 0 !important;' +
@@ -194,7 +194,7 @@
     '.cvox_indicator_bottom {' +
     '  border-radius: 0 0 inherit inherit !important;' +
     '}' +
-    '@-webkit-keyframes cvox_indicator_pulsing_animation {' +
+    '@keyframes cvox_indicator_pulsing_animation {' +
     '   0% {opacity: 1.0}' +
     '  50% {opacity: 0.5}' +
     ' 100% {opacity: 1.0}' +
diff --git a/chrome/browser/resources/chromeos/login/oobe_a11y_option.css b/chrome/browser/resources/chromeos/login/oobe_a11y_option.css
index 280b5b8..0911b07 100644
--- a/chrome/browser/resources/chromeos/login/oobe_a11y_option.css
+++ b/chrome/browser/resources/chromeos/login/oobe_a11y_option.css
@@ -14,10 +14,10 @@
 }
 
 paper-toggle-button {
-  /* paper-toggle-button has fixed width of 36px. Make it 32. */
-  -webkit-transform: scale(.8888);
   min-height: 20px;
   min-width: 32px;
+  /* paper-toggle-button has fixed width of 36px. Make it 32. */
+  transform: scale(.8888);
 }
 
 #titleContainer {
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen.css b/chrome/browser/resources/chromeos/login/oobe_screen.css
index f0cffef..5569a69 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen.css
+++ b/chrome/browser/resources/chromeos/login/oobe_screen.css
@@ -15,7 +15,7 @@
 }
 
 .step.animated:not(.faded) {
-  -webkit-transition: -webkit-transform 200ms ease-in-out,
+  -webkit-transition: transform 200ms ease-in-out,
                       opacity 200ms ease-in-out,
                       visibility 200ms ease-in-out;
 }
@@ -31,11 +31,11 @@
 }
 
 .step.right {
-  -webkit-transform: translateX(50px);
+  transform: translateX(50px);
 }
 
 .step.left {
-  -webkit-transform: translateX(-50px)
+  transform: translateX(-50px)
 }
 
 .step.fullscreen {
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.css b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.css
index df17705..45194a6f 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_user_image.css
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_user_image.css
@@ -105,7 +105,7 @@
 }
 
 #user-image-preview-img.animated-transform {
-  -webkit-transition: -webkit-transform 200ms linear;
+  -webkit-transition: transform 200ms linear;
 }
 
 .camera.live #user-image-preview-img {
@@ -113,7 +113,7 @@
 }
 
 .camera.flip-x #user-image-preview-img {
-  -webkit-transform: rotateY(180deg);
+  transform: rotateY(180deg);
 }
 
 .default-image #user-image-preview-img {
@@ -134,7 +134,7 @@
 }
 
 #user-image-stream-crop {
-  -webkit-transition: -webkit-transform 200ms linear;
+  -webkit-transition: transform 200ms linear;
   height: 220px;
   overflow: hidden;
   position: relative;
@@ -142,7 +142,7 @@
 }
 
 .flip-x #user-image-stream-crop {
-  -webkit-transform: rotateY(180deg);
+  transform: rotateY(180deg);
 }
 
 /* TODO(ivankr): specify dimensions from real capture size. */
@@ -185,7 +185,7 @@
 
 /* TODO(merkulova): remove when webkit crbug.com/126479 is fixed. */
 .flip-trick {
-  -webkit-transform: translateZ(1px);
+  transform: translateZ(1px);
 }
 
 html[dir=rtl] #flip-photo {
@@ -221,10 +221,10 @@
 }
 
 #user-image-preview .perspective-box {
-  -webkit-perspective: 600px;
   border: solid 1px #cacaca;
   border-radius: 4px;
   padding: 2px;
+  perspective: 600px;
   width: 220px;
 }
 
diff --git a/chrome/browser/resources/chromeos/login/screen_error_message.css b/chrome/browser/resources/chromeos/login/screen_error_message.css
index 986a4a90..b85da668 100644
--- a/chrome/browser/resources/chromeos/login/screen_error_message.css
+++ b/chrome/browser/resources/chromeos/login/screen_error_message.css
@@ -47,13 +47,13 @@
 }
 
 .error-header {
-  /* A hack used to prevent aliasing on High-DPI displays. */
-  -webkit-transform: scale3d(1,1,1);
   background-clip: padding-box;
   background-color: white;
   border-bottom: 1px solid rgb(238,238,238);
   padding: 71px 20px 50px;
   text-align: center;
+  /* A hack used to prevent aliasing on High-DPI displays. */
+  transform: scale3d(1,1,1);
 }
 
 .error-icon {
@@ -112,7 +112,7 @@
   display: block;
 }
 
-@-webkit-keyframes connecting-indicator-ellipsis {
+@keyframes connecting-indicator-ellipsis {
   0% {
     opacity: 0;
   }
@@ -128,15 +128,15 @@
 }
 
 #connecting-indicator-ellipsis-1 {
-  -webkit-animation: connecting-indicator-ellipsis 3s 0 infinite;
+  animation: connecting-indicator-ellipsis 3s 0 infinite;
 }
 
 #connecting-indicator-ellipsis-2 {
-  -webkit-animation: connecting-indicator-ellipsis 3s 500ms infinite;
+  animation: connecting-indicator-ellipsis 3s 500ms infinite;
 }
 
 #connecting-indicator-ellipsis-3 {
-  -webkit-animation: connecting-indicator-ellipsis 3s 1s infinite;
+  animation: connecting-indicator-ellipsis 3s 1s infinite;
 }
 
 #error-navigation {
diff --git a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css
index baf3c24..7bf3345 100644
--- a/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css
+++ b/chrome/browser/resources/chromeos/login/screen_supervised_user_creation.css
@@ -413,7 +413,7 @@
 }
 
 #supervised-user-creation-image-preview-img.animated-transform {
-  -webkit-transition: -webkit-transform 200ms linear;
+  -webkit-transition: transform 200ms linear;
 }
 
 .camera.live #supervised-user-creation-image-preview-img {
@@ -421,7 +421,7 @@
 }
 
 .camera.flip-x #supervised-user-creation-image-preview-img {
-  -webkit-transform: rotateY(180deg);
+  transform: rotateY(180deg);
 }
 
 .default-image #supervised-user-creation-image-preview-img {
@@ -442,7 +442,7 @@
 }
 
 #supervised-user-creation-image-stream-crop {
-  -webkit-transition: -webkit-transform 200ms linear;
+  -webkit-transition: transform 200ms linear;
   height: 220px;
   overflow: hidden;
   position: relative;
@@ -450,7 +450,7 @@
 }
 
 .flip-x #supervised-user-creation-image-stream-crop {
-  -webkit-transform: rotateY(180deg);
+  transform: rotateY(180deg);
 }
 
 .supervised-user-creation-image-stream {
@@ -491,7 +491,7 @@
 
 /* TODO(merkulova): remove when webkit crbug.com/126479 is fixed. */
 .flip-trick {
-  -webkit-transform: translateZ(1px);
+  transform: translateZ(1px);
 }
 
 html[dir=rtl] #supervised-user-creation-flip-photo {
@@ -527,11 +527,11 @@
 }
 
 #supervised-user-creation-image-preview .perspective-box {
-  -webkit-perspective: 600px;
-   border: solid 1px #cacaca;
-   border-radius: 4px;
-   padding: 2px;
-   width: 220px;
+  border: solid 1px #cacaca;
+  border-radius: 4px;
+  padding: 2px;
+  perspective: 600px;
+  width: 220px;
 }
 
 .supervised-user-creation-image-stream-area .spinner {
diff --git a/chrome/browser/resources/history/history.css b/chrome/browser/resources/history/history.css
index 1d4da44..b64b6b0 100644
--- a/chrome/browser/resources/history/history.css
+++ b/chrome/browser/resources/history/history.css
@@ -120,11 +120,11 @@
 
 html[dir='rtl'] #range-next,
 #range-previous {
-  -webkit-transform: scalex(-1);
+  transform: scalex(-1);
 }
 
 html[dir='rtl'] #range-previous {
-  -webkit-transform: scaleX(1);
+  transform: scaleX(1);
 }
 
 #range-today {
@@ -480,8 +480,7 @@
 }
 
 .site-domain-arrow {
-  -webkit-transform: rotate(0);
-  -webkit-transition: -webkit-transform 300ms linear;
+  -webkit-transition: transform 300ms linear;
   background: url(../disclosure_triangle_small.png) no-repeat;
   background-position: 5px 5px;
   color: rgb(143, 143, 143);
@@ -489,15 +488,16 @@
   margin-right: 2px;
   opacity: 0.58;
   text-align: center;
+  transform: rotate(0);
   width: 21px;
 }
 
 html[dir='rtl'] .site-domain-arrow {
-  -webkit-transform: rotate(180deg);
+  transform: rotate(180deg);
 }
 
 html .expand .site-domain-arrow {
-  -webkit-transform: rotate(90deg);
+  transform: rotate(90deg);
 }
 
 .entry .bookmark-section {
diff --git a/chrome/browser/resources/hotword_audio_verification/style.css b/chrome/browser/resources/hotword_audio_verification/style.css
index 664ad5c..233ad31 100644
--- a/chrome/browser/resources/hotword_audio_verification/style.css
+++ b/chrome/browser/resources/hotword_audio_verification/style.css
@@ -174,13 +174,13 @@
   color: rgba(66, 133, 244, 1);
 }
 
-@-webkit-keyframes rotate {
-  from { -webkit-transform: rotate(0); }
-  to { -webkit-transform: rotate(359deg); }
+@keyframes rotate {
+  from { transform: rotate(0); }
+  to { transform: rotate(359deg); }
 }
 
 .train.listening .icon {
-  -webkit-animation: rotate 2s linear infinite;
+  animation: rotate 2s linear infinite;
   background: -webkit-image-set(
       url(../images/placeholder-loader-1x.png) 1x,
       url(../images/placeholder-loader-2x.png) 2x)
@@ -290,7 +290,7 @@
 }
 
 .buttonbar .message.wait .icon {
-  -webkit-animation: rotate 2s linear infinite;
+  animation: rotate 2s linear infinite;
   background: -webkit-image-set(
       url(../images/placeholder-loader-1x.png) 1x,
       url(../images/placeholder-loader-2x.png) 2x)
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index 2584a92..629ace4 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -147,8 +147,8 @@
 }
 
 .port-icon.transient {
-  -webkit-transform: scale(1.2);
   background-color: orange;
+  transform: scale(1.2);
 }
 
 .port-number {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 40493ba1..ab2bf92 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -50,8 +50,7 @@
 }
 
 #fakebox {
-  -webkit-transform: translate3d(0, 0, 0);
-  -webkit-transition: -webkit-transform 100ms linear, border-color 100ms linear;
+  -webkit-transition: transform 100ms linear, border-color 100ms linear;
   background-color: #fff;
   border: 1px solid rgb(185, 185, 185);
   border-radius: 1px;
@@ -62,6 +61,7 @@
   line-height: 36px;
   max-width: 672px;
   position: relative;
+  transform: translate3d(0, 0, 0);
   /* #fakebox width (here and below) should be 2px less than #mv-tiles
      to account for its border. */
   width: 298px;
@@ -136,7 +136,7 @@
   right: 9px;
 }
 
-@-webkit-keyframes blink {
+@keyframes blink {
   0% {
     opacity: 1;
   }
@@ -155,7 +155,7 @@
 }
 
 body.fakebox-focused #cursor {
-  -webkit-animation: blink 1.3s step-end infinite;
+  animation: blink 1.3s step-end infinite;
   visibility: inherit;
 }
 
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index 349fcd2..568ab6a 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -79,7 +79,7 @@
 
 .mv-tile {
   -webkit-transition-duration: 200ms;
-  -webkit-transition-property: -webkit-transform, border,
+  -webkit-transition-property: transform, border,
     box-shadow, margin, opacity, width;
   cursor: pointer;
 }
@@ -90,9 +90,9 @@
 }
 
 .mv-tile.blacklisted {
-  -webkit-transform: scale(0, 0);
   border: none !important;
   margin: 0;
+  transform: scale(0, 0);
   width: 0;
 }
 
@@ -105,10 +105,10 @@
 }
 
 .mv-tile.mv-blacklist {
-  -webkit-transform: scale(0, 0);
-  -webkit-transform-origin: 0 41px;
   margin-left: 0;
   margin-right: 0;
+  transform: scale(0, 0);
+  transform-origin: 0 41px;
   width: 0;
 }
 
diff --git a/chrome/browser/resources/md_history/app.html b/chrome/browser/resources/md_history/app.html
index 43865e79..7b38634 100644
--- a/chrome/browser/resources/md_history/app.html
+++ b/chrome/browser/resources/md_history/app.html
@@ -35,10 +35,6 @@
         position: relative;
       }
 
-      :host([grouped_]) #main-container {
-        height: calc(100% - var(--toolbar-grouped-height));
-      }
-
       #content-side-bar {
         float: left;
       }
@@ -74,19 +70,14 @@
     </history-query-manager>
     <history-router id="router"
         selected-page="{{selectedPage_}}"
-        grouped="[[grouped_]]"
         query-state="[[queryState_]]">
     </history-router>
     <history-toolbar id="toolbar"
-        grouped-offset="[[queryState_.groupedOffset]]"
-        grouped-range="[[queryState_.range]]"
         has-drawer="[[hasDrawer_]]"
         has-more-results="[[!queryResult_.info.finished]]"
-        is-grouped-mode="[[grouped_]]"
         query-info="[[queryResult_.info]]"
         querying="[[queryState_.querying]]"
         search-term="[[queryState_.searchTerm]]"
-        show-grouped-controls="[[!syncedTabsSelected_(selectedPage_)]]"
         show-menu-promo="[[showMenuPromo_]]"
         show-sync-notice="[[showSyncNotice_(hasSyncedResults, selectedPage_)]]"
         spinner-active="[[shouldShowSpinner_(queryState_.querying,
@@ -104,8 +95,7 @@
           selected="[[getSelectedPage_(selectedPage_, items)]]"
           items="{{items}}">
         <history-list-container id="history" query-state="[[queryState_]]"
-            query-result="[[queryResult_]]" grouped="[[grouped_]]"
-            path="history">
+            query-result="[[queryResult_]]" path="history">
         </history-list-container>
         <template is="dom-if" if="[[syncedTabsSelected_(selectedPage_)]]">
           <history-synced-device-manager id="synced-devices"
diff --git a/chrome/browser/resources/md_history/app.js b/chrome/browser/resources/md_history/app.js
index b67bf99d..afe3b04 100644
--- a/chrome/browser/resources/md_history/app.js
+++ b/chrome/browser/resources/md_history/app.js
@@ -33,12 +33,6 @@
       observer: 'selectedPageChanged_',
     },
 
-    // Whether domain-grouped history is enabled.
-    grouped_: {
-      type: Boolean,
-      reflectToAttribute: true,
-    },
-
     /** @type {!QueryResult} */
     queryResult_: {
       type: Object,
@@ -106,8 +100,6 @@
 
   /** @override */
   attached: function() {
-    this.grouped_ = loadTimeData.getBoolean('groupByDomain');
-
     cr.ui.decorate('command', cr.ui.Command);
     this.boundOnCanExecute_ = this.onCanExecute_.bind(this);
     this.boundOnCommand_ = this.onCommand_.bind(this);
@@ -234,9 +226,6 @@
     e = /** @type {cr.ui.CanExecuteEvent} */ (e);
     switch (e.command.id) {
       case 'find-command':
-      case 'toggle-grouped':
-        e.canExecute = true;
-        break;
       case 'slash-command':
         e.canExecute = !this.$.toolbar.searchField.isSearchFocused();
         break;
@@ -253,10 +242,8 @@
   onCommand_: function(e) {
     if (e.command.id == 'find-command' || e.command.id == 'slash-command')
       this.focusToolbarSearchField();
-    if (e.command.id == 'delete-command')
+    else if (e.command.id == 'delete-command')
       this.deleteSelected();
-    if (e.command.id == 'toggle-grouped')
-      this.grouped_ = !this.grouped_;
   },
 
   /**
@@ -313,9 +300,7 @@
     return hasSyncedResults && selectedPage != 'syncedTabs';
   },
 
-  /**
-   * @private
-   */
+  /** @private */
   selectedPageChanged_: function() {
     this.unselectAll();
     this.historyViewChanged_();
@@ -377,17 +362,7 @@
             HistoryPageViewHistogram.SIGNIN_PROMO;
         break;
       default:
-        switch (this.queryState_.range) {
-          case HistoryRange.ALL_TIME:
-            histogramValue = HistoryPageViewHistogram.HISTORY;
-            break;
-          case HistoryRange.WEEK:
-            histogramValue = HistoryPageViewHistogram.GROUPED_WEEK;
-            break;
-          case HistoryRange.MONTH:
-            histogramValue = HistoryPageViewHistogram.GROUPED_MONTH;
-            break;
-        }
+        histogramValue = HistoryPageViewHistogram.HISTORY;
         break;
     }
 
diff --git a/chrome/browser/resources/md_history/compiled_resources2.gyp b/chrome/browser/resources/md_history/compiled_resources2.gyp
index 964f55f..e67bdc7f 100644
--- a/chrome/browser/resources/md_history/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_history/compiled_resources2.gyp
@@ -24,17 +24,6 @@
       'includes': ['../../../../third_party/closure_compiler/include_js.gypi'],
     },
     {
-      'target_name': 'grouped_list',
-      'dependencies': [
-        '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-collapse/compiled_resources2.gyp:iron-collapse-extracted',
-        'constants',
-        'history_item',
-        'history_list_behavior',
-        '../history/compiled_resources2.gyp:externs',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
       'target_name': 'history_item',
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon',
@@ -100,7 +89,6 @@
         '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/compiled_resources2.gyp:iron-a11y-announcer-extracted',
         '<(DEPTH)/ui/webui/resources/cr_elements/cr_lazy_render/compiled_resources2.gyp:cr_lazy_render',
         'externs',
-        'grouped_list',
         'history_list',
         'history_list_behavior',
         '../history/compiled_resources2.gyp:externs',
diff --git a/chrome/browser/resources/md_history/constants.js b/chrome/browser/resources/md_history/constants.js
index 9971923..550f0ce 100644
--- a/chrome/browser/resources/md_history/constants.js
+++ b/chrome/browser/resources/md_history/constants.js
@@ -33,8 +33,8 @@
  */
 var HistoryPageViewHistogram = {
   HISTORY: 0,
-  GROUPED_WEEK: 1,
-  GROUPED_MONTH: 2,
+  DEPRECATED_GROUPED_WEEK: 1,
+  DEPRECATED_GROUPED_MONTH: 2,
   SYNCED_TABS: 3,
   SIGNIN_PROMO: 4,
   END: 5,  // Should always be last.
@@ -63,12 +63,3 @@
   HIDE_FOR_NOW: 10,
   LIMIT: 11  // Should always be the last one.
 };
-
-/**
- * @enum {number}
- */
-var HistoryRange = {
-  ALL_TIME: 0,
-  WEEK: 1,
-  MONTH: 2,
-};
diff --git a/chrome/browser/resources/md_history/externs.js b/chrome/browser/resources/md_history/externs.js
index 3dfb80d..04f5931 100644
--- a/chrome/browser/resources/md_history/externs.js
+++ b/chrome/browser/resources/md_history/externs.js
@@ -9,10 +9,8 @@
 
 // Types:
 /**
- * @typedef {{groupedOffset: number,
- *            incremental: boolean,
+ * @typedef {{incremental: boolean,
  *            querying: boolean,
- *            range: HistoryRange,
  *            searchTerm: string}}
  */
 var QueryState;
diff --git a/chrome/browser/resources/md_history/grouped_list.html b/chrome/browser/resources/md_history/grouped_list.html
deleted file mode 100644
index 9986263..0000000
--- a/chrome/browser/resources/md_history/grouped_list.html
+++ /dev/null
@@ -1,119 +0,0 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
-<link rel="import" href="chrome://history/constants.html">
-<link rel="import" href="chrome://history/history_item.html">
-<link rel="import" href="chrome://history/history_list_behavior.html">
-<link rel="import" href="chrome://history/shared_style.html">
-
-<dom-module id="history-grouped-list">
-  <template>
-    <style include="shared-style">
-      :host {
-        display: block;
-        overflow: auto;
-        position: relative;
-      }
-
-      #main-container {
-        @apply(--card-sizing);
-        align-items: center;
-        display: flex;
-        flex-direction: column;
-        padding-top: var(--first-card-padding-top);
-      }
-
-      .domain-heading {
-        align-items: center;
-        display: flex;
-        height: var(--item-height);
-        padding: 0 20px;
-      }
-
-      .domain-count {
-        color: var(--secondary-text-color);
-        padding-left: 10px;
-      }
-
-      .domain-heading-text {
-        display: flex;
-      }
-
-      .group-container {
-        @apply(--shadow-elevation-2dp);
-        background: #fff;
-        border-radius: 2px;
-        margin-bottom: var(--card-padding-between);
-        max-width: var(--card-max-width);
-        min-width: var(--card-min-width);
-        width: 100%;
-      }
-
-      .card-title {
-        margin-bottom: var(--card-first-last-item-padding);
-      }
-
-      .domain-heading-text {
-        flex: 1 1 0;
-      }
-
-      .dropdown-indicator {
-        max-width: 16px;
-      }
-
-      history-item {
-        padding-left: 20px;
-      }
-    </style>
-    <div id="no-results" class="centered-message"
-        hidden$="[[hasResults(groupedHistoryData_.length)]]">
-      [[noResultsMessage(searchedTerm, querying)]]
-    </div>
-    <div id="main-container"
-        hidden$="[[!hasResults(groupedHistoryData_.length)]]">
-      <template is="dom-repeat" items="[[groupedHistoryData_]]" as="group"
-          initial-count="1" index-as="groupIndex">
-        <div class="group-container">
-          <div class="card-title">
-            [[group.title]]
-          </div>
-
-          <template is="dom-repeat" items="[[group.domains]]" as="domain"
-              initial-count="10" index-as="domainIndex">
-            <div>
-              <div class="domain-heading" on-tap="toggleDomainExpanded_">
-                <div class="domain-heading-text">
-                  <div class="website-icon"
-                      style="[[getWebsiteIconStyle_(domain)]]"></div>
-                  <span>[[domain.domain]]</span>
-                  <span class="domain-count">[[domain.visits.length]]</span>
-                </div>
-                <iron-icon icon="[[getDropdownIcon_(domain.expanded)]]"
-                    class="dropdown-indicator"></iron-icon>
-              </div>
-              <iron-collapse opened="{{domain.expanded}}" id="collapse">
-                <template is="dom-if" if="[[domain.rendered]]">
-                  <template is="dom-repeat" items="[[domain.visits]]"
-                      as="item" initial-count="5" index-as="itemIndex">
-                    <history-item item="[[item]]"
-                        selected="{{item.selected}}"
-                        has-time-gap="[[needsTimeGap_(
-                            groupIndex, domainIndex, itemIndex)]]"
-                        search-term="[[searchedTerm]]"
-                        number-of-items="[[historyData.length]]"
-                        path="[[pathForItem_(
-                            groupIndex, domainIndex, itemIndex)]]"
-                        embedded>
-                    </history-item>
-                  </template>
-                </template>
-              </iron-collapse>
-            </div>
-          </template>
-        </div>
-      </template>
-    </div>
-    </template>
-  <script src="chrome://history/grouped_list.js"></script>
-</dom-module>
diff --git a/chrome/browser/resources/md_history/grouped_list.js b/chrome/browser/resources/md_history/grouped_list.js
deleted file mode 100644
index 44b3b94..0000000
--- a/chrome/browser/resources/md_history/grouped_list.js
+++ /dev/null
@@ -1,193 +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.
-
-/**
- * @typedef {{domain: string,
- *            visits: !Array<HistoryEntry>,
- *            rendered: boolean,
- *            expanded: boolean}}
- */
-var HistoryDomain;
-
-/**
- * @typedef {{title: string,
- *            domains: !Array<HistoryDomain>}}
- */
-var HistoryGroup;
-
-Polymer({
-  is: 'history-grouped-list',
-
-  behaviors: [HistoryListBehavior],
-
-  properties: {
-    searchedTerm: {
-      type: String,
-      value: '',
-    },
-
-    /**
-     * @type {Array<HistoryGroup>}
-     */
-    groupedHistoryData_: Array,
-
-    // An array of history entries in reverse chronological order.
-    historyData: Array,
-
-    queryInterval: String,
-
-    range: Number,
-  },
-
-  observers: ['updateGroupedHistoryData_(historyData)'],
-
-  /**
-   * @param {!Array<!HistoryEntry>} results
-   * @param {boolean} incremental
-   * @param {boolean} finished
-   */
-  addNewResults: function(results, incremental, finished) {
-    this.historyData = results;
-  },
-
-  /**
-   * Make a list of domains from visits.
-   * @param {!Array<!HistoryEntry>} visits
-   * @return {!Array<!HistoryDomain>}
-   */
-  createHistoryDomains_: function(visits) {
-    var domainIndexes = {};
-    var domains = [];
-
-    // Group the visits into a dictionary and generate a list of domains.
-    for (var i = 0, visit; visit = visits[i]; i++) {
-      var domain = visit.domain;
-      if (domainIndexes[domain] == undefined) {
-        domainIndexes[domain] = domains.length;
-        domains.push({
-          domain: domain,
-          visits: [],
-          expanded: false,
-          rendered: false,
-        });
-      }
-      domains[domainIndexes[domain]].visits.push(visit);
-    }
-    var sortByVisits = function(a, b) {
-      return b.visits.length - a.visits.length;
-    };
-    domains.sort(sortByVisits);
-
-    return domains;
-  },
-
-  /** @private */
-  updateGroupedHistoryData_: function() {
-    if (this.historyData.length == 0) {
-      this.groupedHistoryData_ = [];
-      return;
-    }
-
-    if (this.range == HistoryRange.WEEK) {
-      // Group each day into a list of results.
-      var days = [];
-      var currentDayVisits = [this.historyData[0]];
-
-      var pushCurrentDay = function() {
-        days.push({
-          title: this.searchedTerm ? currentDayVisits[0].dateShort :
-                                     currentDayVisits[0].dateRelativeDay,
-          domains: this.createHistoryDomains_(currentDayVisits),
-        });
-      }.bind(this);
-
-      var visitsSameDay = function(a, b) {
-        if (this.searchedTerm)
-          return a.dateShort == b.dateShort;
-
-        return a.dateRelativeDay == b.dateRelativeDay;
-      }.bind(this);
-
-      for (var i = 1; i < this.historyData.length; i++) {
-        var visit = this.historyData[i];
-        if (!visitsSameDay(visit, currentDayVisits[0])) {
-          pushCurrentDay();
-          currentDayVisits = [];
-        }
-        currentDayVisits.push(visit);
-      }
-      pushCurrentDay();
-
-      this.groupedHistoryData_ = days;
-    } else if (this.range == HistoryRange.MONTH) {
-      // Group each all visits into a single list.
-      this.groupedHistoryData_ = [{
-        title: this.queryInterval,
-        domains: this.createHistoryDomains_(this.historyData)
-      }];
-    }
-  },
-
-  /**
-   * @param {{model:Object, currentTarget:IronCollapseElement}} e
-   */
-  toggleDomainExpanded_: function(e) {
-    var collapse = e.currentTarget.parentNode.querySelector('iron-collapse');
-    e.model.set('domain.rendered', true);
-
-    // Give the history-items time to render.
-    setTimeout(function() {
-      collapse.toggle()
-    }, 0);
-  },
-
-  /**
-   * Check whether the time difference between the given history item and the
-   * next one is large enough for a spacer to be required.
-   * @param {number} groupIndex
-   * @param {number} domainIndex
-   * @param {number} itemIndex
-   * @return {boolean} Whether or not time gap separator is required.
-   * @private
-   */
-  needsTimeGap_: function(groupIndex, domainIndex, itemIndex) {
-    var visits =
-        this.groupedHistoryData_[groupIndex].domains[domainIndex].visits;
-
-    return md_history.HistoryItem.needsTimeGap(
-        visits, itemIndex, this.searchedTerm);
-  },
-
-  /**
-   * @param {number} groupIndex
-   * @param {number} domainIndex
-   * @param {number} itemIndex
-   * @return {string}
-   * @private
-   */
-  pathForItem_: function(groupIndex, domainIndex, itemIndex) {
-    return [
-      'groupedHistoryData_', groupIndex, 'domains', domainIndex, 'visits',
-      itemIndex
-    ].join('.');
-  },
-
-  /**
-   * @param {HistoryDomain} domain
-   * @return {string}
-   * @private
-   */
-  getWebsiteIconStyle_: function(domain) {
-    return 'background-image: ' + cr.icon.getFavicon(domain.visits[0].url);
-  },
-
-  /**
-   * @param {boolean} expanded
-   * @return {string}
-   * @private
-   */
-  getDropdownIcon_: function(expanded) {
-    return expanded ? 'cr:expand-less' : 'cr:expand-more';
-  },
-});
diff --git a/chrome/browser/resources/md_history/history.html b/chrome/browser/resources/md_history/history.html
index 12502ad5..e9e4b1c 100644
--- a/chrome/browser/resources/md_history/history.html
+++ b/chrome/browser/resources/md_history/history.html
@@ -78,7 +78,6 @@
 </if>
   <command id="delete-command" shortcut="Delete Backspace">
   <command id="slash-command" shortcut="/">
-  <command id="toggle-grouped" shortcut="Ctrl|Alt|Shift|G">
 
   <link rel="import" href="chrome://resources/html/util.html">
   <link rel="import" href="chrome://resources/html/load_time_data.html">
diff --git a/chrome/browser/resources/md_history/history_item.html b/chrome/browser/resources/md_history/history_item.html
index cbbd233a..f45440c2 100644
--- a/chrome/browser/resources/md_history/history_item.html
+++ b/chrome/browser/resources/md_history/history_item.html
@@ -29,7 +29,7 @@
         padding: 0;
       }
 
-      :host(:not([embedded])) #main-container {
+      #main-container {
         position: relative;
       }
 
@@ -183,10 +183,6 @@
         top: 0;
       }
 
-      :host([embedded]) #background {
-        display: none;
-      }
-
       :host(:not([is-card-start])) #background {
         top: -5px; /* Draw the box shadow up the full edge of the background. */
       }
diff --git a/chrome/browser/resources/md_history/history_item.js b/chrome/browser/resources/md_history/history_item.js
index 4dd5d354..4dca56c9 100644
--- a/chrome/browser/resources/md_history/history_item.js
+++ b/chrome/browser/resources/md_history/history_item.js
@@ -100,13 +100,6 @@
         reflectToAttribute: true,
       },
 
-      // True if the item is being displayed embedded in another element and
-      // should not manage its own borders or size.
-      embedded: {
-        type: Boolean,
-        reflectToAttribute: true,
-      },
-
       /** @type {Element} */
       lastFocused: {
         type: Object,
diff --git a/chrome/browser/resources/md_history/history_toolbar.html b/chrome/browser/resources/md_history/history_toolbar.html
index 2b5708c1..8cebe69 100644
--- a/chrome/browser/resources/md_history/history_toolbar.html
+++ b/chrome/browser/resources/md_history/history_toolbar.html
@@ -7,8 +7,7 @@
 <link rel="import" href="chrome://history/icons.html">
 <link rel="import" href="chrome://history/shared_style.html">
 
-<!-- Lazy loaded: iron-dropdown, paper-button, paper-icon-button-light,
-  paper-tab, paper-tabs. -->
+<!-- Lazy loaded: iron-dropdown, paper-button, paper-icon-button-light. -->
 
 <dom-module id="history-toolbar">
   <template>
@@ -108,82 +107,6 @@
         -webkit-margin-end: 24px;
         -webkit-margin-start: 2px;
       }
-
-      /* Grouped toolbar. */
-
-      paper-tabs {
-        --paper-tabs: {
-          font-size: inherit;
-        };
-        --paper-tabs-selection-bar-color: #fff;
-        height: calc(var(--toolbar-grouped-height) - var(--toolbar-height));
-        min-width: 300px;
-      }
-
-      paper-tab {
-        --paper-tab-ink: rgba(255, 255, 255, 0.4);
-        text-transform: uppercase;
-      }
-
-      #grouped-buttons-container {
-        @apply(--card-sizing);
-        align-items: center;
-        display: flex;
-        max-height: 0;
-        opacity: 0;
-        transition: opacity 300ms, max-height 300ms;
-      }
-
-      :host([show-grouped-controls]) #grouped-buttons-container {
-        max-height: calc(var(--toolbar-grouped-height) - var(--toolbar-height));
-        opacity: 1;
-      }
-
-      #grouped-spacer {
-        -webkit-margin-start: var(--side-bar-width);
-      }
-
-      :host([has-drawer]) #grouped-spacer {
-        -webkit-margin-start: 0;
-      }
-
-      #grouped-nav-container {
-        -webkit-margin-end: 16px;
-        align-items: center;
-        display: flex;
-        flex: 1;
-        justify-content: flex-end;
-        overflow: hidden;
-        transition: opacity 150ms;
-      }
-
-      :host([grouped-range='0']) #grouped-nav-container {
-        opacity: 0;
-        pointer-events: none;
-      }
-
-      #grouped-date {
-        -webkit-margin-end: 8px;
-        flex: 0 1 auto;
-        opacity: 0.7;
-        overflow: hidden;
-        text-align: right;
-        text-overflow: ellipsis;
-        white-space: nowrap;
-      }
-
-      #grouped-nav-container button {
-        -webkit-margin-start: 8px;
-        flex: 0 0 auto;
-      }
-
-      #grouped-nav-container button[disabled] {
-        color: rgba(255, 255, 255, 0.5);
-      }
-
-      :host-context([dir=rtl]) .rtl-reversible {
-        transform: rotate(180deg);
-      }
     </style>
     <div id="toolbar-container">
       <cr-toolbar id="main-toolbar"
@@ -233,47 +156,6 @@
         </div>
       </template>
     </div>
-    <template is="dom-if" if="[[isGroupedMode]]">
-      <div id="grouped-spacer">
-        <div id="grouped-buttons-container">
-          <paper-tabs attr-for-selected="value" selected="[[groupedRange]]"
-              on-iron-select="onTabSelected_">
-            <paper-tab value="0">$i18n{rangeAllTime}</paper-tab>
-            <paper-tab value="1">$i18n{rangeWeek}</paper-tab>
-            <paper-tab value="2">$i18n{rangeMonth}</paper-tab>
-          </paper-tabs>
-          <div id="grouped-nav-container">
-            <span id="grouped-date">
-              [[getHistoryInterval_(queryInfo)]]
-            </span>
-            <button is="paper-icon-button-light"
-                id="today-button"
-                class="icon-button"
-                title="$i18n{rangeToday}"
-                on-click="onTodayTap_"
-                disabled="[[isToday_(groupedOffset)]]">
-              <iron-icon icon="history:today"></iron-icon>
-            </button>
-            <button is="paper-icon-button-light"
-                id="prev-button"
-                title="$i18n{rangePrevious}"
-                class="icon-button rtl-reversible"
-                on-click="onPrevTap_"
-                disabled="[[!hasMoreResults]]">
-              <iron-icon icon="history:chevron-left"></iron-icon>
-            </button>
-            <button is="paper-icon-button-light"
-                id="next-button"
-                title="$i18n{rangeNext}"
-                class="icon-button rtl-reversible"
-                on-click="onNextTap_"
-                disabled="[[isToday_(groupedOffset)]]">
-              <iron-icon icon="cr:chevron-right"></iron-icon>
-            </button>
-          </div>
-        </div>
-      </div>
-    </template>
   </template>
   <script src="chrome://history/history_toolbar.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/md_history/history_toolbar.js b/chrome/browser/resources/md_history/history_toolbar.js
index 400ad21..e28bbaf 100644
--- a/chrome/browser/resources/md_history/history_toolbar.js
+++ b/chrome/browser/resources/md_history/history_toolbar.js
@@ -41,17 +41,6 @@
       reflectToAttribute: true,
     },
 
-    // The period to search over. Matches BrowsingHistoryHandler::Range.
-    groupedRange: {
-      type: Number,
-      reflectToAttribute: true,
-    },
-
-    showGroupedControls: {
-      type: Boolean,
-      reflectToAttribute: true,
-    },
-
     // Show an (i) button on the right of the toolbar to display a notice about
     // synced history.
     showSyncNotice: {
@@ -67,11 +56,6 @@
 
     hasMoreResults: Boolean,
 
-    groupedOffset: Number,
-
-    // Whether domain-grouped history is enabled.
-    isGroupedMode: Boolean,
-
     querying: Boolean,
 
     queryInfo: Object,
@@ -206,58 +190,4 @@
   numberOfItemsSelected_: function(count) {
     return count > 0 ? loadTimeData.getStringF('itemsSelected', count) : '';
   },
-
-  /** @private */
-  getHistoryInterval_: function() {
-    var info = this.queryInfo;
-    if (!info)
-      return;
-
-    if (this.groupedRange == HistoryRange.WEEK)
-      return info.queryInterval;
-
-    if (this.groupedRange == HistoryRange.MONTH)
-      return info.queryStartMonth;
-  },
-
-  /**
-   * @param {Event} e
-   * @private
-   */
-  onTabSelected_: function(e) {
-    this.fire(
-        'change-query', {range: Number(e.detail.item.getAttribute('value'))});
-  },
-
-  /**
-   * @param {number} newOffset
-   * @private
-   */
-  changeOffset_: function(newOffset) {
-    if (!this.querying)
-      this.fire('change-query', {offset: newOffset});
-  },
-
-  /** @private */
-  onTodayTap_: function() {
-    this.changeOffset_(0);
-  },
-
-  /** @private */
-  onPrevTap_: function() {
-    this.changeOffset_(this.groupedOffset + 1);
-  },
-
-  /** @private */
-  onNextTap_: function() {
-    this.changeOffset_(this.groupedOffset - 1);
-  },
-
-  /**
-   * @private
-   * @return {boolean}
-   */
-  isToday_: function() {
-    return this.groupedOffset == 0;
-  },
 });
diff --git a/chrome/browser/resources/md_history/lazy_load.html b/chrome/browser/resources/md_history/lazy_load.html
index 47329bb..7a5a1c0a 100644
--- a/chrome/browser/resources/md_history/lazy_load.html
+++ b/chrome/browser/resources/md_history/lazy_load.html
@@ -1,9 +1,6 @@
-<link rel="import" href="chrome://history/grouped_list.html">
 <link rel="import" href="chrome://history/synced_device_manager.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_drawer/cr_drawer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-tabs/paper-tab.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-tabs/paper-tabs.html">
diff --git a/chrome/browser/resources/md_history/list_container.html b/chrome/browser/resources/md_history/list_container.html
index 9fd0601..b9b6188 100644
--- a/chrome/browser/resources/md_history/list_container.html
+++ b/chrome/browser/resources/md_history/list_container.html
@@ -7,8 +7,7 @@
 <link rel="import" href="chrome://history/history_list.html">
 <link rel="import" href="chrome://history/shared_style.html">
 
-<!-- Lazy loaded: cr-dialog, cr-action-menu, history-grouped-list, paper-button.
-  -->
+<!-- Lazy loaded: cr-dialog, cr-action-menu, paper-button. -->
 
 <dom-module id="history-list-container">
   <template>
@@ -19,8 +18,7 @@
         overflow: hidden;
       }
 
-      #content,
-      #content > * {
+      history-list {
         height: 100%;
       }
 
@@ -28,21 +26,10 @@
         white-space: pre-wrap;
       }
     </style>
-    <iron-pages id="content"
-        attr-for-selected="id"
-        selected="[[selectedPage_]]">
-      <history-list id="infinite-list"
-          querying="[[queryState.querying]]"
-          searched-term="[[queryResult.info.term]]">
-      </history-list>
-      <template is="dom-if" if="[[grouped]]">
-        <history-grouped-list id="grouped-list"
-            range="[[queryState.range]]"
-            query-interval="[[queryResult.info.queryInterval]]"
-            searched-term="[[queryResult.info.term]]">
-        </history-grouped-list>
-      </template>
-    </iron-pages>
+    <history-list id="infinite-list"
+        querying="[[queryState.querying]]"
+        searched-term="[[queryResult.info.term]]">
+    </history-list>
 
     <template is="cr-lazy-render" id="dialog">
       <dialog is="cr-dialog">
diff --git a/chrome/browser/resources/md_history/list_container.js b/chrome/browser/resources/md_history/list_container.js
index 94e545e7..772a9a6 100644
--- a/chrome/browser/resources/md_history/list_container.js
+++ b/chrome/browser/resources/md_history/list_container.js
@@ -6,15 +6,6 @@
   is: 'history-list-container',
 
   properties: {
-    // The path of the currently selected page.
-    selectedPage_: {
-      type: String,
-      computed: 'computeSelectedPage_(queryState.range)',
-    },
-
-    // Whether domain-grouped history is enabled.
-    grouped: Boolean,
-
     /** @type {!QueryState} */
     queryState: Object,
 
@@ -54,14 +45,7 @@
     }
 
     var list = /** @type {HistoryListBehavior} */ this.getSelectedList_();
-    // It is possible for results to arrive for the grouped list before the lazy
-    // load has finished and the <history-grouped-list> element exists. In this
-    // case, add the items to a property on the unresolved element which can be
-    // read when it upgrades and is attached.
-    if (Polymer.isInstance(list))
-      list.addNewResults(results, this.queryState.incremental, info.finished);
-    else
-      list.initialData = results;
+    list.addNewResults(results, this.queryState.incremental, info.finished);
   },
 
   historyDeleted: function() {
@@ -108,15 +92,6 @@
   },
 
   /**
-   * @param {HistoryRange} range
-   * @return {string}
-   * @private
-   */
-  computeSelectedPage_: function(range) {
-    return range == HistoryRange.ALL_TIME ? 'infinite-list' : 'grouped-list';
-  },
-
-  /**
    * @param {HistoryQuery} info
    * @param {!Array<HistoryEntry>} results
    * @private
@@ -233,7 +208,7 @@
    * @private
    */
   getSelectedList_: function() {
-    return this.$$('#' + this.selectedPage_);
+    return this.$['infinite-list'];
   },
 
   /** @private */
diff --git a/chrome/browser/resources/md_history/query_manager.js b/chrome/browser/resources/md_history/query_manager.js
index 9fbe1d4..3ad12d9 100644
--- a/chrome/browser/resources/md_history/query_manager.js
+++ b/chrome/browser/resources/md_history/query_manager.js
@@ -17,16 +17,7 @@
           // A query is initiated by page load.
           querying: true,
           queryingDisabled: false,
-          _range: HistoryRange.ALL_TIME,
           searchTerm: '',
-          groupedOffset: 0,
-
-          set range(val) {
-            this._range = Number(val);
-          },
-          get range() {
-            return this._range;
-          },
         };
       },
     },
@@ -79,15 +70,12 @@
       lastVisitTime = lastVisit ? Math.floor(lastVisit.time) : 0;
     }
 
-    var maxResults =
-        this.queryState.range == HistoryRange.ALL_TIME ? RESULTS_PER_PAGE : 0;
-
     chrome.send('queryHistory', [
       queryState.searchTerm,
-      queryState.groupedOffset,
-      queryState.range,
+      0,  // No grouped offset.
+      0,  // Disable grouping.
       lastVisitTime,
-      maxResults,
+      RESULTS_PER_PAGE,
     ]);
   },
 
@@ -96,29 +84,9 @@
    * @private
    */
   onChangeQuery_: function(e) {
-    var changes =
-        /** @type {{range: ?HistoryRange, offset: ?number, search: ?string}} */
-        (e.detail);
+    var changes = /** @type {{search: ?string}} */ (e.detail);
     var needsUpdate = false;
 
-    if (changes.range != null && changes.range != this.queryState.range) {
-      this.set('queryState.range', changes.range);
-      needsUpdate = true;
-
-      // Reset back to page 0 of the results, unless changing to a specific
-      // page.
-      if (!changes.offset)
-        this.set('queryState.groupedOffset', 0);
-
-      this.fire('history-view-changed');
-    }
-
-    if (changes.offset != null &&
-        changes.offset != this.queryState.groupedOffset) {
-      this.set('queryState.groupedOffset', changes.offset);
-      needsUpdate = true;
-    }
-
     if (changes.search != null &&
         changes.search != this.queryState.searchTerm) {
       this.set('queryState.searchTerm', changes.search);
diff --git a/chrome/browser/resources/md_history/router.js b/chrome/browser/resources/md_history/router.js
index 38c5f05..b20d4e2 100644
--- a/chrome/browser/resources/md_history/router.js
+++ b/chrome/browser/resources/md_history/router.js
@@ -15,8 +15,6 @@
     /** @type {QueryState} */
     queryState: Object,
 
-    grouped: Boolean,
-
     path_: String,
 
     queryParams_: Object,
@@ -44,20 +42,12 @@
   serializeUrl: function() {
     var path = this.selectedPage;
 
-    if (path == 'history' && this.queryState.range != HistoryRange.ALL_TIME)
-      path += '/' + this.rangeToString_(this.queryState.range);
-
     if (path == 'history')
       path = '';
 
-    var offsetParam = null;
-    if (this.selectedPage == 'history' && this.queryState.groupedOffset)
-      offsetParam = this.queryState.groupedOffset;
-
     // Make all modifications at the end of the method so observers can't change
     // the outcome.
     this.path_ = '/' + path;
-    this.set('queryParams_.offset', offsetParam);
     this.set('queryParams_.q', this.queryState.searchTerm || null);
   },
 
@@ -76,13 +66,6 @@
     var sections = this.path_.substr(1).split('/');
     var page = sections[0] || 'history';
 
-    if (page == 'history' && this.grouped) {
-      var range = sections.length > 1 ? this.stringToRange_(sections[1]) :
-                                        HistoryRange.ALL_TIME;
-      changes.range = range;
-      changes.offset = Number(this.queryParams_.offset) || 0;
-    }
-
     changes.search = this.queryParams_.q || '';
 
     // Must change selectedPage before `change-query`, otherwise the
@@ -101,34 +84,4 @@
     // changes get processed together.
     this.debounce('parseUrl', this.parseUrl_.bind(this));
   },
-
-  /**
-   * @param {!HistoryRange} range
-   * @return {string}
-   */
-  rangeToString_: function(range) {
-    switch (range) {
-      case HistoryRange.WEEK:
-        return 'week';
-      case HistoryRange.MONTH:
-        return 'month';
-      default:
-        return '';
-    }
-  },
-
-  /**
-   * @param {string} str
-   * @return {HistoryRange}
-   */
-  stringToRange_: function(str) {
-    switch (str) {
-      case 'week':
-        return HistoryRange.WEEK;
-      case 'month':
-        return HistoryRange.MONTH;
-      default:
-        return HistoryRange.ALL_TIME;
-    }
-  }
 });
diff --git a/chrome/browser/resources/md_history/shared_vars.html b/chrome/browser/resources/md_history/shared_vars.html
index 68bf438f..5c419991 100644
--- a/chrome/browser/resources/md_history/shared_vars.html
+++ b/chrome/browser/resources/md_history/shared_vars.html
@@ -27,7 +27,6 @@
     --side-bar-width: 256px;
     --sidebar-footer-text-color: #6e6e6e;
     --sidebar-unselected-color: #5a5a5a;
-    --toolbar-grouped-height: 101px;
     --toolbar-height: 56px;
   }
 </style>
diff --git a/chrome/browser/resources/net_internals/timeline_view.css b/chrome/browser/resources/net_internals/timeline_view.css
index 0bcea44..a90349e 100644
--- a/chrome/browser/resources/net_internals/timeline_view.css
+++ b/chrome/browser/resources/net_internals/timeline_view.css
@@ -17,11 +17,11 @@
 }
 
 .timeline-view-rotateleft {
-  -webkit-transform: rotate(90deg);
+  transform: rotate(90deg);
 }
 
 .timeline-view-rotateright {
-  -webkit-transform: rotate(270deg);
+  transform: rotate(270deg);
 }
 
 #timeline-view-selection-div ul {
diff --git a/chrome/browser/resources/ntp4/apps_page.css b/chrome/browser/resources/ntp4/apps_page.css
index dc64dc70..1e1f5ee 100644
--- a/chrome/browser/resources/ntp4/apps_page.css
+++ b/chrome/browser/resources/ntp4/apps_page.css
@@ -9,13 +9,13 @@
 }
 
 .app-contents {
-  -webkit-transition: -webkit-transform 100ms;
+  -webkit-transition: transform 100ms;
 }
 
 .app-contents:active:not(.suppress-active),
 .app:not(.click-focus):focus .app-contents:not(.suppress-active),
 .drag-representation:not(.placing) .app-contents {
-  -webkit-transform: scale(1.1);
+  transform: scale(1.1);
 }
 
 /* Don't animate the initial scaling.  */
diff --git a/chrome/browser/resources/ntp4/new_tab.css b/chrome/browser/resources/ntp4/new_tab.css
index 43dd42dc..e00cd94 100644
--- a/chrome/browser/resources/ntp4/new_tab.css
+++ b/chrome/browser/resources/ntp4/new_tab.css
@@ -262,11 +262,11 @@
 }
 
 #footer.showing-trash-mode #trash.drag-target .lid {
-  -webkit-transform: rotate(-45deg);
+  transform: rotate(-45deg);
 }
 
 html[dir='rtl'] #footer.showing-trash-mode #trash.drag-target .lid {
-  -webkit-transform: rotate(45deg);
+  transform: rotate(45deg);
 }
 
 #fontMeasuringDiv {
diff --git a/chrome/browser/resources/ntp4/tile_page.css b/chrome/browser/resources/ntp4/tile_page.css
index 52fd059e..0abc043 100644
--- a/chrome/browser/resources/ntp4/tile_page.css
+++ b/chrome/browser/resources/ntp4/tile_page.css
@@ -100,18 +100,18 @@
 }
 
 .tile.drag-representation.placing > * {
-  -webkit-transition: -webkit-transform 200ms;
+  -webkit-transition: transform 200ms;
 }
 
 /* When a drag finishes while we're not showing the page where the tile
  * belongs, the tile shrinks to a dot. */
 .tile.drag-representation.dropped-on-other-page > * {
-   -webkit-transform: scale(0) rotate(0);
+   transform: scale(0) rotate(0);
 }
 
 .tile.drag-representation.deleting > * {
-  -webkit-transform: scale(0) rotate(360deg);
-  -webkit-transition: -webkit-transform 600ms;
+  -webkit-transition: transform 600ms;
+  transform: scale(0) rotate(360deg);
 }
 
 .animating-tile-page .tile,
@@ -127,50 +127,50 @@
   -webkit-transition: margin-bottom 200ms;
 }
 
-@-webkit-keyframes bounce {
+@keyframes bounce {
   0% {
-    -webkit-transform: scale(0, 0);
+    transform: scale(0, 0);
   }
 
   60% {
-    -webkit-transform: scale(1.2, 1.2);
+    transform: scale(1.2, 1.2);
   }
 
   100% {
-    -webkit-transform: scale(1, 1);
+    transform: scale(1, 1);
   }
 }
 
 .tile > .new-tile-contents {
-  -webkit-animation: bounce 500ms ease-in-out;
+  animation: bounce 500ms ease-in-out;
 }
 
-@-webkit-keyframes blipout {
+@keyframes blipout {
   0% {
-    -webkit-transform: scale(1, 1);
+    transform: scale(1, 1);
   }
 
   60% {
-    -webkit-animation-timing-function: ease-in;
-    -webkit-transform: scale(1.3, 0.02);
+    animation-timing-function: ease-in;
     opacity: 1;
+    transform: scale(1.3, 0.02);
   }
 
   90% {
-    -webkit-transform: scale(0.3, 0.02);
     opacity: 0.7;
+    transform: scale(0.3, 0.02);
   }
 
   100% {
-    -webkit-animation-timing-function: linear;
-    -webkit-transform: scale(0.3, 0.02);
+    animation-timing-function: linear;
     opacity: 0;
+    transform: scale(0.3, 0.02);
   }
 }
 
 .tile > .removing-tile-contents {
-  -webkit-animation: blipout 300ms;
-  -webkit-animation-fill-mode: forwards;
+  animation: blipout 300ms;
+  animation-fill-mode: forwards;
   pointer-events: none;
 }
 
diff --git a/chrome/browser/resources/ntp4/tile_page.js b/chrome/browser/resources/ntp4/tile_page.js
index ca032ca..d6748cfa 100644
--- a/chrome/browser/resources/ntp4/tile_page.js
+++ b/chrome/browser/resources/ntp4/tile_page.js
@@ -60,7 +60,7 @@
       this.addEventListener('dragend', this.onDragEnd_);
 
       this.firstChild.addEventListener(
-          'webkitAnimationEnd', this.onContentsAnimationEnd_.bind(this));
+          'animationend', this.onContentsAnimationEnd_.bind(this));
 
       this.eventTracker = new EventTracker();
     },
@@ -238,8 +238,8 @@
       if (isRTL())
         x *= -1;
 
-      this.doppleganger_.style.WebkitTransform = 'translate(' + x + 'px, ' +
-                                                                y + 'px)';
+      this.doppleganger_.style.transform = 'translate(' + x + 'px, ' +
+                                                          y + 'px)';
     },
 
     /**
@@ -304,7 +304,7 @@
     },
 
     /**
-     * Callback for the webkitAnimationEnd event on the tile's contents.
+     * Callback for the animationend event on the tile's contents.
      * @param {Event} e The event object.
      */
     onContentsAnimationEnd_: function(e) {
diff --git a/chrome/browser/resources/options/browser_options.css b/chrome/browser/resources/options/browser_options.css
index c0c4b19..7e79825 100644
--- a/chrome/browser/resources/options/browser_options.css
+++ b/chrome/browser/resources/options/browser_options.css
@@ -235,7 +235,7 @@
   width: 100%;
 }
 
-@-webkit-keyframes connecting-animation {
+@keyframes connecting-animation {
   0% {
     background-position: 0 25%;
   }
@@ -271,11 +271,11 @@
 
 .network-options-button {
   -webkit-box-flex: 0;
-  -webkit-transform: scale(0.6);
   background-image: none;
   background-position: center center;
   display: block;
   opacity: 0.5;
+  transform: scale(0.6);
   vertical-align: middle;
   width: 19px;
 }
@@ -289,7 +289,7 @@
   opacity: 1;
 }
 
-@-webkit-keyframes vpn-connecting-animation {
+@keyframes vpn-connecting-animation {
   from {
     opacity: 1;
   }
@@ -299,11 +299,11 @@
 }
 
 .network-connecting {
-  -webkit-animation: connecting-animation 1s step-end infinite;
+  animation: connecting-animation 1s step-end infinite;
 }
 
 .network-vpn.network-connecting {
-  -webkit-animation: vpn-connecting-animation 500ms alternate infinite;
+  animation: vpn-connecting-animation 500ms alternate infinite;
 }
 
 .network-title {
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index 41b0fae..0324429 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -50,6 +50,7 @@
   DISABLED: 1,
   IP_ONLY: 2,
   SEND_WIFI_ACCESS_POINTS: 3,
+  SEND_ALL_LOCATION_INFO: 4,
 };
 
 cr.define('options', function() {
diff --git a/chrome/browser/resources/options/chromeos/change_picture_options.css b/chrome/browser/resources/options/chromeos/change_picture_options.css
index 97b9838..11285b8 100644
--- a/chrome/browser/resources/options/chromeos/change_picture_options.css
+++ b/chrome/browser/resources/options/chromeos/change_picture_options.css
@@ -58,10 +58,10 @@
 }
 
 #user-image-preview .perspective-box {
-  -webkit-perspective: 600px;
   border: solid 1px #cacaca;
   border-radius: 4px;
   padding: 3px;
+  perspective: 600px;
   width: 220px;
 }
 
@@ -79,7 +79,7 @@
 }
 
 .camera.flip-x #user-image-preview-img {
-  -webkit-transform: rotateY(180deg);
+  transform: rotateY(180deg);
 }
 
 .user-image-stream-area {
@@ -99,7 +99,7 @@
 }
 
 .flip-x #user-image-stream-crop {
-  -webkit-transform: rotateY(180deg);
+  transform: rotateY(180deg);
 }
 
 /* TODO(ivankr): specify dimensions from real capture size. */
diff --git a/chrome/browser/resources/options/chromeos/display_options.css b/chrome/browser/resources/options/chromeos/display_options.css
index 36b6332..55d0455 100644
--- a/chrome/browser/resources/options/chromeos/display_options.css
+++ b/chrome/browser/resources/options/chromeos/display_options.css
@@ -31,11 +31,11 @@
  * This is achieved by a square rotated by 45-deg, and it has border at the
  * upper-half, which were left/top before the rotation. */
 #display-configuration-arrow {
-  -webkit-transform: rotate(45deg);
   border-left: 1px solid lightgrey;
   border-top: 1px solid lightgrey;
   height: 20px;
   position: absolute;
+  transform: rotate(45deg);
   width: 20px;
   z-index: 1;
 }
diff --git a/chrome/browser/resources/options/search_page.css b/chrome/browser/resources/options/search_page.css
index 47548c6..2d047ba 100644
--- a/chrome/browser/resources/options/search_page.css
+++ b/chrome/browser/resources/options/search_page.css
@@ -44,7 +44,6 @@
 
 /* Provides the arrow which points at the anchor element. */
 .search-bubble-innards::after {
-  -webkit-transform: rotate(45deg);
   background:
       -webkit-linear-gradient(-45deg, rgb(251, 255, 181),
                                       rgb(255, 248, 172) 50%,
@@ -57,6 +56,7 @@
   left: 53px;
   position: absolute;
   top: -7px;
+  transform: rotate(45deg);
   width: 12px;
   z-index: -1;
 }
@@ -64,9 +64,9 @@
 /* Turns the arrow direction downwards, when the bubble is placed above the
  * anchor element */
 .search-bubble-innards.above::after {
-  -webkit-transform: rotate(-135deg);
   bottom: -7px;
   top: auto;
+  transform: rotate(-135deg);
 }
 
 .search-bubble-wrapper {
diff --git a/chrome/browser/resources/options_resources.grd b/chrome/browser/resources/options_resources.grd
index afb6dcd..71abcdae 100644
--- a/chrome/browser/resources/options_resources.grd
+++ b/chrome/browser/resources/options_resources.grd
@@ -70,6 +70,24 @@
         <structure name="IDR_OPTIONS_FINGERPRINT_LIST_HTML"
                    file="settings/people_page/fingerprint_list.html"
                    type="chrome_html" />
+        <structure name="IDR_OPTIONS_SETUP_FINGERPRINT_DIALOG_JS"
+                   file="settings/people_page/setup_fingerprint_dialog.js"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_SETUP_FINGERPRINT_DIALOG_HTML"
+                   file="settings/people_page/setup_fingerprint_dialog.html"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_FINGERPRINT_PROGRESS_ARC_JS"
+                   file="settings/people_page/fingerprint_progress_arc.js"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_FINGERPRINT_PROGRESS_ARC_HTML"
+                   file="settings/people_page/fingerprint_progress_arc.html"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_FINGERPRINT_BROWSER_PROXY_JS"
+                   file="settings/people_page/fingerprint_browser_proxy.js"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_FINGERPRINT_BROWSER_PROXY_HTML"
+                   file="settings/people_page/fingerprint_browser_proxy.html"
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_LOCK_SCREEN_JS"
                    file="settings/people_page/lock_screen.js"
                    type="chrome_html" />
diff --git a/chrome/browser/resources/print_preview/common/search_bubble.css b/chrome/browser/resources/print_preview/common/search_bubble.css
index 06288b9d1..770f37b 100644
--- a/chrome/browser/resources/print_preview/common/search_bubble.css
+++ b/chrome/browser/resources/print_preview/common/search_bubble.css
@@ -40,7 +40,6 @@
 
 /* Provides the arrow which points at the anchor element. */
 .search-bubble-innards::after {
-  -webkit-transform: rotate(45deg);
   background: linear-gradient(-45deg, rgb(251, 255, 181),
                                       rgb(255, 248, 172) 50%,
                                       rgba(255, 248, 172, 0));
@@ -52,6 +51,7 @@
   left: 53px;
   position: absolute;
   top: -7px;
+  transform: rotate(45deg);
   width: 12px;
   z-index: -1;
 }
diff --git a/chrome/browser/resources/print_preview/print_preview.css b/chrome/browser/resources/print_preview/print_preview.css
index 8e2e049..b6fe8cd 100644
--- a/chrome/browser/resources/print_preview/print_preview.css
+++ b/chrome/browser/resources/print_preview/print_preview.css
@@ -159,9 +159,9 @@
 }
 
 span.hint.visible {
-  -webkit-animation-duration: 200ms;
-  -webkit-animation-fill-mode: forwards;
   -webkit-user-select: text;
+  animation-duration: 200ms;
+  animation-fill-mode: forwards;
   color: rgb(140, 20, 20);
   height: auto;
   margin-bottom: -5px;
@@ -183,8 +183,8 @@
 }
 
 .collapsible.visible {
-  -webkit-animation-duration: 200ms;
-  -webkit-animation-fill-mode: forwards;
+  animation-duration: 200ms;
+  animation-fill-mode: forwards;
   height: auto;
 }
 
@@ -222,8 +222,8 @@
 }
 
 .visible .extra {
-  -webkit-animation-duration: 200ms;
-  -webkit-animation-fill-mode: forwards;
+  animation-duration: 200ms;
+  animation-fill-mode: forwards;
   height: auto;
   opacity: 1;
   overflow: hidden;
@@ -251,7 +251,7 @@
   display: none !important;
 }
 
-@-webkit-keyframes dancing-dots-jump {
+@keyframes dancing-dots-jump {
   0% { top: 0; }
   55% { top: 0; }
   60% { top: -10px; }
@@ -262,17 +262,17 @@
 }
 
 span.jumping-dots > span {
-  -webkit-animation: dancing-dots-jump 1800ms infinite;
+  animation: dancing-dots-jump 1800ms infinite;
   padding: 1px;
   position: relative;
 }
 
 span.jumping-dots > span:nth-child(2) {
-  -webkit-animation-delay: 100ms;
+  animation-delay: 100ms;
 }
 
 span.jumping-dots > span:nth-child(3) {
-  -webkit-animation-delay: 300ms;
+  animation-delay: 300ms;
 }
 
 #print-header .button-strip {
diff --git a/chrome/browser/resources/print_preview/search/destination_search.css b/chrome/browser/resources/print_preview/search/destination_search.css
index 113fd652..903d86f4 100644
--- a/chrome/browser/resources/print_preview/search/destination_search.css
+++ b/chrome/browser/resources/print_preview/search/destination_search.css
@@ -69,12 +69,12 @@
 }
 
 #destination-search .invitation-container {
-  -webkit-animation: invitation-fadein 500ms;
   -webkit-box-align: center;
   -webkit-box-orient: vertical;
+  animation: invitation-fadein 500ms;
 }
 
-@-webkit-keyframes invitation-fadein {
+@keyframes invitation-fadein {
   from {
     opacity: 0;
   }
diff --git a/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chrome/browser/resources/settings/a11y_page/a11y_page.html
index a3eac49..432ee614 100644
--- a/chrome/browser/resources/settings/a11y_page/a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/a11y_page.html
@@ -29,9 +29,13 @@
               on-tap="onManageAccessibilityFeaturesTap_" actionable>
             <div class="start">
               $i18n{manageAccessibilityFeatures}
-              <div class="secondary">$i18n{moreFeaturesLinkDescription}</div>
+              <div class="secondary" id="themesSecondary">
+                $i18n{moreFeaturesLinkDescription}
+              </div>
             </div>
-            <button class="subpage-arrow" is="paper-icon-button-light"></button>
+            <button class="subpage-arrow" is="paper-icon-button-light"
+                aria-label="$i18n{manageAccessibilityFeatures}"
+                aria-describedby="themesSecondary"></button>
           </div>
         </template>
       </neon-animatable>
@@ -52,9 +56,13 @@
         actionable>
       <div class="start">
         $i18n{moreFeaturesLink}
-        <div class="secondary">$i18n{a11yWebStore}</div>
+        <div class="secondary" id="moreFeaturesSecondary">
+          $i18n{a11yWebStore}
+        </div>
       </div>
-      <button class="icon-external" is="paper-icon-button-light"></button>
+      <button class="icon-external" is="paper-icon-button-light"
+          aria-label="$i18n{moreFeaturesLink}"
+          aria-describedby="moreFeaturesSecondary"></button>
     </div>
 </if>
 
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
index 993090b..3c1ff3c9 100644
--- a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
@@ -41,7 +41,8 @@
           label="$i18n{chromeVoxLabel}">
         <button class="more-actions icon-external" is="paper-icon-button-light"
             on-tap="onChromeVoxSettingsTap_"
-            hidden="[[!prefs.settings.accessibility.value]]"></button>
+            hidden="[[!prefs.settings.accessibility.value]]"
+            aria-label="$i18n{chromeVoxLabel}"></button>
       </settings-toggle-button>
     </div>
     <template is="dom-if" if="[[showExperimentalFeatures_]]">
@@ -68,16 +69,24 @@
     <div class="settings-box two-line" on-tap="onDisplayTap_" actionable>
       <div class="start">
         $i18n{displaySettingsTitle}
-        <div class="secondary">$i18n{displaySettingsDescription}</div>
+        <div class="secondary" id="deisplaySettingsSecondary">
+          $i18n{displaySettingsDescription}
+        </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{displaySettingsTitle}"
+          aria-describedby="displaySettingsSecondary"></button>
     </div>
     <div class="settings-box two-line" on-tap="onAppearanceTap_" actionable>
       <div class="start">
         $i18n{appearanceSettingsTitle}
-        <div class="secondary">$i18n{appearanceSettingsDescription}</div>
+        <div class="secondary" id="appearanceSettingsSecondary">
+          $i18n{appearanceSettingsDescription}
+        </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{appearanceSettingsTitle}"
+          aria-describedby="appearanceSettingsSecondary"></button>
     </div>
 
     <h2>$i18n{keyboardHeading}</h2>
@@ -108,9 +117,13 @@
     <div class="settings-box two-line" on-tap="onKeyboardTap_" actionable>
       <div class="start">
         $i18n{keyboardSettingsTitle}
-        <div class="secondary">$i18n{keyboardSettingsDescription}</div>
+        <div class="secondary" id="keyboardSettingsSecondary">
+          $i18n{keyboardSettingsDescription}
+        </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{keyboardSettingsTitle}"
+          aria-describedby="keyboardSettingsSecondary"></button>
     </div>
 
     <h2>$i18n{mouseAndTouchpadHeading}</h2>
@@ -143,9 +156,13 @@
     <div class="settings-box two-line" on-tap="onMouseTap_" actionable>
       <div class="start">
         $i18n{mouseSettingsTitle}
-        <div class="secondary">$i18n{mouseSettingsDescription}</div>
+        <div class="secondary" id="mouseSettingsSecondary">
+          $i18n{mouseSettingsDescription}
+        </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{mouseSettingsTitle}"
+          aria-describedby="mouseSettingsSecondary"></button>
     </div>
 
     <h2>$i18n{audioHeading}</h2>
@@ -159,9 +176,13 @@
     <div class="settings-box two-line" on-tap="onMoreFeaturesTap_" actionable>
       <div class="start">
         $i18n{additionalFeaturesTitle}
-        <div class="secondary">$i18n{a11yWebStore}</div>
+        <div class="secondary" id="moreFeaturesSecondary">
+          $i18n{a11yWebStore}
+        </div>
       </div>
-      <button class="icon-external" is="paper-icon-button-light"></button>
+      <button class="icon-external" is="paper-icon-button-light"
+          aria-label="$i18n{additionalFeaturesTitle}"
+          aria-describedby="moreFeaturesSecondary"></button>
     </div>
   </template>
   <script src="manage_a11y_page.js"></script>
diff --git a/chrome/browser/resources/settings/about_page/about_page.html b/chrome/browser/resources/settings/about_page/about_page.html
index b3005df..3e4f029 100644
--- a/chrome/browser/resources/settings/about_page/about_page.html
+++ b/chrome/browser/resources/settings/about_page/about_page.html
@@ -154,29 +154,31 @@
                 </div>
                 <button class="subpage-arrow" is="paper-icon-button-light"
                     disabled="[[promoteUpdaterStatus_.disabled]]"
-                    hidden="[[!promoteUpdaterStatus_.actionable]]">
+                    hidden="[[!promoteUpdaterStatus_.actionable]]"
+                    aria-label="[[promoteUpdaterStatus_.text]]">
                 </button>
               </div>
             </template>
 </if>
             <div id="help" class="settings-box" on-tap="onHelpTap_" actionable>
               <div class="start">$i18n{aboutGetHelpUsingChrome}</div>
-              <button class="icon-external" is="paper-icon-button-light">
-              </button>
+              <button class="icon-external" is="paper-icon-button-light"
+                  aria-labelledby="help"></button>
             </div>
 <if expr="_google_chrome">
             <div id="reportIssue" class="settings-box" actionable
                 on-tap="onReportIssueTap_">
               <div class="start">$i18n{aboutReportAnIssue}</div>
-              <button class="subpage-arrow" is="paper-icon-button-light">
-              </button>
+              <button class="subpage-arrow" is="paper-icon-button-light"
+                  aria-labelledby="reportIssue"></button>
             </div>
 </if>
 <if expr="chromeos">
             <div class="settings-box" on-tap="onDetailedBuildInfoTap_"
                 actionable>
               <div class="start">$i18n{aboutDetailedBuildInfo}</div>
-              <button class="subpage-arrow" is="paper-icon-button-light">
+              <button class="subpage-arrow" is="paper-icon-button-light"
+                  aria-label="$i18n{aboutDetailedBuildInfo}">
               </button>
             </div>
 </if>
diff --git a/chrome/browser/resources/settings/about_page/about_page.js b/chrome/browser/resources/settings/about_page/about_page.js
index 1e53ea6d..e19861d4 100644
--- a/chrome/browser/resources/settings/about_page/about_page.js
+++ b/chrome/browser/resources/settings/about_page/about_page.js
@@ -294,7 +294,7 @@
 
     switch (this.currentUpdateStatusEvent_.status) {
       case UpdateStatus.DISABLED_BY_ADMIN:
-        return 'cr:domain';
+        return 'cr20:domain';
       case UpdateStatus.FAILED:
         return 'settings:error';
       case UpdateStatus.UPDATED:
diff --git a/chrome/browser/resources/settings/about_page/detailed_build_info.html b/chrome/browser/resources/settings/about_page/detailed_build_info.html
index ee8be1c..135f813 100644
--- a/chrome/browser/resources/settings/about_page/detailed_build_info.html
+++ b/chrome/browser/resources/settings/about_page/detailed_build_info.html
@@ -45,7 +45,7 @@
             disabled="[[!canChangeChannel_]]">
           $i18n{aboutChangeChannel}
         </paper-button>
-        <iron-icon icon="cr:domain" hidden="[[canChangeChannel_]]"</iron-icon>
+        <iron-icon icon="cr20:domain" hidden="[[canChangeChannel_]]"</iron-icon>
       </div>
       <template is="dom-if" if="[[showChannelSwitcherDialog_]]" restamp>
         <settings-channel-switcher-dialog></settings-channel-switcher-dialog>
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
index 8ee3bd8..782feff8 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.html
@@ -114,12 +114,14 @@
       <div class="settings-box two-line" id="advancedButton"
           on-tap="openAdvancedExtension_" actionable>
         <div class="start">
-          <div>$i18n{advancedFontSettings}</div>
+          $i18n{advancedFontSettings}
           <div class="secondary" id="advancedButtonSublabel">
             [[advancedExtensionSublabel_]]
           </div>
         </div>
-        <button class="icon-external" is="paper-icon-button-light"></button>
+        <button class="icon-external" is="paper-icon-button-light"
+            aria-label="$i18n{advancedFontSettings}"
+            aria-describedby="advancedButtonSublabel"></button>
       </div>
     </template>
   </template>
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_page.html b/chrome/browser/resources/settings/appearance_page/appearance_page.html
index 4d84842..de37163 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_page.html
+++ b/chrome/browser/resources/settings/appearance_page/appearance_page.html
@@ -41,9 +41,13 @@
             hidden="[[!pageVisibility.setWallpaper]]">
           <div class="start">
             $i18n{setWallpaper}
-            <div class="secondary">$i18n{openWallpaperApp}</div>
+            <div class="secondary" id="wallpaperSecondary">
+              $i18n{openWallpaperApp}
+            </div>
           </div>
-          <button class="icon-external" is="paper-icon-button-light"></button>
+          <button class="icon-external" is="paper-icon-button-light"
+              aria-label="$i18n{setWallpaper}"
+              aria-describedby="wallpaperSecondary"></button>
         </div>
         <div class="settings-box two-line"
             hidden="[[!pageVisibility.setTheme]]">
@@ -54,10 +58,14 @@
 </if>
           <div class="start two-line" on-tap="onThemesTap_" actionable>
             <div class="flex">
-              <div>$i18n{themes}</div>
-              <div class="secondary">[[themeSublabel_]]</div>
+              $i18n{themes}
+              <div class="secondary" id="themesSecondary">
+                [[themeSublabel_]]
+              </div>
             </div>
-            <button class="icon-external" is="paper-icon-button-light"></button>
+            <button class="icon-external" is="paper-icon-button-light"
+                aria-label="$i18n{themes}"
+                aria-describedby="themesSecondary"></button>
           </div>
 <if expr="not is_linux or chromeos">
           <template is="dom-if" if="[[prefs.extensions.theme.id.value]]">
@@ -156,10 +164,12 @@
         <div id="customize-fonts-subpage-trigger" class="settings-box two-line"
             on-tap="onCustomizeFontsTap_" actionable>
           <div class="start">
-            <div>$i18n{customizeFonts}</div>
-            <div class="secondary">$i18n{chooseFonts}</div>
+            $i18n{customizeFonts}
+            <div class="secondary" id="fontsSecondary">$i18n{chooseFonts}</div>
           </div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{customizeFonts}"
+              aria-describedby="fontsSecondary"></button>
         </div>
         <div class="settings-box"
             hidden="[[!pageVisibility.pageZoom]]">
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
index cdcd55a..2afc30f 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -22,15 +22,18 @@
         <div class="settings-box two-line" actionable on-tap="onTap_">
           <iron-icon icon="[[getIcon_(bluetoothEnabled_)]]"></iron-icon>
           <div class="middle">
-            <div>$i18n{bluetoothPageTitle}</div>
-            <div class="secondary">[[getDescription_(bluetoothEnabled_)]]</div>
+            $i18n{bluetoothPageTitle}
+            <div class="secondary" id="bluetoothSecondary">
+              [[getDescription_(bluetoothEnabled_)]]
+            </div>
           </div>
           <cr-policy-pref-indicator
               pref="[[prefs.cros.device.allow_bluetooth]]"
             hidden="[[prefs.cros.device.allow_bluetooth.value]]">
           </cr-policy-pref-indicator>
           <button class="subpage-arrow" is="paper-icon-button-light"
-              on-tap="onSubpageArrowTap_">
+              on-tap="onSubpageArrowTap_" aria-label="$i18n{bluetoothPageTitle}"
+              aria-describedby="bluetoothSecondary">
           </button>
           <div class="secondary-action">
             <paper-toggle-button id="enableBluetooth"
diff --git a/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.js b/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.js
index d15e3eb..248397e3 100644
--- a/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.js
+++ b/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.js
@@ -61,6 +61,10 @@
     'prefValueChanged_(pref.value)',
   ],
 
+  notifyChangedByUserInteraction: function() {
+    this.fire('settings-boolean-control-change');
+  },
+
   /** Reset the checked state to match the current pref value. */
   resetToPrefValue: function() {
     this.checked = this.getNewValue_(this.pref.value);
diff --git a/chrome/browser/resources/settings/controls/settings_checkbox.html b/chrome/browser/resources/settings/controls/settings_checkbox.html
index 9f4ae7b9..5bc7cf3 100644
--- a/chrome/browser/resources/settings/controls/settings_checkbox.html
+++ b/chrome/browser/resources/settings/controls/settings_checkbox.html
@@ -30,6 +30,8 @@
       }
     </style>
     <div id="outerRow" noSubLabel$="[[!subLabel]]">
+      <!-- TODO(dbeam): should we be calling notifyChangedByUserInteraction
+           somewhere here like we do for settings-toggle-button? -->
       <paper-checkbox id="checkbox" checked="{{checked}}"
           disabled="[[controlDisabled_(disabled, pref)]]">
         <div>[[label]] <content></content></div>
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.html b/chrome/browser/resources/settings/controls/settings_toggle_button.html
index 91eb26e7..a294ae0 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.html
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.html
@@ -45,10 +45,11 @@
         <div class="secondary label">[[subLabel]]</div>
       </div>
       <content select=".more-actions"></content>
-      <template is="dom-if" if="[[pref.controlledBy]]">
+      <template is="dom-if" if="[[pref.controlledBy]]" restamp>
         <cr-policy-pref-indicator pref="[[pref]]"></cr-policy-pref-indicator>
       </template>
       <paper-toggle-button id="control" checked="{{checked}}"
+          on-change="notifyChangedByUserInteraction"
           disabled="[[controlDisabled_(disabled, pref)]]">
       </paper-toggle-button>
     </div>
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.js b/chrome/browser/resources/settings/controls/settings_toggle_button.js
index fcfa247e..1352bccf 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.js
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.js
@@ -20,7 +20,10 @@
 
   /** @private */
   onLabelWrapperTap_: function() {
-    if (!this.controlDisabled_())
-      this.checked = !this.checked;
+    if (this.controlDisabled_())
+      return;
+
+    this.checked = !this.checked;
+    this.notifyChangedByUserInteraction();
   },
 });
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chrome/browser/resources/settings/date_time_page/date_time_page.html
index 345c0ed9..050fd3b 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.html
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.html
@@ -50,10 +50,9 @@
     </div>
     <div class="settings-box" id="setDateTime" actionable
         on-tap="onSetDateTimeTap_" hidden$="[[!canSetDateTime_]]">
-      <div class="start">
-        <div>$i18n{setDateTime}</div>
-      </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <div class="start">$i18n{setDateTime}</div>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{setDateTime}"></button>
     </div>
   </template>
   <script src="date_time_page.js"></script>
diff --git a/chrome/browser/resources/settings/device_page/device_page.html b/chrome/browser/resources/settings/device_page/device_page.html
index 1665552..9e7e6b59 100644
--- a/chrome/browser/resources/settings/device_page/device_page.html
+++ b/chrome/browser/resources/settings/device_page/device_page.html
@@ -26,29 +26,35 @@
           <div class="middle">
             [[getPointersTitle_(hasMouse_, hasTouchpad_)]]
           </div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="[[getPointersTitle_(hasMouse_,
+                                              hasTouchpad_)]]"></button>
         </div>
         <div id="keyboardRow" class="settings-box" on-tap="onKeyboardTap_"
             actionable>
           <div class="middle">$i18n{keyboardTitle}</div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{keyboardTitle}"></button>
         </div>
         <template is="dom-if" if="[[hasStylus_]]">
           <div id="stylusRow" class="settings-box" on-tap="onStylusTap_"
               actionable>
             <div class="middle">$i18n{stylusTitle}</div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{stylusTitle}"></button>
           </div>
         </template>
         <div id="displayRow" class="settings-box" on-tap="onDisplayTap_"
             actionable>
           <div class="middle">$i18n{displayTitle}</div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{displayTitle}"></button>
         </div>
         <div id="storageRow" class="settings-box" on-tap="onStorageTap_"
             actionable>
           <div class="middle">$i18n{storageTitle}</div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{storageTitle}"></button>
         </div>
         <template is="dom-if" if="[[enablePowerSettings_]]">
           <div id="powerRow" class="settings-box two-line">
diff --git a/chrome/browser/resources/settings/device_page/display.html b/chrome/browser/resources/settings/device_page/display.html
index 81e6763..45e588eb 100644
--- a/chrome/browser/resources/settings/device_page/display.html
+++ b/chrome/browser/resources/settings/device_page/display.html
@@ -134,10 +134,14 @@
           on-tap="onOverscanTap_" hidden$="[[selectedDisplay.isInternal]]"
           actionable>
         <div class="start">
-          <div>$i18n{displayOverscanPageTitle}</div>
-          <div class="secondary">$i18n{displayOverscanPageText}</div>
+          $i18n{displayOverscanPageTitle}
+          <div class="secondary" id="displayOverscanSecondary">
+            $i18n{displayOverscanPageText}
+          </div>
         </div>
-        <button class="subpage-arrow" is="paper-icon-button-light"></button>
+        <button class="subpage-arrow" is="paper-icon-button-light"
+            aria-label="$i18n{displayOverscanPageTitle}"
+            aria-describedby="displayOverscanSecondary"></button>
       </div>
 
       <settings-display-overscan-dialog id="displayOverscan"
@@ -149,10 +153,14 @@
           hidden$="[[!showTouchCalibrationSetting_(selectedDisplay)]]"
           actionable>
         <div class="start">
-          <div>$i18n{displayTouchCalibrationTitle}</div>
-          <div class="secondary">$i18n{displayTouchCalibrationText}</div>
+          $i18n{displayTouchCalibrationTitle}
+          <div class="secondary" id="touchCalibrationSecondary">
+            $i18n{displayTouchCalibrationText}
+          </div>
         </div>
-        <button class="subpage-arrow" is="paper-icon-button-light"></button>
+        <button class="subpage-arrow" is="paper-icon-button-light"
+            aria-label="$i18n{displayTouchCalibrationTitle}"
+            aria-describedby="touchCalibrationSecondary"></button>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/settings/device_page/keyboard.html b/chrome/browser/resources/settings/device_page/keyboard.html
index 075525a..b57ec09 100644
--- a/chrome/browser/resources/settings/device_page/keyboard.html
+++ b/chrome/browser/resources/settings/device_page/keyboard.html
@@ -109,11 +109,13 @@
     <div id="keyboardOverlay" class="settings-box"
         on-tap="onShowKeyboardShortcutsOverlayTap_" actionable>
       <div class="start">$i18n{showKeyboardShortcutsOverlay}</div>
-      <button class="icon-external" is="paper-icon-button-light"></button>
+      <button class="icon-external" is="paper-icon-button-light"
+          aria-label="$i18n{showKeyboardShortcutsOverlay}"></button>
     </div>
     <div class="settings-box" on-tap="onShowLanguageInputTap_" actionable>
       <div class="start">$i18n{keyboardShowLanguageAndInput}</div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{keyboardShowLanguageAndInput}"></button>
     </div>
   </template>
   <script src="keyboard.js"></script>
diff --git a/chrome/browser/resources/settings/device_page/storage.html b/chrome/browser/resources/settings/device_page/storage.html
index 32a1b88..b08f43942 100644
--- a/chrome/browser/resources/settings/device_page/storage.html
+++ b/chrome/browser/resources/settings/device_page/storage.html
@@ -125,6 +125,20 @@
         direction: initial;
         unicode-bidi: embed;
       }
+
+      #deleteButton {
+        display: none;
+      }
+
+      [actionable] #deleteButton {
+        display: block;
+      }
+
+      button > iron-icon {
+        --iron-icon-fill-color: var(--paper-grey-400);
+        --iron-icon-height: 24px;
+        --iron-icon-width: 24px;
+      }
     </style>
     <template is="dom-if" if="[[isSpaceLow_(sizeStat_.spaceState)]]">
       <div class="settings-box first">
@@ -178,45 +192,68 @@
         </div>
       </div>
     </div>
-    <div class="settings-box" on-tap="onDownloadsTap_" actionable>
-      <div class="start">$i18n{storageItemDownloads}</div>
-      <div id="downloadsSize" class="storage-size">
-        $i18n{storageSizeComputing}
+    <div class="settings-box two-line" on-tap="onDownloadsTap_" actionable>
+      <div class="start">
+        $i18n{storageItemDownloads}
+        <div id="downloadsSize" class="secondary">
+          $i18n{storageSizeComputing}
+        </div>
       </div>
-      <button class="icon-external" is="paper-icon-button-light"></button>
+      <button class="icon-external" is="paper-icon-button-light"
+          aria-label="$i18n{storageItemDownloads}"
+          aria-describedby="downloadsSize"></button>
     </div>
     <template is="dom-if" if="[[driveEnabled_]]">
-      <div class="settings-box" on-tap="onDriveCacheTap_" actionable>
-        <div class="start">$i18n{storageItemDriveCache}</div>
-        <div id="driveCacheSize" class="storage-size">
-          $i18n{storageSizeComputing}
+      <div class="settings-box two-line" on-tap="onDriveCacheTap_"
+          actionable$="[[hasDriveCache_]]" >
+        <div class="start">
+          $i18n{storageItemDriveCache}
+          <div id="driveCacheSize" class="secondary">
+            $i18n{storageSizeComputing}
+          </div>
         </div>
-        <button class="subpage-arrow" is="paper-icon-button-light"></button>
+        <button id="deleteButton" is="paper-icon-button-light"
+            aria-label="$i18n{storageItemDriveCache}"
+            aria-describedby="driveSizeCache">
+          <iron-icon icon="cr:delete"></iron-icon>
+        </button>
       </div>
     </template>
-    <div class="settings-box" on-tap="onBrowsingDataTap_" actionable>
-      <div class="start">$i18n{storageItemBrowsingData}</div>
-      <div id="browsingDataSize" class="storage-size">
-        $i18n{storageSizeComputing}
-      </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
-    </div>
-    <template is="dom-if" if="[[androidEnabled_]]">
-      <div class="settings-box" on-tap="onAndroidTap_" actionable>
-        <div class="start">$i18n{storageItemAndroid}</div>
-        <div id="androidSize" class="storage-size">
+    <div class="settings-box two-line" on-tap="onBrowsingDataTap_" actionable>
+      <div class="start">
+        $i18n{storageItemBrowsingData}
+        <div id="browsingDataSize" class="secondary">
           $i18n{storageSizeComputing}
         </div>
-        <button class="icon-external" is="paper-icon-button-light"></button>
+      </div>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{storageItemBrowsingData}"
+          aria-describedby="browsingDataSize"></button>
+    </div>
+    <template is="dom-if" if="[[androidEnabled_]]">
+      <div class="settings-box two-line" on-tap="onAndroidTap_" actionable>
+        <div class="start">
+          $i18n{storageItemAndroid}
+          <div id="androidSize" class="secondary">
+            $i18n{storageSizeComputing}
+          </div>
+        </div>
+        <button class="icon-external" is="paper-icon-button-light"
+            aria-label="$i18n{storageItemAndroid}"
+            aria-describedby="androidSize"></button>
       </div>
     </template>
     <template is="dom-if" if="[[!isGuest_]]">
-      <div class="settings-box" on-tap="onOtherUsersTap_" actionable>
-        <div class="start">$i18n{storageItemOtherUsers}</div>
-        <div id="otherUsersSize" class="storage-size">
-          $i18n{storageSizeComputing}
+      <div class="settings-box two-line" on-tap="onOtherUsersTap_" actionable>
+        <div class="start">
+          $i18n{storageItemOtherUsers}
+          <div id="otherUsersSize" class="secondary">
+            $i18n{storageSizeComputing}
+          </div>
         </div>
-        <button class="subpage-arrow" is="paper-icon-button-light"></button>
+        <button class="subpage-arrow" is="paper-icon-button-light"
+            aria-label="$i18n{storageItemOtherUsers}"
+            aria-describedby="otherUsersSize"></button>
       </div>
     </template>
 
diff --git a/chrome/browser/resources/settings/device_page/storage.js b/chrome/browser/resources/settings/device_page/storage.js
index 6649b83..4517f98 100644
--- a/chrome/browser/resources/settings/device_page/storage.js
+++ b/chrome/browser/resources/settings/device_page/storage.js
@@ -55,6 +55,12 @@
       value: function() { return loadTimeData.getBoolean('isGuest'); }
     },
 
+    /** @private */
+    hasDriveCache_: {
+      type: Boolean,
+      value: false
+    },
+
     /** @private {settings.StorageSizeStat} */
     sizeStat_: Object,
   },
@@ -128,7 +134,8 @@
    */
   onDriveCacheTap_: function(e) {
     e.preventDefault();
-    this.$.storageDriveCache.open();
+    if (this.hasDriveCache_)
+      this.$.storageDriveCache.open();
   },
 
   /**
@@ -177,11 +184,14 @@
   /**
    * @param {string} size Formatted string representing the size of Offline
    *     files.
+   * @param {boolean} hasCache True if the device has at least one offline file.
    * @private
    */
-  handleDriveCacheSizeChanged_: function(size) {
-    if (this.driveEnabled_)
+  handleDriveCacheSizeChanged_: function(size, hasCache) {
+    if (this.driveEnabled_) {
       this.$$('#driveCacheSize').textContent = size;
+      this.hasDriveCache_ = hasCache;
+    }
   },
 
   /**
diff --git a/chrome/browser/resources/settings/device_page/stylus.html b/chrome/browser/resources/settings/device_page/stylus.html
index a86599ca..acc3c4b 100644
--- a/chrome/browser/resources/settings/device_page/stylus.html
+++ b/chrome/browser/resources/settings/device_page/stylus.html
@@ -73,11 +73,13 @@
         hidden$="[[!prefs.arc.enabled.value]]">
       <div class="start">
         $i18n{stylusFindMoreAppsPrimary}
-        <div class="secondary">
+        <div class="secondary" id="stylusFindMoreAppsSecondary">
           $i18n{stylusFindMoreAppsSecondary}
         </div>
       </div>
-      <button class="icon-external" is="paper-icon-button-light"></button>
+      <button class="icon-external" is="paper-icon-button-light"
+          aria-label="$i18n{stylusFindMoreAppsPrimary}"
+          aria-describedby="stylusFindMoreAppsSecondary"></button>
     </div>
 
   </template>
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html
index 6c02d08..de9b38b 100644
--- a/chrome/browser/resources/settings/icons.html
+++ b/chrome/browser/resources/settings/icons.html
@@ -55,6 +55,7 @@
       <g id="done"><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"></path></g>
       <g id="error"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"></path></g>
 <if expr="chromeos">
+<g id="fingerprint"><path d="M17.81 4.47c-.08 0-.16-.02-.23-.06C15.66 3.42 14 3 12.01 3c-1.98 0-3.86.47-5.57 1.41-.24.13-.54.04-.68-.2-.13-.24-.04-.55.2-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67-.09.18-.26.28-.44.28zM3.5 9.72c-.1 0-.2-.03-.29-.09-.23-.16-.28-.47-.12-.7.99-1.4 2.25-2.5 3.75-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54-.12.7-.23.16-.54.11-.7-.12-.9-1.26-2.04-2.25-3.39-2.94-2.87-1.47-6.54-1.47-9.4.01-1.36.7-2.5 1.7-3.4 2.96-.08.14-.23.21-.39.21zm6.25 12.07c-.13 0-.26-.05-.35-.15-.87-.87-1.34-1.43-2.01-2.64-.69-1.23-1.05-2.73-1.05-4.34 0-2.97 2.54-5.39 5.66-5.39s5.66 2.42 5.66 5.39c0 .28-.22.5-.5.5s-.5-.22-.5-.5c0-2.42-2.09-4.39-4.66-4.39-2.57 0-4.66 1.97-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71-.11.1-.24.15-.37.15zm7.17-1.85c-1.19 0-2.24-.3-3.1-.89-1.49-1.01-2.38-2.65-2.38-4.39 0-.28.22-.5.5-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64-.03 1.04-.1.27-.05.53.13.58.41.05.27-.13.53-.41.58-.57.11-1.07.12-1.21.12zM14.91 22c-.04 0-.09-.01-.13-.02-1.59-.44-2.63-1.03-3.72-2.1-1.4-1.39-2.17-3.24-2.17-5.22 0-1.62 1.38-2.94 3.08-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08-.87 2.08-1.94c0-3.77-3.25-6.83-7.25-6.83-2.84 0-5.44 1.58-6.61 4.03-.39.81-.59 1.76-.59 2.8 0 .78.07 2.01.67 3.61.1.26-.03.55-.29.64-.26.1-.55-.04-.64-.29-.49-1.31-.73-2.61-.73-3.96 0-1.2.23-2.29.68-3.24 1.33-2.79 4.28-4.6 7.51-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62-1.38 2.94-3.08 2.94s-3.08-1.32-3.08-2.94c0-1.07-.93-1.94-2.08-1.94s-2.08.87-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61-.05.23-.26.38-.47.38z"></path></g>
       <g id="flip"><path d="M15 21h2v-2h-2v2zm4-12h2V7h-2v2zM3 5v14c0 1.1.9 2 2 2h4v-2H5V5h4V3H5c-1.1 0-2 .9-2 2zm16-2v2h2c0-1.1-.9-2-2-2zm-8 20h2V1h-2v22zm8-6h2v-2h-2v2zM15 5h2V3h-2v2zm4 8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2z"></path></g>
       <g id="gamepad"><path d="M15 7.5V2H9v5.5l3 3 3-3zM7.5 9H2v6h5.5l3-3-3-3zM9 16.5V22h6v-5.5l-3-3-3 3zM16.5 9l-3 3 3 3H22V9h-5.5z"></path></g>
       <g id="headset"><path d="M12 1c-4.97 0-9 4.03-9 9v7c0 1.66 1.34 3 3 3h3v-8H5v-2c0-3.87 3.13-7 7-7s7 3.13 7 7v2h-4v8h3c1.66 0 3-1.34 3-3v-7c0-4.97-4.03-9-9-9z"></path></g>
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index a70e4dca..eb97739 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -138,7 +138,7 @@
     <!-- Disabled by policy / Shared messages. -->
     <div class="settings-box continuation"
         hidden$="[[!connectNotAllowed_(networkProperties, globalPolicy)]]">
-      <iron-icon class="policy" icon="cr:domain"></iron-icon>
+      <iron-icon class="policy" icon="cr20:domain"></iron-icon>
       <div>$i18n{networkConnectNotAllowed}</div>
     </div>
     <div class="settings-box continuation"
@@ -253,7 +253,7 @@
                 network-properties="[[networkProperties]]">
             </network-apnlist>
           </template>
-          
+
           <!-- IP Config, Nameservers, Proxy -->
           <template is="dom-if"
               if="[[isRememberedOrConnected_(networkProperties)]]">
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.html b/chrome/browser/resources/settings/internet_page/internet_page.html
index a921f139..1a07d2b 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_page.html
@@ -52,13 +52,15 @@
             <div actionable class="settings-box continuation center"
                 on-tap="onAddWiFiTap_">
               <div class="start add-no-icon">$i18n{internetAddWiFi}</div>
-              <button class="icon-external" is="paper-icon-button-light">
+              <button class="icon-external" is="paper-icon-button-light"
+                  aria-label="$i18n{internetAddWiFi}">
               </button>
             </div>
             <div actionable class="settings-box continuation center"
                 on-tap="onAddVPNTap_">
               <div class="start add-no-icon">$i18n{internetAddVPN}</div>
-              <button class="icon-external" is="paper-icon-button-light">
+              <button class="icon-external" is="paper-icon-button-light"
+                  aria-label="$i18n{internetAddVPN}">
               </button>
             </div>
             <template is="dom-repeat" items="[[thirdPartyVpnProviders_]]">
@@ -73,7 +75,7 @@
         </template>
         <template is="dom-if" if="[[!allowAddConnection_(globalPolicy_)]]">
           <div class="settings-box">
-            <iron-icon class="policy" icon="cr:domain"></iron-icon>
+            <iron-icon class="policy" icon="cr20:domain"></iron-icon>
             <div>$i18n{internetAddConnectionNotAllowed}</div>
           </div>
         </template>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html
index 30bc56e..6f1422b 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -78,6 +78,8 @@
         </template>
         <template is="dom-if"
             if="[[showDetailsIsVisible_(deviceState, networkStateList)]]">
+          <!-- TODO(dbeam): this needs an aria-label. Maybe
+               [[activeNetworkState.name]]? -->
           <button class="subpage-arrow" is="paper-icon-button-light"
               on-tap="onShowDetailsTap_">
           </button>
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index 85b8e7c..34545a7 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -204,13 +204,15 @@
           <div class="list-frame vertical-list">
             <template is="dom-repeat" items="[[languages.enabled]]">
               <div class="list-item">
-                <paper-checkbox
-                    checked="[[item.spellCheckEnabled]]"
-                    on-change="onSpellCheckChange_"
-                    disabled$="[[!item.language.supportsSpellcheck]]">
+                <div class="start" on-tap="onSpellCheckChange_"
+                    actionable$="[[item.language.supportsSpellcheck]]">
                   [[item.language.displayName]]
-                </paper-checkbox>
-              </label>
+                </div>
+                <paper-toggle-button on-change="onSpellCheckChange_"
+                    disabled="[[!item.language.supportsSpellcheck]]"
+                    checked="[[item.spellCheckEnabled]]">
+                </paper-toggle-button>
+              </div>
             </template>
             <div class="list-item">
               <a is="action-link" class="list-button"
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.js b/chrome/browser/resources/settings/languages_page/languages_page.js
index 76147b0..5e3c1bb 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.js
+++ b/chrome/browser/resources/settings/languages_page/languages_page.js
@@ -65,8 +65,12 @@
    * @param {!{target: Element, model: !{item: !LanguageState}}} e
    */
   onSpellCheckChange_: function(e) {
-    this.languageHelper.toggleSpellCheck(e.model.item.language.code,
-                                         e.target.checked);
+    var item = e.model.item;
+    if (!item.language.supportsSpellcheck)
+      return;
+
+    this.languageHelper.toggleSpellCheck(item.language.code,
+                                         !item.spellCheckEnabled);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
index e192458..f45db56 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
@@ -75,10 +75,15 @@
                 $i18n{googlePayments}
               </span>
             </div>
-            <paper-icon-button id="addressMenu" icon="cr:more-vert"
-                tabindex$="[[tabIndex]]" alt="$i18n{overflowMenu}"
-                on-tap="onAddressMenuTap_">
-            </paper-icon-button>
+            <template is="dom-if" if="[[item.metadata.isLocal]]">
+              <paper-icon-button id="addressMenu" icon="cr:more-vert"
+                  on-tap="onAddressMenuTap_" alt="$i18n{overflowMenu}">
+              </paper-icon-button>
+            </template>
+            <template is="dom-if" if="[[!item.metadata.isLocal]]">
+              <button is="paper-icon-button-light" class="icon-external"
+                  on-tap="onRemoteEditAddressTap_" actionable></button>
+            </template>
           </div>
         </template>
       </div>
@@ -91,7 +96,6 @@
       <button id="menuEditAddress" class="dropdown-item"
           on-tap="onMenuEditAddressTap_">$i18n{editAddress}</button>
       <button id="menuRemoveAddress" class="dropdown-item"
-          hidden$="[[!activeAddress.metadata.isLocal]]"
           on-tap="onMenuRemoveAddressTap_">$i18n{removeAddress}</button>
     </dialog>
     <template is="dom-if" if="[[showAddressDialog_]]" restamp>
@@ -129,10 +133,15 @@
             <div class="expiration-column">
               <div id="creditCardExpiration"
                   class="expiration-date">[[expiration_(item)]]</div>
-              <paper-icon-button id="creditCardMenu" icon="cr:more-vert"
-                  tabindex$="[[tabIndex]]" alt="$i18n{overflowMenu}"
-                  on-tap="onCreditCardMenuTap_">
-              </paper-icon-button>
+              <template is="dom-if" if="[[item.metadata.isLocal]]">
+                <paper-icon-button id="creditCardMenu" icon="cr:more-vert"
+                    on-tap="onCreditCardMenuTap_" alt="$i18n{overflowMenu}">
+                </paper-icon-button>
+              </template>
+              <template is="dom-if" if="[[!item.metadata.isLocal]]">
+                <button is="paper-icon-button-light" class="icon-external"
+                    on-tap="onRemoteEditCreditCardTap_" actionable></button>
+              </template>
             </div>
           </div>
         </template>
@@ -146,7 +155,6 @@
       <button id="menuEditCreditCard" class="dropdown-item"
           on-tap="onMenuEditCreditCardTap_">$i18n{editCreditCard}</button>
       <button id="menuRemoveCreditCard" class="dropdown-item"
-          hidden$="[[!activeCreditCard.metadata.isLocal]]"
           on-tap="onMenuRemoveCreditCardTap_">$i18n{removeCreditCard}</button>
       <button id="menuClearCreditCard" class="dropdown-item"
           on-tap="onMenuClearCreditCardTap_"
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
index 5d8c75db..a064ef9 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js
@@ -31,7 +31,7 @@
       showAddressDialog_: Boolean,
 
       /**
-       * An array of saved addresses.
+       * An array of saved credit cards.
        * @type {!Array<!chrome.autofillPrivate.CreditCardEntry>}
        */
       creditCards: Array,
@@ -63,9 +63,13 @@
     onAddressMenuTap_: function(e) {
       var menuEvent = /** @type {!{model: !{item: !Object}}} */(e);
 
+      /* TODO(scottchen): drop the [dataHost][dataHost] once this bug is fixed:
+       https://github.com/Polymer/polymer/issues/2574 */
+      var item = menuEvent.model['dataHost']['dataHost'].item;
+
       // Copy item so dialog won't update model on cancel.
       this.activeAddress = /** @type {!chrome.autofillPrivate.AddressEntry} */(
-          Object.assign({}, menuEvent.model.item));
+          Object.assign({}, item));
 
       var dotsButton = /** @type {!HTMLElement} */ (Polymer.dom(e).localTarget);
       /** @type {!CrActionMenuElement} */ (
@@ -95,14 +99,15 @@
      */
     onMenuEditAddressTap_: function(e) {
       e.preventDefault();
-      if (this.activeAddress.metadata.isLocal)
-        this.showAddressDialog_ = true;
-      else
-        window.open(this.i18n('manageAddressesUrl'));
-
+      this.showAddressDialog_ = true;
       this.$.addressSharedMenu.close();
     },
 
+    /** @private */
+    onRemoteEditAddressTap_: function() {
+      window.open(this.i18n('manageAddressesUrl'));
+    },
+
     /**
      * Handles tapping on the "Remove" address button.
      * @private
@@ -120,10 +125,14 @@
     onCreditCardMenuTap_: function(e) {
       var menuEvent = /** @type {!{model: !{item: !Object}}} */(e);
 
+      /* TODO(scottchen): drop the [dataHost][dataHost] once this bug is fixed:
+       https://github.com/Polymer/polymer/issues/2574 */
+      var item = menuEvent.model['dataHost']['dataHost'].item;
+
       // Copy item so dialog won't update model on cancel.
       this.activeCreditCard =
           /** @type {!chrome.autofillPrivate.CreditCardEntry} */(
-              Object.assign({}, menuEvent.model.item));
+              Object.assign({}, item));
 
       var dotsButton = /** @type {!HTMLElement} */ (Polymer.dom(e).localTarget);
       /** @type {!CrActionMenuElement} */ (
@@ -158,14 +167,14 @@
      */
     onMenuEditCreditCardTap_: function(e) {
       e.preventDefault();
-      if (this.activeCreditCard.metadata.isLocal)
-        this.showCreditCardDialog_ = true;
-      else
-        window.open(this.i18n('manageCreditCardsUrl'));
-
+      this.showCreditCardDialog_ = true;
       this.$.creditCardSharedMenu.close();
     },
 
+    /** @private */
+    onRemoteEditCreditCardTap_: function() {
+      window.open(this.i18n('manageCreditCardsUrl'));
+    },
 
     /**
      * Handles tapping on the "Remove" credit card button.
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
index b71ed1d..f6e1e37 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html
@@ -23,10 +23,14 @@
               id="autofillManagerButton"
               actionable$="[[prefs.autofill.enabled.value]]">
             <div class="flex">
-              <div>$i18n{autofill}</div>
-              <div class="secondary">$i18n{autofillDetail}</div>
+              $i18n{autofill}
+              <div class="secondary" id="autofillSecondary">
+                $i18n{autofillDetail}
+              </div>
             </div>
-            <button class="subpage-arrow" is="paper-icon-button-light"></button>
+            <button class="subpage-arrow" is="paper-icon-button-light"
+                aria-label="$i18n{autofill}"
+                aria-describedby="autofillSecondary"></button>
           </div>
           <div class="secondary-action">
             <paper-toggle-button id="autofillToggle"
@@ -39,10 +43,14 @@
               id="passwordManagerButton"
               actionable$="[[prefs.profile.password_manager_enabled.value]]">
             <div class="flex">
-              <div>$i18n{passwords}</div>
-              <div class="secondary">$i18n{passwordsDetail}</div>
+              $i18n{passwords}
+              <div class="secondary" id="passwordsSecondary">
+                $i18n{passwordsDetail}
+              </div>
             </div>
-            <button class="subpage-arrow" is="paper-icon-button-light"></button>
+            <button class="subpage-arrow" is="paper-icon-button-light"
+                aria-label="$i18n{passwords}"
+                aria-describedby="passwordsSecondary"></button>
           </div>
           <div class="secondary-action">
             <paper-toggle-button id="passwordToggle"
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
index 4d709a9..952457c 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
@@ -13,7 +13,7 @@
       }
 
       paper-icon-button {
-        -webkit-margin-end: -8px;
+        @apply(--cr-paper-icon-button-margin);
         color: var(--paper-grey-600);
       }
 
diff --git a/chrome/browser/resources/settings/people_page/camera.html b/chrome/browser/resources/settings/people_page/camera.html
index debaaf07..515896ad 100644
--- a/chrome/browser/resources/settings/people_page/camera.html
+++ b/chrome/browser/resources/settings/people_page/camera.html
@@ -9,8 +9,8 @@
   <template>
     <style include="settings-shared">
       #perspectiveBox {
-        -webkit-perspective: 600px;
         height: 228px;
+        perspective: 600px;
         width: 228px;
       }
 
@@ -22,7 +22,7 @@
       }
 
       #userImageStreamCrop.flip-x {
-        -webkit-transform: rotateY(180deg);
+        transform: rotateY(180deg);
       }
 
       paper-spinner {
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_browser_proxy.html b/chrome/browser/resources/settings/people_page/fingerprint_browser_proxy.html
index 7b332d0..1e90fb8 100644
--- a/chrome/browser/resources/settings/people_page/fingerprint_browser_proxy.html
+++ b/chrome/browser/resources/settings/people_page/fingerprint_browser_proxy.html
@@ -1 +1 @@
-<script src="/people_page/fingerprint_browser_proxy.js"></script>
+<script src="fingerprint_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_list.html b/chrome/browser/resources/settings/people_page/fingerprint_list.html
index 5483336..4a5f4f1 100644
--- a/chrome/browser/resources/settings/people_page/fingerprint_list.html
+++ b/chrome/browser/resources/settings/people_page/fingerprint_list.html
@@ -5,7 +5,8 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
-<link rel="import" href="/settings_shared_css.html">
+<link rel="import" href="setup_fingerprint_dialog.html">
+<link rel="import" href="../settings_shared_css.html">
 
 <dom-module id="settings-fingerprint-list">
   <template>
@@ -25,12 +26,16 @@
       </template>
     </iron-list>
     <div class="settings-box first radio-indent">
-      <paper-button class="action-button" on-tap="onAddFingerprint_"
+      <paper-button class="action-button" on-tap="openAddFingerprintDialog_"
           disabled="[[!canAddNewFingerprint_(fingerprints_.*)]]">
         [[getFingerprintButtonText_(fingerprints_.*)]]
       </paper-button>
     </div>
     <i>$i18n{lockScreenFingerprintWarning}</i>
+
+    <settings-setup-fingerprint-dialog id="setupFingerprint"
+        on-add-fingerprint="onAddFingerprint_">
+    </settings-setup-fingerprint-dialog>
   </template>
   <script src="fingerprint_list.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_list.js b/chrome/browser/resources/settings/people_page/fingerprint_list.js
index 46deca9..7a0673dd 100644
--- a/chrome/browser/resources/settings/people_page/fingerprint_list.js
+++ b/chrome/browser/resources/settings/people_page/fingerprint_list.js
@@ -77,6 +77,14 @@
    */
   canAddNewFingerprint_: function() {
     return this.fingerprints_.length < MAX_NUMBER_FINGERPRINTS_ALLOWED;
-  }
+  },
+
+  /**
+   * Opens the setup fingerprint dialog.
+   * @private
+   */
+  openAddFingerprintDialog_: function() {
+    this.$.setupFingerprint.open();
+  },
 });
 })();
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_progress_arc.html b/chrome/browser/resources/settings/people_page/fingerprint_progress_arc.html
new file mode 100644
index 0000000..ba4553ad4
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/fingerprint_progress_arc.html
@@ -0,0 +1,8 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<dom-module id="settings-fingerprint-progress-arc">
+  <template>
+    <canvas id="canvas"></canvas>
+  </template>
+  <script src="fingerprint_progress_arc.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_progress_arc.js b/chrome/browser/resources/settings/people_page/fingerprint_progress_arc.js
new file mode 100644
index 0000000..4e66ebe
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/fingerprint_progress_arc.js
@@ -0,0 +1,163 @@
+// 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.
+
+(function() {
+
+/**
+ * The time in millseconds of the animation updates.
+ * @const {number}
+ */
+var ANIMATE_TICKS_MS = 20;
+
+/**
+ * The duration in millseconds of the animation of the progress circle when the
+ * user is touching the scanner.
+ * @const {number}
+ */
+var ANIMATE_DURATION_MS = 200;
+
+/**
+ * The radius of the add fingerprint progress circle.
+ * @const {number}
+ */
+var CANVAS_CIRCLE_RADIUS = 50;
+
+/**
+ * The thickness of the add fingerprint progress circle.
+ * @const {number}
+ */
+var CANVAS_CIRCLE_STROKE_WIDTH = 4;
+
+/**
+ * The color of the canvas circle background.
+ * @const {string}
+ */
+var CANVAS_CIRCLE_BACKGROUND_COLOR = 'rgba(0, 0, 0, 1.0)';
+
+/**
+ * The color of the arc/circle which indicates setup progress.
+ * @const {string}
+ */
+var CANVAS_CIRCLE_PROGRESS_COLOR = 'rgba(0, 0, 255, 1.0)';
+
+/**
+ * The color of the canvas circle shadow.
+ * @const {string}
+ */
+var CANVAS_CIRCLE_SHADOW_COLOR = 'rgba(0, 0, 0, 0.5)';
+
+Polymer({
+  is: 'settings-fingerprint-progress-arc',
+
+  // Also put these values as member values so they can be overriden by tests
+  // and the tests do not need to be changed everytime the UI is.
+  /** @private {number} */
+  canvasCircleRadius_: CANVAS_CIRCLE_RADIUS,
+  /** @private {number} */
+  canvasCircleStrokeWidth_: CANVAS_CIRCLE_STROKE_WIDTH,
+  /** @private {number} */
+  canvasCircleBackgroundColor_: CANVAS_CIRCLE_BACKGROUND_COLOR,
+  /** @private {number} */
+  canvasCircleProgressColor_: CANVAS_CIRCLE_PROGRESS_COLOR,
+  /** @private {number} */
+  canvasCircleShadowColor_: CANVAS_CIRCLE_SHADOW_COLOR,
+
+  /**
+   * Draws an arc on the canvas element around the center with radius
+   * |CANVAS_CIRCLE_RADIUS|.
+   * @param {number} startAngle The start angle of the arc we want to draw.
+   * @param {number} endAngle The end angle of the arc we want to draw.
+   * @param {string} color The color of the arc we want to draw. The string is
+   *     in the format rgba(r',g',b',a'). r', g', b' are values from [0-255]
+   *     and a' is a value from [0-1].
+   */
+  drawArc: function(startAngle, endAngle, color) {
+    var c = this.$.canvas;
+    var ctx = c.getContext('2d');
+
+    ctx.beginPath();
+    ctx.arc(c.width / 2, c.height / 2, this.canvasCircleRadius_, startAngle,
+        endAngle);
+    ctx.lineWidth = this.canvasCircleStrokeWidth_;
+    ctx.strokeStyle = color;
+    ctx.stroke();
+  },
+
+  /**
+   * Draws a circle on the canvas element around the center with radius
+   * |CANVAS_CIRCLE_RADIUS| and color |CANVAS_CIRCLE_BACKGROUND_COLOR|.
+   */
+  drawBackgroundCircle: function() {
+    this.drawArc(0, 2 * Math.PI, this.canvasCircleBackgroundColor_);
+  },
+
+  /**
+   * Draws a circular shadow around the center with radius
+   * |CANVAS_CIRCLE_RADIUS|.
+   * @param {number} blur
+   * @param {number} offsetX
+   * @param {number} offsetY
+   */
+  drawShadow: function(blur, offsetX, offsetY) {
+    var c = this.$.canvas;
+    var ctx = c.getContext('2d');
+
+    ctx.beginPath();
+    ctx.translate(-c.width, 0);
+    ctx.shadowOffsetX = c.width + offsetX;
+    ctx.shadowOffsetY = 0;
+    ctx.shadowColor = this.canvasCircleShadowColor_;
+    ctx.shadowBlur = blur;
+    ctx.arc(c.width / 2, c.height / 2,
+        this.canvasCircleRadius_ - this.canvasCircleStrokeWidth_ / 2 + blur / 2,
+        0, 2*Math.PI);
+    ctx.stroke();
+    ctx.translate(c.width, 0);
+  },
+
+  /**
+   * Animates the progress the circle. Animates an arc that starts at the top of
+   * the circle to startAngle, to an arc that starts at the top of the circle to
+   * endAngle.
+   * @param {number} startAngle The start angle of the arc we want to draw.
+   * @param {number} endAngle The end angle of the arc we want to draw.
+   */
+  animate: function(startAngle, endAngle) {
+    var currentAngle = startAngle;
+    // The value to update the angle by each tick.
+    var step = (endAngle - startAngle) /
+        (ANIMATE_DURATION_MS / ANIMATE_TICKS_MS);
+    var id = setInterval(doAnimate.bind(this), ANIMATE_TICKS_MS);
+    // Circles on html canvas have 0 radians on the positive x-axis and go in
+    // clockwise direction. We want to start at the top of the circle which is
+    // 3pi/2.
+    var start = 3 * Math.PI / 2;
+
+    // Function that is called every tick of the interval, draws the arc a bit
+    // closer to the final destination each tick, until it reaches the final
+    // destination.
+    function doAnimate() {
+      if (currentAngle >= endAngle)
+        clearInterval(id);
+
+      // Clears the canvas and draws the new progress circle.
+      this.clearCanvas();
+      this.drawArc(start, start + currentAngle,
+          this.canvasCircleProgressColor_);
+      this.drawArc(start + currentAngle, start,
+          this.canvasCircleBackgroundColor_);
+      currentAngle += step;
+    }
+  },
+
+  /**
+   * Clear the canvas of any renderings.
+   */
+  clearCanvas: function() {
+    var c = this.$.canvas;
+    var ctx = c.getContext('2d');
+    ctx.clearRect(0, 0, c.width, c.height);
+  },
+});
+})();
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html
index b20ea35e..9646103 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.html
+++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -55,11 +55,13 @@
               actionable>
             <div class="start">
               $i18n{lockScreenEditFingerprints}
-              <div class="secondary">
+              <div class="secondary" id="lockScreenEditFingerprintsSecondary">
                 $i18n{lockScreenEditFingerprintsDescription}
               </div>
             </div>
-            <button class="subpage-arrow" is="paper-icon-button-light"></button>
+            <button class="subpage-arrow" is="paper-icon-button-light"
+                aria-label="$i18n{lockScreenEditFingerprints}"
+                aria-describedby="lockScreenEditFingerprintsSecondary"></button>
           </div>
         </iron-collapse>
       </template>
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 0f5fe6c..363a7a64 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -123,12 +123,14 @@
 </if>
               <div class="flex text-elide">
                 <span id="profile-name">[[profileName_]]</span>
-                <div class="secondary" hidden="[[!syncStatus.signedIn]]">
+                <div class="secondary" hidden="[[!syncStatus.signedIn]]"
+                    id="profileNameSecondary">
                   [[syncStatus.signedInUsername]]
                 </div>
               </div>
-              <button class="subpage-arrow" is="paper-icon-button-light">
-              </button>
+              <button class="subpage-arrow" is="paper-icon-button-light"
+                  aria-labelledby="profile-name"
+                  aria-describedby="profileNameSecondary"></button>
             </div>
 <if expr="not chromeos">
             <template is="dom-if" if="[[showSignin_(syncStatus)]]">
@@ -165,7 +167,7 @@
         <template is="dom-if" if="[[syncStatus.domain]]">
           <div class="settings-box">
             <div class="icon-container">
-              <iron-icon icon="cr:domain"></iron-icon>
+              <iron-icon icon="cr20:domain"></iron-icon>
             </div>
             <div class="middle"
                 inner-h-t-m-l="[[getDomainHtml_(syncStatus.domain)]]">
@@ -184,12 +186,15 @@
               </iron-icon>
             </div>
             <div class="middle">
-              <div>$i18n{sync}</div>
-              <div class$="secondary [[getSyncStatusTextClass_(syncStatus)]]">
+              $i18n{sync}
+              <div class$="secondary [[getSyncStatusTextClass_(syncStatus)]]"
+                  id="syncSecondary">
                 [[syncStatus.statusText]]
               </div>
             </div>
-            <button class="subpage-arrow" is="paper-icon-button-light"></button>
+            <button class="subpage-arrow" is="paper-icon-button-light"
+                aria-label="$i18n{sync}"
+                aria-describedby="syncSecondary"></button>
           </div>
         </template>
 
@@ -200,10 +205,14 @@
             <div id="googleg-logo"></div>
           </div>
           <div class="middle">
-            <div>$i18n{personalizeGoogleServicesTitle}</div>
-            <div class="secondary">$i18n{personalizeGoogleServicesText}</div>
+            $i18n{personalizeGoogleServicesTitle}
+            <div class="secondary" id="personalizeGoogleServicesSecondary">
+              $i18n{personalizeGoogleServicesText}
+            </div>
           </div>
-          <button class="icon-external" is="paper-icon-button-light"></button>
+          <button class="icon-external" is="paper-icon-button-light"
+              aria-label="$i18n{personalizeGoogleServicesTitle}"
+              aria-describedby="personalizeGoogleServicesSecondary"></button>
         </div>
 
 <if expr="chromeos">
@@ -221,12 +230,14 @@
                on-tap="onConfigureLockTap_">
             <div class="start">
               $i18n{lockScreenTitle}
-              <div class="secondary">
+              <div class="secondary" id="lockScreenSecondary">
                 [[getPasswordState_(hasPin,
                                     prefs.settings.enable_screen_lock.value)]]
               </div>
             </div>
-            <button class="subpage-arrow" is="paper-icon-button-light"></button>
+            <button class="subpage-arrow" is="paper-icon-button-light"
+                aria-label="$i18n{lockScreenTitle}"
+                aria-describedby="lockScrenSecondary"></button>
           </div>
         </template>
 
@@ -278,13 +289,15 @@
         <div id="manage-other-people-subpage-trigger"
             class="settings-box" on-tap="onManageOtherPeople_" actionable>
           <div class="start">$i18n{manageOtherPeople}</div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{manageOtherPeople}"></button>
         </div>
 
 <if expr="not chromeos">
         <div class="settings-box" on-tap="onImportDataTap_" actionable>
           <div class="start">$i18n{importTitle}</div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{importTitle}"></button>
         </div>
 </if>
 
@@ -293,11 +306,13 @@
               on-tap="onManageSupervisedUsers_" actionable>
             <div class="start">
               $i18n{manageSupervisedUsers}
-              <div class="secondary">
+              <div class="secondary" id="manageSupervisedUsersSecondary">
                 $i18n{manageSupervisedUsersDescription}
               </div>
             </div>
-            <button class="icon-external" is="paper-icon-button-light"></button>
+            <button class="icon-external" is="paper-icon-button-light"
+                aria-label="$i18n{manageSupervisedUsers}"
+                aria-describedby="manageSupervisedUsersSecondary"></button>
           </div>
         </template>
       </neon-animatable>
diff --git a/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html
new file mode 100644
index 0000000..4e2b71f
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.html
@@ -0,0 +1,72 @@
+<link rel="import" href="chrome://resources/cr_elements/icons.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
+<link rel="import" href="../icons.html">
+<link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="fingerprint_browser_proxy.html">
+<link rel="import" href="fingerprint_progress_arc.html">
+
+<dom-module id="settings-setup-fingerprint-dialog">
+  <template>
+    <style include="settings-shared">
+      #dialog {
+        min-width: 500px;
+        width: 500px;
+      }
+
+      /* Use this instead of hidden so that the dialog does not resize when the
+         problem appears or disappears. */
+      #problemDiv[invisible] {
+        visibility: hidden;
+      }
+
+      #image {
+        min-height: 50px;
+        min-width: 50px;
+      }
+
+      #image[step='3'] {
+        --iron-icon-fill-color: blue;
+      }
+    </style>
+
+    <dialog is="cr-dialog" id="dialog" on-close="close">
+      <div class="title">$i18n{configureFingerprintTitle}</div>
+        <!-- TODO(sammiequon): on-click and on-dblclik are temporary, remove
+          once we can interact with the fingerprint hardware -->
+      <div class="body" on-click="handleClick_"
+          on-dblclick="handleDoubleClick_">
+        <div class="settings-box first">
+          <span class="middle">[[getInstructionMessage_(step_)]]</span>
+        </div>
+        <settings-fingerprint-progress-arc id="arc">
+        </settings-fingerprint-progress-arc>
+        <iron-icon id="image" icon="settings:fingerprint"
+            step$="[[step_]]">
+        </iron-icon>
+        <div id="problemDiv" class="settings-box first"
+            invisible$="[[!problemMessage_]]">
+          <iron-icon icon="settings:warning"></iron-icon>
+          <span class="middle">[[problemMessage_]]</span>
+        </div>
+
+        <div class="button-strip">
+          <paper-button class="cancel-button" on-tap="onCancelTap_"
+              disabled$="[[enableContinue_(step_)]]">
+            $i18n{cancel}
+          </paper-button>
+
+          <paper-button class="action-button" on-tap="onContinueTap_"
+              disabled$="[[!enableContinue_(step_)]]">
+            $i18n{configurePinContinueButton}
+          </paper-button>
+        </div>
+      </div>
+    </dialog>
+  </template>
+
+  <script src="setup_fingerprint_dialog.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.js b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.js
new file mode 100644
index 0000000..b9774af
--- /dev/null
+++ b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.js
@@ -0,0 +1,229 @@
+// 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.
+
+(function() {
+
+/**
+ * The steps in the fingerprint setup flow.
+ * @enum {number}
+ */
+var FingerprintSetupStep = {
+  LOCATE_SCANNER: 1,      // The user needs to locate the scanner.
+  MOVE_FINGER: 2,         // The user needs to move finger around the scanner.
+  READY: 3                // The scanner has read the fingerprint successfully.
+};
+
+/**
+ * The estimated amount of complete scans needed to enroll a fingerprint. Used
+ * to help us estimate the progress of an enroll session.
+ * @const {number}
+ */
+var SUCCESSFUL_SCANS_TO_COMPLETE = 5;
+
+Polymer({
+  is: 'settings-setup-fingerprint-dialog',
+
+  behaviors: [I18nBehavior],
+
+  properties: {
+    /**
+     * The problem message to display.
+     * @private
+     */
+    problemMessage_: {
+      type: String,
+      value: '',
+    },
+
+    /**
+     * The setup phase we are on.
+     * @type {!FingerprintSetupStep}
+     * @private
+     */
+    step_: {
+      type: Number,
+      value: FingerprintSetupStep.LOCATE_SCANNER
+    },
+  },
+
+  /**
+   * The number of scans that have been received during setup. This is used to
+   * approximate the progress of the setup.
+   * @type {number}
+   * @private
+   */
+  receivedScanCount_: 0,
+
+  /**
+   * Opens the dialog.
+   */
+  open: function() {
+    this.$.arc.drawBackgroundCircle();
+    this.$.arc.drawShadow(10, 0, 0);
+    this.$.dialog.showModal();
+  },
+
+  /**
+   * Closes the dialog.
+   */
+  close: function() {
+    this.reset_();
+  },
+
+  /**
+   * Resets the dialog to its start state. Call this when the dialog gets
+   * closed.
+   * @private
+   */
+  reset_: function() {
+    this.step_ = FingerprintSetupStep.LOCATE_SCANNER;
+    this.receivedScanCount_ = 0;
+    this.$.arc.clearCanvas();
+  },
+
+  /**
+   * Checks if the the fingerprint can be submitted and added.
+   * @private
+   * @return {boolean}
+   */
+  enableContinue_: function(step) {
+    return step == FingerprintSetupStep.READY;
+  },
+
+  /**
+   * Closes the dialog.
+   * @private
+   */
+  onCancelTap_: function() {
+    if (this.$.dialog.open)
+      this.$.dialog.close();
+  },
+
+  /**
+   * Closes the dialog.
+   * @private
+   */
+  onContinueTap_: function() {
+    this.fire('add-fingerprint');
+    if (this.$.dialog.open)
+      this.$.dialog.close();
+  },
+
+  /**
+   * Function to help test functionality without the fingerprint sensor.
+   * TODO(sammiequon): Remove this when the fingerprint proxy is ready.
+   * @param {Event} e The mouse click event.
+   * @private
+   */
+  handleClick_: function(e) {
+    this.onScanReceived_(settings.FingerprintResultType.SUCCESS,
+        this.receivedScanCount_ == SUCCESSFUL_SCANS_TO_COMPLETE - 1);
+  },
+
+  /**
+   * Function to help test functionality without the fingerprint sensor.
+   * TODO(sammiequon): Remove this when the fingerprint proxy is ready.
+   * @param {Event} e The mouse click event.
+   * @private
+   */
+  handleDoubleClick_: function(e) {
+    this.onScanReceived_(settings.FingerprintResultType.TOO_FAST,
+        false /*isComplete*/);
+  },
+
+  /**
+   * Advances steps, shows problems and animates the progress as needed based on
+   * scan results.
+   * @param {!settings.FingerprintResultType} scanResult The result from the
+   *     scanner.
+   * @param {bool} isComplete Whether the enroll session is complete.
+   * @private
+   */
+  onScanReceived_: function(scanResult, isComplete) {
+    switch (this.step_) {
+      case FingerprintSetupStep.LOCATE_SCANNER:
+      case FingerprintSetupStep.MOVE_FINGER:
+        if (this.step_ == FingerprintSetupStep.LOCATE_SCANNER) {
+          // Clear canvas because there will be shadows present at this step.
+          this.$.arc.clearCanvas();
+          this.$.arc.drawBackgroundCircle();
+
+          this.step_ = FingerprintSetupStep.MOVE_FINGER;
+          this.receivedScanCount_ = 0;
+        }
+        var slice = 2 * Math.PI / SUCCESSFUL_SCANS_TO_COMPLETE;
+        if (isComplete) {
+          this.problemMessage_ = '';
+          this.step_ = FingerprintSetupStep.READY;
+          this.$.arc.animate(this.receivedScanCount_ * slice, 2 * Math.PI);
+        } else if (scanResult != settings.FingerprintResultType.SUCCESS) {
+          this.setProblem_(scanResult);
+        } else {
+          this.problemMessage_ = '';
+          this.$.arc.animate(this.receivedScanCount_ * slice,
+              (this.receivedScanCount_ + 1) * slice);
+          this.receivedScanCount_++;
+        }
+        break;
+      case FingerprintSetupStep.READY:
+        break;
+      default:
+        assertNotReached();
+        break;
+    }
+  },
+
+  /**
+   * Sets the instructions based on which phase of the fingerprint setup we are
+   * on.
+   * @param {!FingerprintSetupStep} step The current step the fingerprint setup
+   *     is on.
+   * @private
+   */
+  getInstructionMessage_: function(step) {
+    switch (step) {
+      case FingerprintSetupStep.LOCATE_SCANNER:
+        return this.i18n('configureFingerprintInstructionLocateScannerStep');
+      case FingerprintSetupStep.MOVE_FINGER:
+        return this.i18n('configureFingerprintInstructionMoveFingerStep');
+      case FingerprintSetupStep.READY:
+        return this.i18n('configureFingerprintInstructionReadyStep');
+    }
+    assertNotReached();
+  },
+
+  /**
+   * Set the problem message based on the result from the fingerprint scanner.
+   * @param {!settings.FingerprintResultType} scanResult The result the
+   *     fingerprint scanner gives.
+   * @private
+   */
+  setProblem_: function(scanResult) {
+    switch (scanResult) {
+      case settings.FingerprintResultType.SUCCESS:
+        this.problemMessage_ = '';
+        break;
+      case settings.FingerprintResultType.PARTIAL_DATA:
+        this.problemMessage_ = this.i18n('configureFingerprintPartialData');
+        break;
+      case settings.FingerprintResultType.INSUFFICIENT_DATA:
+        this.problemMessage_ =
+            this.i18n('configureFingerprintInsufficientData');
+        break;
+      case settings.FingerprintResultType.SENSOR_DIRTY:
+        this.problemMessage_ = this.i18n('configureFingerprintSensorDirty');
+        break;
+      case settings.FingerprintResultType.TOO_SLOW:
+        this.problemMessage_ = this.i18n('configureFingerprintTooSlow');
+        break;
+      case settings.FingerprintResultType.TOO_FAST:
+        this.problemMessage_ = this.i18n('configureFingerprintTooFast');
+        break;
+      default:
+        assertNotReached();
+        break;
+    }
+  },
+});
+})();
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html
index a3e583a..191147e3 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -185,9 +185,13 @@
           on-tap="onManageSyncedDataTap_">
         <div class="start">
           $i18n{manageSyncedDataTitle}
-          <div class="secondary">$i18n{manageSyncedDataDescription}</div>
+          <div class="secondary" id="manageSyncedDataSecondary">
+            $i18n{manageSyncedDataDescription}
+          </div>
         </div>
-        <button class="icon-external" is="paper-icon-button-light"></button>
+        <button class="icon-external" is="paper-icon-button-light"
+            aria-label="$i18n{manageSyncedDataTitle}"
+            aria-describedby="manageSyncedDataSecondary"></button>
       </div>
 
       <div class="settings-box two-line single-column">
diff --git a/chrome/browser/resources/settings/printing_page/cloud_printers.html b/chrome/browser/resources/settings/printing_page/cloud_printers.html
index 9eaa0a3..2321a7bf 100644
--- a/chrome/browser/resources/settings/printing_page/cloud_printers.html
+++ b/chrome/browser/resources/settings/printing_page/cloud_printers.html
@@ -23,11 +23,13 @@
     <div class="settings-box two-line" on-tap="onManageTap_" actionable>
       <div class="start">
         $i18n{printingManageCloudPrintDevices}
-        <div class="secondary">
+        <div class="secondary" id="manageCloudPrintSecondary">
           $i18n{printingManageCloudPrintDevicesDescription}
         </div>
       </div>
-      <button class="icon-external" is="paper-icon-button-light"></button>
+      <button class="icon-external" is="paper-icon-button-light"
+          aria-label="$i18n{printingManageCloudPrintDevices}"
+          aria-describedby="manageCloudPrintSecondary"></button>
     </div>
   </template>
   <script src="cloud_printers.js"></script>
diff --git a/chrome/browser/resources/settings/printing_page/printing_page.html b/chrome/browser/resources/settings/printing_page/printing_page.html
index 85f5e26..dbfa5cf 100644
--- a/chrome/browser/resources/settings/printing_page/printing_page.html
+++ b/chrome/browser/resources/settings/printing_page/printing_page.html
@@ -23,10 +23,9 @@
         <template is="dom-if" if="[[showCupsPrintingFeatures_]]">
           <div id="cupsPrinters" class="settings-box first"
               on-tap="onTapCupsPrinters_" actionable>
-            <div class="start">
-              $i18n{cupsPrintersTitle}
-            </div>
-            <button class="subpage-arrow" is="paper-icon-button-light"></button>
+            <div class="start">$i18n{cupsPrintersTitle}</div>
+            <button class="subpage-arrow" is="paper-icon-button-light"
+                aria-label="$i18n{cupsPrintersTitle}"></button>
           </div>
         </template>
 </if>
@@ -34,9 +33,13 @@
             on-tap="onTapCloudPrinters_" actionable>
           <div class="start">
             $i18n{cloudPrintersTitle}
-            <div class="secondary">$i18n{cloudPrintersTitleDescription}</div>
+            <div class="secondary" id="cloudPrintersSecondary">
+              $i18n{cloudPrintersTitleDescription}
+            </div>
           </div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{cloudPrintersTitle}"
+              aria-describedby="cloudPrintersSecondary"></button>
         </div>
       </neon-animatable>
 <if expr="chromeos">
diff --git a/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp b/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp
index 599ba78..c842549 100644
--- a/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp
@@ -23,6 +23,7 @@
         '../site_settings/compiled_resources2.gyp:constants',
         '../site_settings/compiled_resources2.gyp:site_data_details_subpage',
         'privacy_page_browser_proxy',
+        '<(EXTERNS_GYP):settings_private',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index f1d1a282..978ac155 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -38,20 +38,6 @@
       button[is='paper-icon-button-light'].icon-help {
         background-image: url(../images/help_outline.svg);
       }
-
-      .settings-row-min-height {
-        min-height: var(--settings-row-min-height);
-      }
-
-      #metricsReporting paper-tooltip {
-        --paper-tooltip: var(--cr-policy-tooltip);
-      }
-
-      #metricsReportingControl,
-      #indicator,
-      #restart {
-        -webkit-margin-start: var(--checkbox-spacing);
-      }
     </style>
     <template is="dom-if" if="[[showClearBrowsingDataDialog_]]" restamp>
       <settings-clear-browsing-data-dialog prefs="{{prefs}}"
@@ -83,11 +69,13 @@
           </settings-toggle-button>
         </div>
         <div class="settings-box">
-          <div class="start">$i18n{safeBrowsingEnableExtendedReporting}</div>
-          <paper-toggle-button id="safeBrowsingExtendedReportingControl"
-              on-tap="onSafeBrowsingExtendedReportingControlTap_"
-              checked="[[safeBrowsingExtendedReportingEnabled_]]">
-          </paper-toggle-button>
+          <settings-toggle-button class="start"
+              id="safeBrowsingExtendedReportingControl"
+              pref="[[safeBrowsingExtendedReportingPref_]]"
+              label="$i18n{safeBrowsingEnableExtendedReporting}"
+              on-settings-boolean-control-change="onSberChange_"
+              no-set-pref>
+          </settings-toggle-button>
         </div>
         <div class="settings-box">
           <settings-toggle-button class="start"
@@ -106,24 +94,19 @@
 </if><!-- chromeos -->
 <if expr="not chromeos">
         <div class="settings-box">
-          <div class="start">$i18n{enableLogging}</div>
-          <template is="dom-if" if="[[showRestart_]]" restamp>
-            <paper-button on-tap="onRestartTap_" id="restart">
-              $i18n{restart}
-            </paper-button>
-          </template>
-          <template is="dom-if" if="[[metricsReporting_.managed]]" restamp>
-            <iron-icon id="indicator" tabindex=0 icon="cr:domain"></iron-icon>
-            <paper-tooltip for="indicator" position="top"
-                fit-to-visible-bounds>
-              $i18n{controlledSettingPolicy}
-            </paper-tooltip>
-          </template>
-          <paper-toggle-button id="metricsReportingControl"
-              on-tap="onMetricsReportingControlTap_"
-              checked="[[metricsReporting_.enabled]]"
-              disabled="[[metricsReporting_.managed]]">
-          </paper-toggle-button>
+          <settings-toggle-button class="start"
+              id="metricsReportingControl"
+              pref="[[metricsReportingPref_]]"
+              label="$i18n{enableLogging}"
+              on-settings-boolean-control-change="onMetricsReportingChange_"
+              no-set-pref>
+            <template is="dom-if" if="[[showRestart_]]" restamp>
+              <paper-button on-tap="onRestartTap_" id="restart"
+                  class="more-actions">
+                $i18n{restart}
+              </paper-button>
+            </template>
+          </settings-toggle-button>
         </div>
 </if><!-- not chromeos -->
 </if><!-- _google_chrome -->
@@ -161,13 +144,19 @@
             actionable on-tap="onManageCertificatesTap_">
           <div class="start">
             $i18n{manageCertificates}
-            <div class="secondary">$i18n{manageCertificatesDescription}</div>
+            <div class="secondary" id="manageCertificatesSecondary">
+              $i18n{manageCertificatesDescription}
+            </div>
           </div>
 <if expr="use_nss_certs">
-          <button is="paper-icon-button-light" class="subpage-arrow"></button>
+          <button is="paper-icon-button-light" class="subpage-arrow"
+              aria-label="$i18n{manageCertificates}"
+              aria-describedby="manageCertificatesSecondary"></button>
 </if>
 <if expr="not use_nss_certs">
-          <button is="paper-icon-button-light" class="icon-external"></button>
+          <button is="paper-icon-button-light" class="icon-external"
+              aria-label="$i18n{manageCertificates}"
+              aria-describedby="manageCertificatesSecondary"></button>
 </if>
         </div>
 </if>
@@ -176,17 +165,25 @@
             on-tap="onSiteSettingsTap_">
           <div class="start">
             [[siteSettingsPageTitle_()]]
-            <div class="secondary">$i18n{siteSettingsDescription}</div>
+            <div class="secondary" id="siteSettingsSecondary">
+              $i18n{siteSettingsDescription}
+            </div>
           </div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="[[siteSettingsPageTitle_()]]"
+              aria-describedby="siteSettingsSecondary"></button>
         </div>
         <div class="settings-box two-line" id="clearBrowsingData"
             on-tap="onClearBrowsingDataTap_" actionable>
           <div class="start">
             $i18n{clearBrowsingData}
-            <div class="secondary">$i18n{clearBrowsingDataDescription}</div>
+            <div class="secondary" id="clearBrowsingDataSecondary">
+              $i18n{clearBrowsingDataDescription}
+            </div>
           </div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{clearBrowsingData}"
+              aria-describedby="clearBrowsingDataSecondary"></button>
         </div>
       </neon-animatable>
 <if expr="use_nss_certs">
@@ -362,10 +359,9 @@
 <if expr="chromeos">
           <div actionable class="settings-box"
               on-tap="onAdobeFlashStorageClicked_">
-            <div class="start">
-              $i18n{adobeFlashStorage}
-            </div>
-            <button class="icon-external" is="paper-icon-button-light"></button>
+            <div class="start">$i18n{adobeFlashStorage}</div>
+            <button class="icon-external" is="paper-icon-button-light"
+                aria-label="$i18n{adobeFlashStorage}"></button>
           </div>
 </if>
           <category-setting-exceptions
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js
index d1cb9f9d..d1fb6d9 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.js
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -32,14 +32,28 @@
     pageVisibility: Object,
 
 // <if expr="_google_chrome and not chromeos">
-    /** @type {MetricsReporting} */
-    metricsReporting_: Object,
+    // TODO(dbeam): make a virtual.* pref namespace and set/get this normally
+    // (but handled differently in C++).
+    /** @private {chrome.settingsPrivate.PrefObject} */
+    metricsReportingPref_: {
+      type: Object,
+      value: function() {
+        // TODO(dbeam): this is basically only to appease PrefControlBehavior.
+        // Maybe add a no-validate attribute instead? This makes little sense.
+        return /** @type {chrome.settingsPrivate.PrefObject} */({});
+      },
+    },
 
     showRestart_: Boolean,
 // </if>
 
-    /** @private */
-    safeBrowsingExtendedReportingEnabled_: Boolean,
+    /** @private {chrome.settingsPrivate.PrefObject} */
+    safeBrowsingExtendedReportingPref_: {
+      type: Object,
+      value: function() {
+        return /** @type {chrome.settingsPrivate.PrefObject} */({});
+      },
+    },
 
     /** @private */
     showClearBrowsingDataDialog_: Boolean,
@@ -48,19 +62,17 @@
   ready: function() {
     this.ContentSettingsTypes = settings.ContentSettingsTypes;
 
-// <if expr="_google_chrome and not chromeos">
-    var boundSetMetricsReporting = this.setMetricsReporting_.bind(this);
-    this.addWebUIListener('metrics-reporting-change', boundSetMetricsReporting);
+    this.browserProxy_ = settings.PrivacyPageBrowserProxyImpl.getInstance();
 
-    var browserProxy = settings.PrivacyPageBrowserProxyImpl.getInstance();
-    browserProxy.getMetricsReporting().then(boundSetMetricsReporting);
+// <if expr="_google_chrome and not chromeos">
+    var setMetricsReportingPref = this.setMetricsReportingPref_.bind(this);
+    this.addWebUIListener('metrics-reporting-change', setMetricsReportingPref);
+    this.browserProxy_.getMetricsReporting().then(setMetricsReportingPref);
 // </if>
 
-    var boundSetSber = this.setSafeBrowsingExtendedReporting_.bind(this);
-    this.addWebUIListener('safe-browsing-extended-reporting-change',
-                          boundSetSber);
-    settings.PrivacyPageBrowserProxyImpl.getInstance()
-        .getSafeBrowsingExtendedReporting().then(boundSetSber);
+    var setSber = this.setSafeBrowsingExtendedReporting_.bind(this);
+    this.addWebUIListener('safe-browsing-extended-reporting-change', setSber);
+    this.browserProxy_.getSafeBrowsingExtendedReporting().then(setSber);
   },
 
   /** @protected */
@@ -75,8 +87,7 @@
     settings.navigateTo(settings.Route.CERTIFICATES);
 // </if>
 // <if expr="is_win or is_macosx">
-    settings.PrivacyPageBrowserProxyImpl.getInstance().
-        showManageSSLCertificates();
+    this.browserProxy_.showManageSSLCertificates();
 // </if>
   },
 
@@ -112,48 +123,67 @@
         'https://support.google.com/chrome/?p=settings_manage_exceptions');
   },
 
+  /** @private */
+  onSberChange_: function() {
+    var enabled = this.$.safeBrowsingExtendedReportingControl.checked;
+    this.browserProxy_.setSafeBrowsingExtendedReportingEnabled(enabled);
+  },
+
 // <if expr="_google_chrome and not chromeos">
   /** @private */
-  onMetricsReportingControlTap_: function() {
-    var browserProxy = settings.PrivacyPageBrowserProxyImpl.getInstance();
+  onMetricsReportingChange_: function() {
     var enabled = this.$.metricsReportingControl.checked;
-    browserProxy.setMetricsReportingEnabled(enabled);
+    this.browserProxy_.setMetricsReportingEnabled(enabled);
   },
 
   /**
    * @param {!MetricsReporting} metricsReporting
    * @private
    */
-  setMetricsReporting_: function(metricsReporting) {
+  setMetricsReportingPref_: function(metricsReporting) {
+    var hadPreviousPref = this.metricsReportingPref_.value !== undefined;
+    var pref = {
+      key: '',
+      type: chrome.settingsPrivate.PrefType.BOOLEAN,
+      value: metricsReporting.enabled,
+    };
+    if (metricsReporting.managed) {
+      pref.enforcement = chrome.settingsPrivate.Enforcement.ENFORCED;
+      pref.controlledBy = chrome.settingsPrivate.ControlledBy.USER_POLICY;
+    }
+
+    // Ignore the next change because it will happen when we set the pref.
+    this.metricsReportingPref_ = pref;
+
     // TODO(dbeam): remember whether metrics reporting was enabled when Chrome
     // started.
-    if (metricsReporting.managed) {
+    if (metricsReporting.managed)
       this.showRestart_ = false;
-    } else if (this.metricsReporting_ &&
-               metricsReporting.enabled != this.metricsReporting_.enabled) {
+    else if (hadPreviousPref)
       this.showRestart_ = true;
-    }
-    this.metricsReporting_ = metricsReporting;
   },
 
-  /** @private */
-  onRestartTap_: function() {
+  /**
+   * @param {Event} e
+   * @private
+   */
+  onRestartTap_: function(e) {
+    e.stopPropagation();
     settings.LifetimeBrowserProxyImpl.getInstance().restart();
   },
 // </if>
 
-  /** @private */
-  onSafeBrowsingExtendedReportingControlTap_: function() {
-    var browserProxy = settings.PrivacyPageBrowserProxyImpl.getInstance();
-    var enabled = this.$.safeBrowsingExtendedReportingControl.checked;
-    browserProxy.setSafeBrowsingExtendedReportingEnabled(enabled);
-  },
-
-  /** @param {boolean} enabled Whether reporting is enabled or not.
-    * @private
-    */
+  /**
+   * @param {boolean} enabled Whether reporting is enabled or not.
+   * @private
+   */
   setSafeBrowsingExtendedReporting_: function(enabled) {
-    this.safeBrowsingExtendedReportingEnabled_ = enabled;
+    // Ignore the next change because it will happen when we set the pref.
+    this.safeBrowsingExtendedReportingPref_ = {
+      key: '',
+      type: chrome.settingsPrivate.PrefType.BOOLEAN,
+      value: enabled,
+    };
   },
 
   /**
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.html b/chrome/browser/resources/settings/reset_page/reset_page.html
index d242059..ce27e28 100644
--- a/chrome/browser/resources/settings/reset_page/reset_page.html
+++ b/chrome/browser/resources/settings/reset_page/reset_page.html
@@ -16,10 +16,14 @@
     <div class="settings-box first two-line" id="resetProfile"
         on-tap="onShowResetProfileDialog_" actionable>
       <div class="start">
-        <div>$i18n{resetPageTitle}</div>
-        <div class="secondary">$i18n{resetPageDescription}</div>
+        $i18n{resetPageTitle}
+        <div class="secondary" id="resetProfileSecondary">
+          $i18n{resetPageDescription}
+        </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{resetPageTitle}"
+          aria-describedby="resetProfileSecondary"></button>
     </div>
     <template is="dom-if" if="[[showResetProfileDialog_]]" restamp>
       <settings-reset-profile-dialog on-close="onResetProfileDialogClose_">
@@ -29,10 +33,14 @@
     <div class="settings-box two-line" id="powerwash" actionable
         on-tap="onShowPowerwashDialog_" hidden="[[!allowPowerwash_]]">
       <div class="start">
-        <div>$i18n{powerwashTitle}</div>
-        <div class="secondary">$i18n{powerwashDescription}</div>
+        $i18n{powerwashTitle}
+        <div class="secondary" id="powerwashSecondary">
+          $i18n{powerwashDescription}
+        </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{powerwashTitle}"
+          aria-describedby="powerwashSecondary"></button>
     </div>
     <template is="dom-if" if="[[showPowerwashDialog_]]" restamp>
       <settings-powerwash-dialog on-close="onPowerwashDialogClose_">
diff --git a/chrome/browser/resources/settings/search_page/search_page.html b/chrome/browser/resources/settings/search_page/search_page.html
index fdbaac1..d1beb97 100644
--- a/chrome/browser/resources/settings/search_page/search_page.html
+++ b/chrome/browser/resources/settings/search_page/search_page.html
@@ -105,16 +105,16 @@
             <div class="settings-box two-line continuation indented"
                 on-tap="onManageAudioHistoryTap_" actionable>
               <div class="start">
-                <div>
-                  [[i18n('searchOkGoogleAudioHistoryLabel',
-                  hotwordInfo_.userName)]]
-                </div>
-                <div class="secondary">
+                [[i18n('searchOkGoogleAudioHistoryLabel',
+                       hotwordInfo_.userName)]]
+                <div class="secondary" id="audioHistorySecondary">
                   $i18n{searchOkGoogleAudioHistorySubtext}
                 </div>
               </div>
-              <button class="icon-external" is="paper-icon-button-light">
-              </button>
+              <button class="icon-external" is="paper-icon-button-light"
+                  aria-label="[[i18n('searchOkGoogleAudioHistoryLabel',
+                                     hotwordInfo_.userName)]]"
+                  aria-describedby="audioHistorySecondary"></button>
             </div>
           </template>
         </template>
@@ -124,11 +124,13 @@
             on-tap="onManageSearchEnginesTap_" actionable>
           <div class="start">
             $i18n{searchEnginesManage}
-            <div class="secondary">
+            <div class="secondary" id="manageSearchEnginesSecondary">
               $i18n{searchEnginesManageDescription}
             </div>
           </div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="$i18n{searchEnginesManage}"
+              aria-describedby="manageSearchEnginesSecondary"></button>
         </div>
       </neon-animatable>
       <template is="dom-if" route-path="/searchEngines">
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index ed42920..6ce1ff7 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -1200,6 +1200,24 @@
         <structure name="IDR_SETTINGS_PEOPLE_FINGERPRINT_LIST_HTML"
                    file="people_page/fingerprint_list.html"
                    type="chrome_html" />
+        <structure name="IDR_SETTINGS_PEOPLE_SETUP_FINGERPRINT_DIALOG_JS"
+                   file="people_page/setup_fingerprint_dialog.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_PEOPLE_SETUP_FINGERPRINT_DIALOG_HTML"
+                   file="people_page/setup_fingerprint_dialog.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_PEOPLE_FINGERPRINT_PROGRESS_ARC_JS"
+                   file="people_page/fingerprint_progress_arc.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_PEOPLE_FINGERPRINT_PROGRESS_ARC_HTML"
+                   file="people_page/fingerprint_progress_arc.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_PEOPLE_FINGERPRINT_BROWSER_PROXY_JS"
+                   file="people_page/fingerprint_browser_proxy.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_PEOPLE_FINGERPRINT_BROWSER_PROXY_HTML"
+                   file="people_page/fingerprint_browser_proxy.html"
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_KEYBOARD_PIN_JS"
                    file="people_page/pin_keyboard.js"
                    type="chrome_html"
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index 2cc33ce5..61a8dbec 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -350,13 +350,13 @@
 
       /* Provides the arrow which points at the anchor element. */
       .search-bubble-innards::after {
-        -webkit-transform: rotate(-45deg);
         background-color: var(--paper-yellow-500);
         content: '';
         height: 10px;
         left: 55px;
         position: absolute;
         top: -5px;
+        transform: rotate(-45deg);
         width: 10px;
         z-index: -1;
       }
@@ -364,9 +364,9 @@
       /* Turns the arrow direction downwards, when the bubble is placed above
        * the anchor element */
       .search-bubble-innards.above::after {
-        -webkit-transform: rotate(-135deg);
         bottom: -5px;
         top: auto;
+        transform: rotate(-135deg);
       }
     </style>
   </template>
diff --git a/chrome/browser/resources/settings/site_settings/site_data.html b/chrome/browser/resources/settings/site_settings/site_data.html
index d9387121..111aa75 100644
--- a/chrome/browser/resources/settings/site_settings/site_data.html
+++ b/chrome/browser/resources/settings/site_settings/site_data.html
@@ -42,9 +42,11 @@
           </div>
           <div class="middle">
             [[item.site]]
-            <div class="secondary">[[item.localData]]</div>
+            <div class="secondary" id="siteSecondary">[[item.localData]]</div>
           </div>
-          <button class="subpage-arrow" is="paper-icon-button-light"></button>
+          <button class="subpage-arrow" is="paper-icon-button-light"
+              aria-label="[[item.site]]"
+              aria-describedby="siteSecondary"></button>
         </div>
       </template>
     </div>
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html
index 5173746..fe3f2a56 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -69,7 +69,7 @@
                 <div class="selectable">[[item.displayName]]</div>
 
                 <!-- This div must not contain extra whitespace. -->
-                <div class="selectable secondary"
+                <div class="selectable secondary" id="siteDescription"
                     >[[computeSiteDescription_(item)]]</div>
               </div>
             </div>
@@ -84,8 +84,9 @@
             </paper-icon-button>
             <template is="dom-if" if="[[enableSiteSettings_]]">
               <div on-tap="onOriginTap_" actionable>
-                <button class="subpage-arrow" is="paper-icon-button-light">
-                </button>
+                <button class="subpage-arrow" is="paper-icon-button-light"
+                    aria-label="[[item.displayName]]"
+                    aria-describedby="siteDescription"></button>
               </div>
             </template>
           </div>
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js
index deb8f38c..319f04b 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.js
+++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -11,7 +11,7 @@
   'extension': 'cr:extension',
   'HostedApp': 'cr:extension',
   'platform_app': 'cr:extension',
-  'policy' : 'cr:domain',
+  'policy' : 'cr20:domain',
 };
 
 /**
diff --git a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
index 5cd0d26..7b140656 100644
--- a/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
+++ b/chrome/browser/resources/settings/site_settings_page/site_settings_page.html
@@ -20,7 +20,8 @@
           data-route="SITE_SETTINGS_ALL" on-tap="onTapNavigate_" actionable>
         <iron-icon icon="settings:list"></iron-icon>
         <div class="middle">$i18n{siteSettingsCategoryAllSites}</div>
-        <button class="subpage-arrow" is="paper-icon-button-light"></button>
+        <button class="subpage-arrow" is="paper-icon-button-light"
+            aria-label="$i18n{siteSettingsCategoryAllSites}"></button>
       </div>
       <div class="settings-box line-only">
       </div>
@@ -30,8 +31,8 @@
         data-route="SITE_SETTINGS_COOKIES" on-tap="onTapNavigate_" actionable>
       <iron-icon icon="settings:cookie"></iron-icon>
       <div class="middle">
-        <div>$i18n{siteSettingsCookies}</div>
-        <div class="secondary">
+        $i18n{siteSettingsCookies}
+        <div class="secondary" id="cookiesSecondary">
           [[defaultSettingLabel_(
               default_.cookies,
               '$i18n{siteSettingsCookiesAllowed}',
@@ -39,22 +40,26 @@
               '$i18n{deleteDataPostSession}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsCookies}"
+          aria-describedby="cookiesSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.GEOLOCATION]]"
         data-route="SITE_SETTINGS_LOCATION" on-tap="onTapNavigate_" actionable>
       <iron-icon icon="settings:location-on"></iron-icon>
       <div class="middle">
-        <div>$i18n{siteSettingsLocation}</div>
-        <div class="secondary">
+        $i18n{siteSettingsLocation}
+        <div class="secondary" id="locationSecondary">
           [[defaultSettingLabel_(
               default_.location,
               '$i18n{siteSettingsAskBeforeAccessing}',
               '$i18n{siteSettingsBlocked}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsLocation}"
+          aria-describedby="locationSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.CAMERA]]"
@@ -62,15 +67,17 @@
         on-tap="onTapNavigate_" actionable>
       <iron-icon icon="settings:videocam"></iron-icon>
       <div class="middle">
-        <div>$i18n{siteSettingsCamera}</div>
-        <div class="secondary">
+        $i18n{siteSettingsCamera}
+        <div class="secondary" id="cameraSecondary">
           [[defaultSettingLabel_(
               default_.mediaStreamCamera,
               '$i18n{siteSettingsAskBeforeAccessing}',
               '$i18n{siteSettingsBlocked}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsCamera}"
+          aria-describedby="cameraSecondary"></button>
     </div>
     <div class="settings-box two-line" category$="[[ContentSettingsTypes.MIC]]"
         data-route="SITE_SETTINGS_MICROPHONE" on-tap="onTapNavigate_"
@@ -78,14 +85,16 @@
       <iron-icon icon="settings:mic"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsMic}
-        <div class="secondary">
+        <div class="secondary" id="micSecondary">
           [[defaultSettingLabel_(
               default_.mediaStreamMic,
               '$i18n{siteSettingsAskBeforeAccessing}',
               '$i18n{siteSettingsBlocked}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsMic}"
+          aria-describedby="micSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.NOTIFICATIONS]]"
@@ -94,14 +103,16 @@
       <iron-icon icon="settings:notifications"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsNotifications}
-        <div class="secondary">
+        <div class="secondary" id="notificationsSecondary">
           [[defaultSettingLabel_(
               default_.notifications,
               '$i18n{siteSettingsAskBeforeSending}',
               '$i18n{siteSettingsBlocked}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsNotifications}"
+          aria-describedby="notificationsSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.JAVASCRIPT]]"
@@ -110,14 +121,16 @@
       <iron-icon icon="settings:input"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsJavascript}
-        <div class="secondary">
+        <div class="secondary" is="javascriptSecondary">
           [[defaultSettingLabel_(
               default_.javascript,
               '$i18n{siteSettingsAllowed}',
               '$i18n{siteSettingsBlocked}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsJavascript}"
+          aria-describedby="javascriptSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.PLUGINS]]"
@@ -125,7 +138,7 @@
       <iron-icon icon="cr:extension"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsFlash}
-        <div class="secondary">
+        <div class="secondary" id="flashSecondary">
           [[defaultSettingLabel_(
               default_.plugins,
               '$i18n{siteSettingsFlashAllow}',
@@ -133,7 +146,9 @@
               '$i18n{siteSettingsFlashAskBefore}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsFlash}"
+          aria-describedby="flashSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.IMAGES]]"
@@ -141,14 +156,16 @@
       <iron-icon icon="settings:photo"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsImages}
-        <div class="secondary">
+        <div class="secondary" id="imagesSecondary">
           [[defaultSettingLabel_(
               default_.images,
               '$i18n{siteSettingsShowAll}',
               '$i18n{siteSettingsDontShowImages}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsImages}"
+          aria-describedby="imagesSecondary"></button>
     </div>
     <div category$="[[ContentSettingsTypes.POPUPS]]"
         class="settings-box two-line" data-route="SITE_SETTINGS_POPUPS"
@@ -156,14 +173,16 @@
       <iron-icon icon="cr:open-in-new"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsPopups}
-        <div class="secondary">
+        <div class="secondary" id="popupsSecondary">
           [[defaultSettingLabel_(
               default_.popups,
               '$i18n{siteSettingsAllowed}',
               '$i18n{siteSettingsBlocked}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsPopups}"
+          aria-describedby="popupsSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.BACKGROUND_SYNC]]"
@@ -172,14 +191,16 @@
       <iron-icon icon="settings:sync"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsBackgroundSync}
-        <div class="secondary">
+        <div class="secondary" id="backgroundSyncSecondary">
           [[defaultSettingLabel_(
               default_.backgroundSync,
               '$i18n{siteSettingsAllowRecentlyClosedSites}',
               '$i18n{siteSettingsBackgroundSyncBlocked}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsBackgroundSync}"
+          aria-describedby="backgroundSyncSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.AUTOMATIC_DOWNLOADS]]"
@@ -188,14 +209,16 @@
       <iron-icon icon="cr:file-download"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsAutomaticDownloads}
-        <div class="secondary">
+        <div class="secondary" id="automaticDownloadsSecondary">
           [[defaultSettingLabel_(
               default_.multipleAutomaticDownloads,
               '$i18n{siteSettingsAutoDownloadAsk}',
               '$i18n{siteSettingsAutoDownloadBlock}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsAutomaticDownloads}"
+          aria-describedby="automaticDownloadsSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.UNSANDBOXED_PLUGINS]]"
@@ -204,14 +227,16 @@
       <iron-icon icon="cr:extension"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsUnsandboxedPlugins}
-        <div class="secondary">
+        <div class="secondary" id="unsandboxedPluginsSecondary">
           [[defaultSettingLabel_(
               default_.ppapiBroker,
               '$i18n{siteSettingsUnsandboxedPluginsAsk}',
               '$i18n{siteSettingsUnsandboxedPluginsBlock}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsUnsandboxedPlugins}"
+          aria-describedby="unsandboxedPluginsSecondary"></button>
     </div>
     <div class="settings-box two-line"
         category$="[[ContentSettingsTypes.PROTOCOL_HANDLERS]]"
@@ -220,40 +245,46 @@
       <iron-icon icon="settings:protocol-handler"></iron-icon>
       <div class="middle">
         $i18n{siteSettingsHandlers}
-        <div class="secondary">
+        <div class="secondary" id="handlersSecondary">
           [[defaultSettingLabel_(
               default_.registerProtocolHandler,
               '$i18n{siteSettingsHandlersAsk}',
               '$i18n{siteSettingsHandlersBlocked}')]]
         </div>
       </div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsHandlers}"
+          aria-describedby="handlersSecondary"></button>
     </div>
     <div class="settings-box" category$="[[ContentSettingsTypes.ZOOM_LEVELS]]"
         data-route="SITE_SETTINGS_ZOOM_LEVELS"
         on-tap="onTapNavigate_" actionable>
       <iron-icon icon="settings:zoom-in"></iron-icon>
       <div class="middle">$i18n{siteSettingsZoomLevels}</div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsZoomLevels}"></button>
     </div>
     <div class="settings-box" category$="[[ContentSettingsTypes.USB_DEVICES]]"
         data-route="SITE_SETTINGS_USB_DEVICES"
         on-tap="onTapNavigate_" actionable>
       <iron-icon icon="settings:usb"></iron-icon>
       <div class="middle">$i18n{siteSettingsUsbDevices}</div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsUsbDevices}"></button>
     </div>
     <div class="settings-box" data-route="SITE_SETTINGS_PDF_DOCUMENTS"
         on-tap="onTapNavigate_" actionable>
       <iron-icon icon="settings:pdf"></iron-icon>
       <div class="middle">$i18n{siteSettingsPdfDocuments}</div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsPdfDocuments}"></button>
     </div>
     <div class="settings-box" data-route="SITE_SETTINGS_PROTECTED_CONTENT"
         on-tap="onTapNavigate_" actionable>
       <iron-icon icon="settings:security"></iron-icon>
       <div class="middle">$i18n{siteSettingsProtectedContent}</div>
-      <button class="subpage-arrow" is="paper-icon-button-light"></button>
+      <button class="subpage-arrow" is="paper-icon-button-light"
+          aria-label="$i18n{siteSettingsProtectedContent}"></button>
     </div>
   </template>
   <script src="site_settings_page.js"></script>
diff --git a/chrome/browser/resources/supervised_user_internals.css b/chrome/browser/resources/supervised_user_internals.css
index 97a8c20..97d3dba0 100644
--- a/chrome/browser/resources/supervised_user_internals.css
+++ b/chrome/browser/resources/supervised_user_internals.css
@@ -44,7 +44,7 @@
   background: rgb(239, 243, 255);
 }
 
-@-webkit-keyframes highlight1 {
+@keyframes highlight1 {
   0% {
     background: rgb(255, 255, 0);
   }
@@ -53,7 +53,7 @@
   }
 }
 
-@-webkit-keyframes highlight2 {
+@keyframes highlight2 {
   0% {
     background: rgb(155, 158, 166);
   }
@@ -63,15 +63,15 @@
 }
 
 .section-details [highlighted] {
-  -webkit-animation-duration: 3s;
-  -webkit-animation-name: highlight1;
-  -webkit-animation-timing-function: linear;
+  animation-duration: 3s;
+  animation-name: highlight1;
+  animation-timing-function: linear;
 }
 
 .section-details [highlighted]:nth-child(odd) {
-  -webkit-animation-duration: 3s;
-  -webkit-animation-name: highlight2;
-  -webkit-animation-timing-function: linear;
+  animation-duration: 3s;
+  animation-name: highlight2;
+  animation-timing-function: linear;
 }
 
 .section-details .uninitialized {
diff --git a/chrome/browser/resources/uber/uber.css b/chrome/browser/resources/uber/uber.css
index 76ba333d..dcbbb547 100644
--- a/chrome/browser/resources/uber/uber.css
+++ b/chrome/browser/resources/uber/uber.css
@@ -28,7 +28,7 @@
 }
 
 #navigation.changing-content {
-  -webkit-transition: -webkit-transform 100ms, width 100ms;
+  -webkit-transition: transform 100ms, width 100ms;
 }
 
 .iframe-container {
diff --git a/chrome/browser/resources/uber/uber.js b/chrome/browser/resources/uber/uber.js
index 2d44c7b..6879a49 100644
--- a/chrome/browser/resources/uber/uber.js
+++ b/chrome/browser/resources/uber/uber.js
@@ -426,7 +426,7 @@
       var navWidth = Math.max(0, +navFrame.dataset.width + scrollOffset);
       navFrame.style.width = navWidth + 'px';
     } else {
-      navFrame.style.webkitTransform = 'translateX(' + -scrollOffset + 'px)';
+      navFrame.style.transform = 'translateX(' + -scrollOffset + 'px)';
     }
   }
 
diff --git a/chrome/browser/resources/uber/uber_frame.css b/chrome/browser/resources/uber/uber_frame.css
index 36aa40d..aa237481 100644
--- a/chrome/browser/resources/uber/uber_frame.css
+++ b/chrome/browser/resources/uber/uber_frame.css
@@ -12,7 +12,7 @@
 }
 
 html.changing-content body {
-  -webkit-transition: -webkit-transform 100ms;
+  -webkit-transition: transform 100ms;
 }
 
 h1 {
diff --git a/chrome/browser/resources/uber/uber_frame.js b/chrome/browser/resources/uber/uber_frame.js
index c815d4c..8bcbca4 100644
--- a/chrome/browser/resources/uber/uber_frame.js
+++ b/chrome/browser/resources/uber/uber_frame.js
@@ -120,7 +120,7 @@
    */
   function adjustToScroll(scrollLeft) {
     assert(isRTL());
-    document.body.style.webkitTransform = 'translateX(' + -scrollLeft + 'px)';
+    document.body.style.transform = 'translateX(' + -scrollLeft + 'px)';
   }
 
   /**
diff --git a/chrome/browser/resources/uber/uber_utils.js b/chrome/browser/resources/uber/uber_utils.js
index 9964321..e1db645b 100644
--- a/chrome/browser/resources/uber/uber_utils.js
+++ b/chrome/browser/resources/uber/uber_utils.js
@@ -45,7 +45,7 @@
     for (var i = 0; i < headerElements.length; i++) {
       // As a workaround for http://crbug.com/231830, set the transform to
       // 'none' rather than 0px.
-      headerElements[i].style.webkitTransform = offset ?
+      headerElements[i].style.transform = offset ?
           'translateX(' + offset + 'px)' : 'none';
     }
 
diff --git a/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win_unittest.cc
index 70d09fee..0145a7dd 100644
--- a/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/environment_data_collection_win_unittest.cc
@@ -183,7 +183,7 @@
   // Ensure that all values and subkeys from the specified registry keys are
   // correctly stored in the report.
   registry_util::RegistryOverrideManager override_manager;
-  override_manager.OverrideRegistry(HKEY_CURRENT_USER);
+  ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(HKEY_CURRENT_USER));
 
   const wchar_t kRootKey[] = L"Software\\TestKey";
   const RegistryKeyInfo kRegKeysToCollect[] = {
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
index 8fd8e3b2..4a3980f 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service_unittest.cc
@@ -212,7 +212,8 @@
 #if defined(OS_WIN)
     // Redirect HKCU so that the platform state store used by the test doesn't
     // collide with existing Chrome installs or other tests running in parallel.
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
 #endif
     ASSERT_TRUE(profile_manager_.SetUp());
   }
diff --git a/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc
index 44d3606..5cc1c2d0 100644
--- a/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/platform_state_store_win_unittest.cc
@@ -42,7 +42,8 @@
   void SetUp() override {
     ::testing::Test::SetUp();
     base::MessageLoop::current()->SetTaskRunner(task_runner_);
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
     ASSERT_TRUE(profile_manager_.SetUp());
   }
 
diff --git a/chrome/browser/safe_browsing/incident_reporting/state_store_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/state_store_unittest.cc
index 72225835..f1db3466c 100644
--- a/chrome/browser/safe_browsing/incident_reporting/state_store_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/state_store_unittest.cc
@@ -46,7 +46,8 @@
 
   void SetUp() override {
     ::testing::Test::SetUp();
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
   }
 
  private:
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index c2256a62..029166f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -257,7 +257,7 @@
 class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
  public:
   SafeBrowsingService* CreateSafeBrowsingService() override {
-    return new SafeBrowsingService();
+    return new SafeBrowsingService(V4FeatureList::GetV4UsageStatus());
   }
 
  private:
@@ -292,12 +292,16 @@
   return factory_->CreateSafeBrowsingService();
 }
 
-SafeBrowsingService::SafeBrowsingService()
+SafeBrowsingService::SafeBrowsingService(
+    V4FeatureList::V4UsageStatus v4_usage_status)
     : services_delegate_(ServicesDelegate::Create(this)),
       estimated_extended_reporting_by_prefs_(SBER_LEVEL_OFF),
       enabled_(false),
       enabled_by_prefs_(false),
-      enabled_v4_only_(safe_browsing::V4FeatureList::IsV4OnlyEnabled()) {}
+      use_v4_only_(v4_usage_status == V4FeatureList::V4UsageStatus::V4_ONLY),
+      v4_enabled_(v4_usage_status ==
+                      V4FeatureList::V4UsageStatus::V4_INSTANTIATED ||
+                  v4_usage_status == V4FeatureList::V4UsageStatus::V4_ONLY) {}
 
 SafeBrowsingService::~SafeBrowsingService() {
   // We should have already been shut down. If we're still enabled, then the
@@ -315,7 +319,7 @@
 
   ui_manager_ = CreateUIManager();
 
-  if (!enabled_v4_only_) {
+  if (!use_v4_only_) {
     database_manager_ = CreateDatabaseManager();
   }
 
@@ -324,7 +328,7 @@
     navigation_observer_manager_ = new SafeBrowsingNavigationObserverManager();
   }
 
-  services_delegate_->Initialize();
+  services_delegate_->Initialize(v4_enabled_);
   services_delegate_->InitializeCsdService(url_request_context_getter_.get());
 
   // Track the safe browsing preference of existing profiles.
@@ -415,7 +419,7 @@
 
 const scoped_refptr<SafeBrowsingDatabaseManager>&
 SafeBrowsingService::database_manager() const {
-  return enabled_v4_only_ ? v4_local_database_manager() : database_manager_;
+  return use_v4_only_ ? v4_local_database_manager() : database_manager_;
 }
 
 scoped_refptr<SafeBrowsingNavigationObserverManager>
@@ -426,7 +430,7 @@
 SafeBrowsingProtocolManager* SafeBrowsingService::protocol_manager() const {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 #if defined(SAFE_BROWSING_DB_LOCAL)
-  DCHECK(!enabled_v4_only_);
+  DCHECK(!use_v4_only_);
   return protocol_manager_.get();
 #else
   return nullptr;
@@ -556,7 +560,7 @@
 SafeBrowsingProtocolManagerDelegate*
 SafeBrowsingService::GetProtocolManagerDelegate() {
 #if defined(SAFE_BROWSING_DB_LOCAL)
-  DCHECK(!enabled_v4_only_);
+  DCHECK(!use_v4_only_);
   return static_cast<LocalSafeBrowsingDatabaseManager*>(
       database_manager_.get());
 #else
@@ -578,14 +582,14 @@
   services_delegate_->StartOnIOThread(url_request_context_getter, v4_config);
 
 #if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
-  if (!enabled_v4_only_) {
+  if (!use_v4_only_) {
     DCHECK(database_manager_.get());
     database_manager_->StartOnIOThread(url_request_context_getter, v4_config);
   }
 #endif
 
 #if defined(SAFE_BROWSING_DB_LOCAL)
-  if (!enabled_v4_only_) {
+  if (!use_v4_only_) {
     SafeBrowsingProtocolManagerDelegate* protocol_manager_delegate =
         GetProtocolManagerDelegate();
     if (protocol_manager_delegate) {
@@ -605,7 +609,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
 #if defined(SAFE_BROWSING_DB_LOCAL) || defined(SAFE_BROWSING_DB_REMOTE)
-  if (!enabled_v4_only_) {
+  if (!use_v4_only_) {
     database_manager_->StopOnIOThread(shutdown);
   }
 #endif
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index d1d35549..e381f7a 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -22,6 +22,7 @@
 #include "chrome/browser/safe_browsing/services_delegate.h"
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
 #include "components/safe_browsing_db/util.h"
+#include "components/safe_browsing_db/v4_feature_list.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -197,7 +198,8 @@
 
  protected:
   // Creates the safe browsing service.  Need to initialize before using.
-  SafeBrowsingService();
+  SafeBrowsingService(V4FeatureList::V4UsageStatus v4_usage_status =
+                          V4FeatureList::V4UsageStatus::V4_DISABLED);
 
   ~SafeBrowsingService() override;
 
@@ -298,7 +300,12 @@
 
   // Whether SafeBrowsing needs to be enabled in V4Only mode. In this mode, all
   // SafeBrowsing decisions are made using the PVer4 implementation.
-  bool enabled_v4_only_;
+  bool use_v4_only_;
+
+  // Whether the PVer4 implementation needs to be instantiated. Note that even
+  // if the PVer4 implementation has been instantiated, it is used only if
+  // |use_v4_only_| is true.
+  bool v4_enabled_;
 
   // Tracks existing PrefServices, and the safe browsing preference on each.
   // This is used to determine if any profile is currently using the safe
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 40f5ef4..b36ae428 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -54,6 +54,9 @@
 #include "components/safe_browsing_db/metadata.pb.h"
 #include "components/safe_browsing_db/test_database_manager.h"
 #include "components/safe_browsing_db/util.h"
+#include "components/safe_browsing_db/v4_database.h"
+#include "components/safe_browsing_db/v4_feature_list.h"
+#include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
 #include "components/safe_browsing_db/v4_protocol_manager_util.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_driver.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
@@ -64,6 +67,7 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
+#include "crypto/sha2.h"
 #include "net/cookies/cookie_store.h"
 #include "net/cookies/cookie_util.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -94,7 +98,9 @@
 
 namespace {
 
+const char kBlacklistResource[] = "/blacklisted/script.js";
 const char kEmptyPage[] = "/empty.html";
+const char kMaliciousResource[] = "/malware/script.js";
 const char kMalwareFile[] = "/downloads/dangerous/dangerous.exe";
 const char kMalwarePage[] = "/safe_browsing/malware.html";
 const char kMalwareDelayedLoadsPage[] =
@@ -102,6 +108,7 @@
 const char kMalwareIFrame[] = "/safe_browsing/malware_iframe.html";
 const char kMalwareImg[] = "/safe_browsing/malware_image.png";
 const char kNeverCompletesPath[] = "/never_completes";
+const char kPrefetchMalwarePage[] = "/safe_browsing/prefetch_malware.html";
 
 class MockSubresourceFilterDriver
     : public subresource_filter::ContentSubresourceFilterDriver {
@@ -454,7 +461,7 @@
   TestProtocolManager* GetProtocolManager() { return pm_; }
 
  private:
-  // Owned by the SafebrowsingService.
+  // Owned by the SafeBrowsingService.
   TestProtocolManager* pm_;
 };
 
@@ -689,7 +696,7 @@
     ASSERT_TRUE(enabled_helper->Run());
   }
 
- private:
+ protected:
   std::unique_ptr<TestSafeBrowsingServiceFactory> sb_factory_;
   TestSafeBrowsingDatabaseFactory db_factory_;
   TestSBProtocolManagerFactory pm_factory_;
@@ -697,6 +704,7 @@
   // Owned by ContentSubresourceFilterFactory.
   MockSubresourceFilterDriver* driver_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceTest);
 };
 
@@ -744,8 +752,8 @@
   // Add the iframe url as malware and then load the parent page.
   SBFullHashResult malware_full_hash;
   GenUrlFullHashResultWithMetadata(iframe_url, &malware_full_hash);
-  EXPECT_CALL(observer_,
-              OnSafeBrowsingHit(IsUnsafeResourceFor(iframe_url))).Times(1);
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(iframe_url)))
+      .Times(1);
   SetupResponseForUrl(iframe_url, malware_full_hash);
   ui_test_utils::NavigateToURL(browser(), main_url);
   // All types should show the interstitial.
@@ -854,33 +862,12 @@
   EXPECT_FALSE(ShowingInterstitialPage());
 }
 
-const char kPrefetchMalwarePage[] = "/safe_browsing/prefetch_malware.html";
-
 // This test confirms that prefetches don't themselves get the
 // interstitial treatment.
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, Prefetch) {
   GURL url = embedded_test_server()->GetURL(kPrefetchMalwarePage);
   GURL malware_url = embedded_test_server()->GetURL(kMalwarePage);
 
-  class SetPrefetchForTest {
-   public:
-    explicit SetPrefetchForTest(bool prefetch)
-        : old_prerender_mode_(prerender::PrerenderManager::GetMode()) {
-      std::string exp_group = prefetch ? "ExperimentYes" : "ExperimentNo";
-      base::FieldTrialList::CreateFieldTrial("Prefetch", exp_group);
-
-      prerender::PrerenderManager::SetMode(
-          prerender::PrerenderManager::PRERENDER_MODE_DISABLED);
-    }
-
-    ~SetPrefetchForTest() {
-      prerender::PrerenderManager::SetMode(old_prerender_mode_);
-    }
-
-   private:
-    prerender::PrerenderManager::PrerenderManagerMode old_prerender_mode_;
-  } set_prefetch_for_test(true);
-
   // Even though we have added this uri to the safebrowsing database and
   // getfullhash result, we should not see the interstitial page since the
   // only malware was a prefetch target.
@@ -958,9 +945,7 @@
 
   EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(bad_url)))
       .Times(1);
-  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_, ::testing::_,
-                                                    ::testing::_))
-      .Times(0);
+  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(_, _, _)).Times(0);
   ui_test_utils::NavigateToURL(browser(), bad_url);
   Mock::VerifyAndClearExpectations(&observer_);
   ASSERT_TRUE(got_hit_report());
@@ -968,9 +953,7 @@
   content::WaitForInterstitialAttach(main_contents);
   EXPECT_TRUE(ShowingInterstitialPage());
   testing::Mock::VerifyAndClearExpectations(driver());
-  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_, ::testing::_,
-                                                    ::testing::_))
-      .Times(1);
+  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(_, _, _)).Times(1);
   InterstitialPage* interstitial_page = main_contents->GetInterstitialPage();
   ASSERT_TRUE(interstitial_page);
   interstitial_page->Proceed();
@@ -1000,9 +983,7 @@
 
   EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(bad_url)))
       .Times(1);
-  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_, ::testing::_,
-                                                    ::testing::_))
-      .Times(0);
+  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(_, _, _)).Times(0);
   ui_test_utils::NavigateToURL(browser(), bad_url);
   testing::Mock::VerifyAndClearExpectations(driver());
   ASSERT_TRUE(got_hit_report());
@@ -1010,9 +991,7 @@
   content::WaitForInterstitialAttach(main_contents);
   EXPECT_TRUE(ShowingInterstitialPage());
   testing::Mock::VerifyAndClearExpectations(driver());
-  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(::testing::_, ::testing::_,
-                                                    ::testing::_))
-      .Times(0);
+  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(_, _, _)).Times(0);
   InterstitialPage* interstitial_page = main_contents->GetInterstitialPage();
   ASSERT_TRUE(interstitial_page);
   interstitial_page->Proceed();
@@ -1462,10 +1441,8 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SafeBrowsingServiceTest, CheckResourceUrl) {
-  const char* kBlacklistResource = "/blacklisted/script.js";
   GURL blacklist_resource = embedded_test_server()->GetURL(kBlacklistResource);
   std::string blacklist_resource_hash;
-  const char* kMaliciousResource = "/malware/script.js";
   GURL malware_resource = embedded_test_server()->GetURL(kMaliciousResource);
   std::string malware_resource_hash;
 
@@ -1690,7 +1667,7 @@
         base::Bind(&SafeBrowsingDatabaseManagerCookieTest::HandleRequest));
     ASSERT_TRUE(embedded_test_server()->Start());
 
-    sb_factory_.reset(new TestSafeBrowsingServiceFactory());
+    sb_factory_ = base::MakeUnique<TestSafeBrowsingServiceFactory>();
     SetProtocolConfigURLPrefix(
         embedded_test_server()->GetURL("/testpath").spec(), sb_factory_.get());
     SafeBrowsingService::RegisterFactory(sb_factory_.get());
@@ -1834,4 +1811,856 @@
   observer.Wait();
 }
 
+class TestV4Store : public V4Store {
+ public:
+  TestV4Store(const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+              const base::FilePath& store_path)
+      : V4Store(task_runner, store_path, 0) {}
+
+  bool HasValidData() const override { return true; }
+
+  void MarkPrefixAsBad(HashPrefix prefix) {
+    hash_prefix_map_[prefix.size()] = prefix;
+  }
+};
+
+class TestV4StoreFactory : public V4StoreFactory {
+ public:
+  V4Store* CreateV4Store(
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+      const base::FilePath& store_path) override {
+    V4Store* new_store = new TestV4Store(task_runner, store_path);
+    new_store->Initialize();
+    return new_store;
+  }
+};
+
+class TestV4Database : public V4Database {
+ public:
+  TestV4Database(const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
+                 std::unique_ptr<StoreMap> store_map)
+      : V4Database(db_task_runner, std::move(store_map)) {}
+
+  void MarkPrefixAsBad(ListIdentifier list_id, HashPrefix prefix) {
+    V4Store* base_store = store_map_->at(list_id).get();
+    TestV4Store* test_store = static_cast<TestV4Store*>(base_store);
+    test_store->MarkPrefixAsBad(prefix);
+  }
+};
+
+class TestV4DatabaseFactory : public V4DatabaseFactory {
+ public:
+  TestV4DatabaseFactory() : v4_db_(nullptr) {}
+
+  std::unique_ptr<V4Database> Create(
+      const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
+      std::unique_ptr<StoreMap> store_map) override {
+    v4_db_ = new TestV4Database(db_task_runner, std::move(store_map));
+    return base::WrapUnique(v4_db_);
+  }
+
+  void MarkPrefixAsBad(ListIdentifier list_id, HashPrefix prefix) {
+    v4_db_->MarkPrefixAsBad(list_id, prefix);
+  }
+
+ private:
+  // Owned by V4LocalDatabaseManager. Each test in the V4SafeBrowsingServiceTest
+  // class instantiates a new SafebrowsingService instance, which instantiates a
+  // new V4LocalDatabaseManager, which instantiates a new V4Database using this
+  // method so use-after-free isn't possible.
+  TestV4Database* v4_db_;
+};
+
+class TestV4GetHashProtocolManager : public V4GetHashProtocolManager {
+ public:
+  TestV4GetHashProtocolManager(
+      net::URLRequestContextGetter* request_context_getter,
+      const StoresToCheck& stores_to_check,
+      const V4ProtocolConfig& config)
+      : V4GetHashProtocolManager(request_context_getter,
+                                 stores_to_check,
+                                 config) {}
+
+  void AddToFullHashCache(FullHashInfo fhi) {
+    full_hash_cache_[fhi.full_hash].full_hash_infos.push_back(fhi);
+  }
+};
+
+class TestV4GetHashProtocolManagerFactory
+    : public V4GetHashProtocolManagerFactory {
+ public:
+  std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager(
+      net::URLRequestContextGetter* request_context_getter,
+      const StoresToCheck& stores_to_check,
+      const V4ProtocolConfig& config) override {
+    pm_ = new TestV4GetHashProtocolManager(request_context_getter,
+                                           stores_to_check, config);
+    return base::WrapUnique(pm_);
+  }
+
+  void AddToFullHashCache(FullHashInfo fhi) { pm_->AddToFullHashCache(fhi); }
+
+ private:
+  // Owned by the SafeBrowsingService.
+  TestV4GetHashProtocolManager* pm_;
+};
+
+// Tests the safe browsing blocking page in a browser.
+class V4SafeBrowsingServiceTest : public SafeBrowsingServiceTest {
+ public:
+  V4SafeBrowsingServiceTest() : SafeBrowsingServiceTest() {}
+
+  void SetUp() override {
+    sb_factory_ = base::MakeUnique<TestSafeBrowsingServiceFactory>(
+        V4FeatureList::V4UsageStatus::V4_ONLY);
+    sb_factory_->SetTestUIManager(new FakeSafeBrowsingUIManager());
+    SafeBrowsingService::RegisterFactory(sb_factory_.get());
+
+    store_factory_ = new TestV4StoreFactory();
+    V4Database::RegisterStoreFactoryForTest(base::WrapUnique(store_factory_));
+
+    v4_db_factory_ = new TestV4DatabaseFactory();
+    V4Database::RegisterDatabaseFactoryForTest(
+        base::WrapUnique(v4_db_factory_));
+
+    v4_get_hash_factory_ = new TestV4GetHashProtocolManagerFactory();
+    V4GetHashProtocolManager::RegisterFactory(
+        base::WrapUnique(v4_get_hash_factory_));
+
+    InProcessBrowserTest::SetUp();
+  }
+
+  void TearDown() override {
+    InProcessBrowserTest::TearDown();
+
+    // Unregister test factories after InProcessBrowserTest::TearDown
+    // (which destructs SafeBrowsingService).
+    V4GetHashProtocolManager::RegisterFactory(nullptr);
+    V4Database::RegisterDatabaseFactoryForTest(nullptr);
+    V4Database::RegisterStoreFactoryForTest(nullptr);
+    SafeBrowsingService::RegisterFactory(nullptr);
+  }
+
+  // Returns a FullHash for the basic host+path pattern for a given URL after
+  // canonicalization.
+  FullHash GetFullHash(const GURL& url) {
+    std::string host;
+    std::string path;
+    V4ProtocolManagerUtil::CanonicalizeUrl(url, &host, &path, nullptr);
+
+    return crypto::SHA256HashString(host + path);
+  }
+
+  // Returns FullHashInfo object for the basic host+path pattern for a given URL
+  // after canonicalization.
+  FullHashInfo GetFullHashInfo(const GURL& url, const ListIdentifier& list_id) {
+    return FullHashInfo(GetFullHash(url), list_id,
+                        base::Time::Now() + base::TimeDelta::FromMinutes(5));
+  }
+
+  // Returns a FullHashInfo info for the basic host+path pattern for a given URL
+  // after canonicalization. Also adds metadata information to the FullHashInfo
+  // object.
+  FullHashInfo GetFullHashInfoWithMetadata(
+      const GURL& url,
+      const ListIdentifier& list_id,
+      ThreatPatternType threat_pattern_type) {
+    FullHashInfo fhi = GetFullHashInfo(url, list_id);
+    fhi.metadata.threat_pattern_type = threat_pattern_type;
+    return fhi;
+  }
+
+  // Sets up the prefix database and the full hash cache to match one of the
+  // prefixes for the given URL and metadata.
+  void MarkUrlForMalwareUnexpired(
+      const GURL& bad_url,
+      ThreatPatternType threat_pattern_type = ThreatPatternType::NONE) {
+    FullHashInfo full_hash_info = GetFullHashInfoWithMetadata(
+        bad_url, GetUrlMalwareId(), threat_pattern_type);
+
+    v4_db_factory_->MarkPrefixAsBad(GetUrlMalwareId(),
+                                    full_hash_info.full_hash);
+    v4_get_hash_factory_->AddToFullHashCache(full_hash_info);
+  }
+
+  // Sets up the prefix database and the full hash cache to match one of the
+  // prefixes for the given URL in the UwS store.
+  void MarkUrlForUwsUnexpired(const GURL& bad_url) {
+    FullHashInfo full_hash_info = GetFullHashInfo(bad_url, GetUrlUwsId());
+    v4_db_factory_->MarkPrefixAsBad(GetUrlUwsId(), full_hash_info.full_hash);
+    v4_get_hash_factory_->AddToFullHashCache(full_hash_info);
+  }
+
+  // Sets up the prefix database and the full hash cache to match one of the
+  // prefixes for the given URL in the phishing store.
+  void MarkUrlForPhishingUnexpired(const GURL& bad_url,
+                                   ThreatPatternType threat_pattern_type) {
+    FullHashInfo full_hash_info = GetFullHashInfoWithMetadata(
+        bad_url, GetUrlSocEngId(), threat_pattern_type);
+
+    v4_db_factory_->MarkPrefixAsBad(GetUrlSocEngId(), full_hash_info.full_hash);
+    v4_get_hash_factory_->AddToFullHashCache(full_hash_info);
+  }
+
+  // Sets up the prefix database and the full hash cache to match one of the
+  // prefixes for the given URL in the malware binary store.
+  void MarkUrlForMalwareBinaryUnexpired(const GURL& bad_url) {
+    FullHashInfo full_hash_info = GetFullHashInfo(bad_url, GetUrlMalBinId());
+    v4_db_factory_->MarkPrefixAsBad(GetUrlMalBinId(), full_hash_info.full_hash);
+    v4_get_hash_factory_->AddToFullHashCache(full_hash_info);
+  }
+
+  // Sets up the prefix database and the full hash cache to match one of the
+  // prefixes for the given URL in the client incident store.
+  void MarkUrlForResourceUnexpired(const GURL& bad_url) {
+    FullHashInfo full_hash_info =
+        GetFullHashInfo(bad_url, GetChromeUrlClientIncidentId());
+    v4_db_factory_->MarkPrefixAsBad(GetChromeUrlClientIncidentId(),
+                                    full_hash_info.full_hash);
+    v4_get_hash_factory_->AddToFullHashCache(full_hash_info);
+  }
+
+ private:
+  // Owned by the V4Database.
+  TestV4DatabaseFactory* v4_db_factory_;
+  // Owned by the V4GetHashProtocolManager.
+  TestV4GetHashProtocolManagerFactory* v4_get_hash_factory_;
+  // Owned by the V4Database.
+  TestV4StoreFactory* store_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(V4SafeBrowsingServiceTest);
+};
+
+// Ensures that if an image is marked as UwS, the main page doesn't show an
+// interstitial.
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, UnwantedImgIgnored) {
+  GURL main_url = embedded_test_server()->GetURL(kMalwarePage);
+  GURL img_url = embedded_test_server()->GetURL(kMalwareImg);
+
+  // Add the img url as coming from a site serving UwS and then load the parent
+  // page.
+  MarkUrlForUwsUnexpired(img_url);
+
+  ui_test_utils::NavigateToURL(browser(), main_url);
+
+  EXPECT_FALSE(ShowingInterstitialPage());
+  EXPECT_FALSE(got_hit_report());
+}
+
+// Proceeding through an interstitial should cause it to get whitelisted for
+// that user.
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, MalwareWithWhitelist) {
+  GURL url = embedded_test_server()->GetURL(kEmptyPage);
+
+  // After adding the URL to SafeBrowsing database and full hash cache, we
+  // should see the interstitial page.
+  MarkUrlForMalwareUnexpired(url);
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(url))).Times(1);
+
+  ui_test_utils::NavigateToURL(browser(), url);
+  Mock::VerifyAndClearExpectations(&observer_);
+  // There should be an InterstitialPage.
+  WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  InterstitialPage* interstitial_page = contents->GetInterstitialPage();
+  ASSERT_TRUE(interstitial_page);
+  // Proceed through it.
+  content::WindowedNotificationObserver load_stop_observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &contents->GetController()));
+  interstitial_page->Proceed();
+  load_stop_observer.Wait();
+  EXPECT_FALSE(ShowingInterstitialPage());
+
+  // Navigate to kEmptyPage again -- should hit the whitelist this time.
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(url))).Times(0);
+  ui_test_utils::NavigateToURL(browser(), url);
+  EXPECT_FALSE(ShowingInterstitialPage());
+}
+
+// This test confirms that prefetches don't themselves get the interstitial
+// treatment.
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, Prefetch) {
+  GURL url = embedded_test_server()->GetURL(kPrefetchMalwarePage);
+  GURL malware_url = embedded_test_server()->GetURL(kMalwarePage);
+
+  // Even though we have added this URI to the SafeBrowsing database and
+  // full hash result, we should not see the interstitial page since the
+  // only malware was a prefetch target.
+  MarkUrlForMalwareUnexpired(malware_url);
+
+  ui_test_utils::NavigateToURL(browser(), url);
+  EXPECT_FALSE(ShowingInterstitialPage());
+  EXPECT_FALSE(got_hit_report());
+  Mock::VerifyAndClear(&observer_);
+
+  // However, when we navigate to the malware page, we should still get
+  // the interstitial.
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(malware_url)))
+      .Times(1);
+  ui_test_utils::NavigateToURL(browser(), malware_url);
+  EXPECT_TRUE(ShowingInterstitialPage());
+  EXPECT_TRUE(got_hit_report());
+  Mock::VerifyAndClear(&observer_);
+}
+
+// Ensure that the referrer information is preserved in the hit report.
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, MainFrameHitWithReferrer) {
+  GURL first_url = embedded_test_server()->GetURL(kEmptyPage);
+  GURL bad_url = embedded_test_server()->GetURL(kMalwarePage);
+
+  MarkUrlForMalwareUnexpired(bad_url);
+
+  // Navigate to first, safe page.
+  ui_test_utils::NavigateToURL(browser(), first_url);
+  EXPECT_FALSE(ShowingInterstitialPage());
+  EXPECT_FALSE(got_hit_report());
+  Mock::VerifyAndClear(&observer_);
+
+  // Navigate to malware page, should show interstitial and have first page in
+  // referrer.
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(bad_url)))
+      .Times(1);
+
+  chrome::NavigateParams params(browser(), bad_url, ui::PAGE_TRANSITION_LINK);
+  params.referrer.url = first_url;
+  ui_test_utils::NavigateToURL(&params);
+
+  EXPECT_TRUE(ShowingInterstitialPage());
+  EXPECT_TRUE(got_hit_report());
+  EXPECT_EQ(bad_url, hit_report().malicious_url);
+  EXPECT_EQ(bad_url, hit_report().page_url);
+  EXPECT_EQ(first_url, hit_report().referrer_url);
+  EXPECT_FALSE(hit_report().is_subresource);
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest,
+                       SocEngReportingBlacklistNotEmpty) {
+  subresource_filter::testing::ScopedSubresourceFilterFeatureToggle
+      scoped_feature_toggle(
+          base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+          subresource_filter::kActivationLevelEnabled,
+          subresource_filter::kActivationScopeActivationList,
+          subresource_filter::kActivationListSocialEngineeringAdsInterstitial);
+  // Tests that when Safe Browsing gets hit which is corresponding to the
+  // SOCIAL_ENGINEERING_ADS threat type, then URL is added to the Subresource
+  // Filter.
+  GURL bad_url = embedded_test_server()->GetURL(kMalwarePage);
+  MarkUrlForPhishingUnexpired(bad_url,
+                              ThreatPatternType::SOCIAL_ENGINEERING_ADS);
+
+  WebContents* main_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(bad_url)))
+      .Times(1);
+  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(_, _, _)).Times(0);
+  ui_test_utils::NavigateToURL(browser(), bad_url);
+  Mock::VerifyAndClearExpectations(&observer_);
+  ASSERT_TRUE(got_hit_report());
+
+  content::WaitForInterstitialAttach(main_contents);
+  EXPECT_TRUE(ShowingInterstitialPage());
+  testing::Mock::VerifyAndClearExpectations(driver());
+  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(_, _, _)).Times(1);
+  InterstitialPage* interstitial_page = main_contents->GetInterstitialPage();
+  ASSERT_TRUE(interstitial_page);
+  interstitial_page->Proceed();
+  content::WaitForInterstitialDetach(main_contents);
+  EXPECT_FALSE(ShowingInterstitialPage());
+  testing::Mock::VerifyAndClearExpectations(driver());
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest,
+                       SocEngReportingBlacklistEmpty) {
+  // Tests that URLS which doesn't belong to the SOCIAL_ENGINEERING_ADS threat
+  // type aren't seen by the Subresource Filter.
+  subresource_filter::testing::ScopedSubresourceFilterFeatureToggle
+      scoped_feature_toggle(
+          base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+          subresource_filter::kActivationLevelEnabled,
+          subresource_filter::kActivationScopeNoSites,
+          subresource_filter::kActivationListSocialEngineeringAdsInterstitial);
+
+  GURL bad_url = embedded_test_server()->base_url().Resolve(kMalwarePage);
+  MarkUrlForMalwareUnexpired(bad_url);
+
+  WebContents* main_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(bad_url)))
+      .Times(1);
+  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(_, _, _)).Times(0);
+  ui_test_utils::NavigateToURL(browser(), bad_url);
+  testing::Mock::VerifyAndClearExpectations(driver());
+  ASSERT_TRUE(got_hit_report());
+
+  content::WaitForInterstitialAttach(main_contents);
+  EXPECT_TRUE(ShowingInterstitialPage());
+  testing::Mock::VerifyAndClearExpectations(driver());
+  EXPECT_CALL(*driver(), ActivateForProvisionalLoad(_, _, _)).Times(0);
+  InterstitialPage* interstitial_page = main_contents->GetInterstitialPage();
+  ASSERT_TRUE(interstitial_page);
+  interstitial_page->Proceed();
+  content::WaitForInterstitialDetach(main_contents);
+  EXPECT_FALSE(ShowingInterstitialPage());
+  testing::Mock::VerifyAndClearExpectations(driver());
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest,
+                       SubResourceHitWithMainFrameReferrer) {
+  GURL first_url = embedded_test_server()->GetURL(kEmptyPage);
+  GURL second_url = embedded_test_server()->GetURL(kMalwarePage);
+  GURL bad_url = embedded_test_server()->GetURL(kMalwareImg);
+
+  MarkUrlForMalwareUnexpired(bad_url);
+
+  // Navigate to first, safe page.
+  ui_test_utils::NavigateToURL(browser(), first_url);
+  EXPECT_FALSE(ShowingInterstitialPage());
+  EXPECT_FALSE(got_hit_report());
+  Mock::VerifyAndClear(&observer_);
+
+  // Navigate to page which has malware subresource, should show interstitial
+  // and have first page in referrer.
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(bad_url)))
+      .Times(1);
+
+  chrome::NavigateParams params(browser(), second_url,
+                                ui::PAGE_TRANSITION_LINK);
+  params.referrer.url = first_url;
+  ui_test_utils::NavigateToURL(&params);
+
+  EXPECT_TRUE(ShowingInterstitialPage());
+  EXPECT_TRUE(got_hit_report());
+  EXPECT_EQ(bad_url, hit_report().malicious_url);
+  EXPECT_EQ(second_url, hit_report().page_url);
+  EXPECT_EQ(first_url, hit_report().referrer_url);
+  EXPECT_TRUE(hit_report().is_subresource);
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest,
+                       SubResourceHitWithMainFrameRendererInitiatedSlowLoad) {
+  GURL first_url = embedded_test_server()->GetURL(kEmptyPage);
+  GURL second_url = embedded_test_server()->GetURL(kMalwareDelayedLoadsPage);
+  GURL third_url = embedded_test_server()->GetURL(kNeverCompletesPath);
+  GURL bad_url = embedded_test_server()->GetURL(kMalwareImg);
+
+  MarkUrlForMalwareUnexpired(bad_url);
+
+  // Navigate to first, safe page.
+  ui_test_utils::NavigateToURL(browser(), first_url);
+  EXPECT_FALSE(ShowingInterstitialPage());
+  EXPECT_FALSE(got_hit_report());
+  Mock::VerifyAndClear(&observer_);
+
+  // Navigate to malware page. The malware subresources haven't loaded yet, so
+  // no interstitial should show yet.
+  chrome::NavigateParams params(browser(), second_url,
+                                ui::PAGE_TRANSITION_LINK);
+  params.referrer.url = first_url;
+  ui_test_utils::NavigateToURL(&params);
+
+  EXPECT_FALSE(ShowingInterstitialPage());
+  EXPECT_FALSE(got_hit_report());
+  Mock::VerifyAndClear(&observer_);
+
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(bad_url)))
+      .Times(1);
+
+  WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  content::WindowedNotificationObserver load_stop_observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &contents->GetController()));
+  // Run javascript function in the page which starts a timer to load the
+  // malware image, and also starts a renderer-initiated top-level navigation to
+  // a site that does not respond.  Should show interstitial and have first page
+  // in referrer.
+  contents->GetMainFrame()->ExecuteJavaScriptForTests(
+      base::ASCIIToUTF16("navigateAndLoadMalwareImage()"));
+  load_stop_observer.Wait();
+
+  EXPECT_TRUE(ShowingInterstitialPage());
+  EXPECT_TRUE(got_hit_report());
+  // Report URLs should be for the current page, not the pending load.
+  EXPECT_EQ(bad_url, hit_report().malicious_url);
+  EXPECT_EQ(second_url, hit_report().page_url);
+  EXPECT_EQ(first_url, hit_report().referrer_url);
+  EXPECT_TRUE(hit_report().is_subresource);
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest,
+                       SubResourceHitWithMainFrameBrowserInitiatedSlowLoad) {
+  GURL first_url = embedded_test_server()->GetURL(kEmptyPage);
+  GURL second_url = embedded_test_server()->GetURL(kMalwareDelayedLoadsPage);
+  GURL third_url = embedded_test_server()->GetURL(kNeverCompletesPath);
+  GURL bad_url = embedded_test_server()->GetURL(kMalwareImg);
+
+  MarkUrlForMalwareUnexpired(bad_url);
+
+  // Navigate to first, safe page.
+  ui_test_utils::NavigateToURL(browser(), first_url);
+  EXPECT_FALSE(ShowingInterstitialPage());
+  EXPECT_FALSE(got_hit_report());
+  Mock::VerifyAndClear(&observer_);
+
+  // Navigate to malware page. The malware subresources haven't loaded yet, so
+  // no interstitial should show yet.
+  chrome::NavigateParams params(browser(), second_url,
+                                ui::PAGE_TRANSITION_LINK);
+  params.referrer.url = first_url;
+  ui_test_utils::NavigateToURL(&params);
+
+  EXPECT_FALSE(ShowingInterstitialPage());
+  EXPECT_FALSE(got_hit_report());
+  Mock::VerifyAndClear(&observer_);
+
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(bad_url)))
+      .Times(1);
+
+  WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
+  content::RenderFrameHost* rfh = contents->GetMainFrame();
+  content::WindowedNotificationObserver load_stop_observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::Source<content::NavigationController>(
+          &contents->GetController()));
+  // Start a browser initiated top-level navigation to a site that does not
+  // respond.
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), third_url, WindowOpenDisposition::CURRENT_TAB,
+      ui_test_utils::BROWSER_TEST_NONE);
+
+  // While the top-level navigation is pending, run javascript
+  // function in the page which loads the malware image.
+  rfh->ExecuteJavaScriptForTests(base::ASCIIToUTF16("loadMalwareImage()"));
+
+  // Wait for interstitial to show.
+  load_stop_observer.Wait();
+
+  EXPECT_TRUE(ShowingInterstitialPage());
+  EXPECT_TRUE(got_hit_report());
+  // Report URLs should be for the current page, not the pending load.
+  EXPECT_EQ(bad_url, hit_report().malicious_url);
+  EXPECT_EQ(second_url, hit_report().page_url);
+  EXPECT_EQ(first_url, hit_report().referrer_url);
+  EXPECT_TRUE(hit_report().is_subresource);
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, SubResourceHitOnFreshTab) {
+  // Allow popups.
+  HostContentSettingsMapFactory::GetForProfile(browser()->profile())
+      ->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_POPUPS,
+                                 CONTENT_SETTING_ALLOW);
+
+  // Add |kMalwareImg| to fake safebrowsing db.
+  GURL img_url = embedded_test_server()->GetURL(kMalwareImg);
+  MarkUrlForMalwareUnexpired(img_url);
+
+  // Have the current tab open a new tab with window.open().
+  WebContents* main_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  content::RenderFrameHost* main_rfh = main_contents->GetMainFrame();
+
+  content::WebContentsAddedObserver web_contents_added_observer;
+  main_rfh->ExecuteJavaScriptForTests(base::ASCIIToUTF16("w=window.open();"));
+  WebContents* new_tab_contents = web_contents_added_observer.GetWebContents();
+  content::RenderFrameHost* new_tab_rfh = new_tab_contents->GetMainFrame();
+  // A fresh WebContents should not have any NavigationEntries yet. (See
+  // https://crbug.com/524208.)
+  EXPECT_EQ(nullptr, new_tab_contents->GetController().GetLastCommittedEntry());
+  EXPECT_EQ(nullptr, new_tab_contents->GetController().GetPendingEntry());
+
+  // Run javascript in the blank new tab to load the malware image.
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(img_url)))
+      .Times(1);
+  new_tab_rfh->ExecuteJavaScriptForTests(
+      base::ASCIIToUTF16("var img=new Image();"
+                         "img.src=\"" +
+                         img_url.spec() + "\";"
+                                          "document.body.appendChild(img);"));
+
+  // Wait for interstitial to show.
+  content::WaitForInterstitialAttach(new_tab_contents);
+  Mock::VerifyAndClearExpectations(&observer_);
+  EXPECT_TRUE(ShowingInterstitialPage());
+  EXPECT_TRUE(got_hit_report());
+  EXPECT_EQ(img_url, hit_report().malicious_url);
+  EXPECT_TRUE(hit_report().is_subresource);
+  // Page report URLs should be empty, since there is no URL for this page.
+  EXPECT_EQ(GURL(), hit_report().page_url);
+  EXPECT_EQ(GURL(), hit_report().referrer_url);
+
+  // Proceed through it.
+  InterstitialPage* interstitial_page = new_tab_contents->GetInterstitialPage();
+  ASSERT_TRUE(interstitial_page);
+  interstitial_page->Proceed();
+
+  content::WaitForInterstitialDetach(new_tab_contents);
+  EXPECT_FALSE(ShowingInterstitialPage());
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// START: These tests use SafeBrowsingService::Client to directly interact with
+// SafeBrowsingService.
+///////////////////////////////////////////////////////////////////////////////
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckDownloadUrl) {
+  GURL badbin_url = embedded_test_server()->GetURL(kMalwareFile);
+  std::vector<GURL> badbin_urls(1, badbin_url);
+
+  scoped_refptr<TestSBClient> client(new TestSBClient);
+  client->CheckDownloadUrl(badbin_urls);
+
+  // Since badbin_url is not in database, it is considered to be safe.
+  EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType());
+
+  MarkUrlForMalwareBinaryUnexpired(badbin_url);
+
+  client->CheckDownloadUrl(badbin_urls);
+
+  // Now, the badbin_url is not safe since it is added to download database.
+  EXPECT_EQ(SB_THREAT_TYPE_BINARY_MALWARE_URL, client->GetThreatType());
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckUnwantedSoftwareUrl) {
+  const GURL bad_url = embedded_test_server()->GetURL(kMalwareFile);
+  {
+    scoped_refptr<TestSBClient> client(new TestSBClient);
+
+    // Since bad_url is not in database, it is considered to be
+    // safe.
+    client->CheckBrowseUrl(bad_url);
+    EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType());
+
+    MarkUrlForUwsUnexpired(bad_url);
+
+    // Now, the bad_url is not safe since it is added to download
+    // database.
+    client->CheckBrowseUrl(bad_url);
+    EXPECT_EQ(SB_THREAT_TYPE_URL_UNWANTED, client->GetThreatType());
+  }
+
+  // The unwantedness should survive across multiple clients.
+  {
+    scoped_refptr<TestSBClient> client(new TestSBClient);
+    client->CheckBrowseUrl(bad_url);
+    EXPECT_EQ(SB_THREAT_TYPE_URL_UNWANTED, client->GetThreatType());
+  }
+
+  // An unwanted URL also marked as malware should be flagged as malware.
+  {
+    scoped_refptr<TestSBClient> client(new TestSBClient);
+
+    MarkUrlForMalwareUnexpired(bad_url);
+
+    client->CheckBrowseUrl(bad_url);
+    EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, client->GetThreatType());
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckBrowseUrl) {
+  const GURL bad_url = embedded_test_server()->GetURL(kMalwareFile);
+  {
+    scoped_refptr<TestSBClient> client(new TestSBClient);
+
+    // Since bad_url is not in database, it is considered to be
+    // safe.
+    client->CheckBrowseUrl(bad_url);
+    EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType());
+
+    MarkUrlForMalwareUnexpired(bad_url);
+
+    // Now, the bad_url is not safe since it is added to download
+    // database.
+    client->CheckBrowseUrl(bad_url);
+    EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, client->GetThreatType());
+  }
+
+  // The unwantedness should survive across multiple clients.
+  {
+    scoped_refptr<TestSBClient> client(new TestSBClient);
+    client->CheckBrowseUrl(bad_url);
+    EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, client->GetThreatType());
+  }
+
+  // Adding the unwanted state to an existing malware URL should have no impact
+  // (i.e. a malware hit should still prevail).
+  {
+    scoped_refptr<TestSBClient> client(new TestSBClient);
+
+    MarkUrlForUwsUnexpired(bad_url);
+
+    client->CheckBrowseUrl(bad_url);
+    EXPECT_EQ(SB_THREAT_TYPE_URL_MALWARE, client->GetThreatType());
+  }
+}
+
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckDownloadUrlRedirects) {
+  GURL original_url = embedded_test_server()->GetURL(kEmptyPage);
+  GURL badbin_url = embedded_test_server()->GetURL(kMalwareFile);
+  GURL final_url = embedded_test_server()->GetURL(kEmptyPage);
+  std::vector<GURL> badbin_urls;
+  badbin_urls.push_back(original_url);
+  badbin_urls.push_back(badbin_url);
+  badbin_urls.push_back(final_url);
+
+  scoped_refptr<TestSBClient> client(new TestSBClient);
+  client->CheckDownloadUrl(badbin_urls);
+
+  // Since badbin_url is not in database, it is considered to be safe.
+  EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType());
+
+  MarkUrlForMalwareBinaryUnexpired(badbin_url);
+
+  client->CheckDownloadUrl(badbin_urls);
+
+  // Now, the badbin_url is not safe since it is added to download database.
+  EXPECT_EQ(SB_THREAT_TYPE_BINARY_MALWARE_URL, client->GetThreatType());
+}
+
+#if defined(GOOGLE_CHROME_BUILD)
+// This test is only enabled when GOOGLE_CHROME_BUILD is true because the store
+// that this test uses is only populated on GOOGLE_CHROME_BUILD builds.
+IN_PROC_BROWSER_TEST_F(V4SafeBrowsingServiceTest, CheckResourceUrl) {
+  GURL blacklist_url = embedded_test_server()->GetURL(kBlacklistResource);
+  GURL malware_url = embedded_test_server()->GetURL(kMaliciousResource);
+  std::string blacklist_url_hash, malware_url_hash;
+
+  scoped_refptr<TestSBClient> client(new TestSBClient);
+  {
+    MarkUrlForResourceUnexpired(blacklist_url);
+    blacklist_url_hash = GetFullHash(blacklist_url);
+
+    client->CheckResourceUrl(blacklist_url);
+    EXPECT_EQ(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, client->GetThreatType());
+    EXPECT_EQ(blacklist_url_hash, client->GetThreatHash());
+  }
+  {
+    MarkUrlForMalwareUnexpired(malware_url);
+    MarkUrlForResourceUnexpired(malware_url);
+    malware_url_hash = GetFullHash(malware_url);
+
+    // Since we're checking a resource url, we should receive result that it's
+    // a blacklisted resource, not a malware.
+    client = new TestSBClient;
+    client->CheckResourceUrl(malware_url);
+    EXPECT_EQ(SB_THREAT_TYPE_BLACKLISTED_RESOURCE, client->GetThreatType());
+    EXPECT_EQ(malware_url_hash, client->GetThreatHash());
+  }
+
+  client->CheckResourceUrl(embedded_test_server()->GetURL(kEmptyPage));
+  EXPECT_EQ(SB_THREAT_TYPE_SAFE, client->GetThreatType());
+}
+#endif
+///////////////////////////////////////////////////////////////////////////////
+// END: These tests use SafeBrowsingService::Client to directly interact with
+// SafeBrowsingService.
+///////////////////////////////////////////////////////////////////////////////
+
+// TODO(vakh): Add test for UnwantedMainFrame.
+
+class V4SafeBrowsingServiceMetadataTest
+    : public V4SafeBrowsingServiceTest,
+      public ::testing::WithParamInterface<ThreatPatternType> {
+ public:
+  V4SafeBrowsingServiceMetadataTest() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(V4SafeBrowsingServiceMetadataTest);
+};
+
+// Irrespective of the threat_type classification, if the main frame URL is
+// marked as Malware, an interstitial should be shown.
+IN_PROC_BROWSER_TEST_P(V4SafeBrowsingServiceMetadataTest, MalwareMainFrame) {
+  GURL url = embedded_test_server()->GetURL(kEmptyPage);
+  MarkUrlForMalwareUnexpired(url, GetParam());
+
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(url))).Times(1);
+
+  ui_test_utils::NavigateToURL(browser(), url);
+  // All types should show the interstitial.
+  EXPECT_TRUE(ShowingInterstitialPage());
+
+  EXPECT_TRUE(got_hit_report());
+  EXPECT_EQ(url, hit_report().malicious_url);
+  EXPECT_EQ(url, hit_report().page_url);
+  EXPECT_EQ(GURL(), hit_report().referrer_url);
+  EXPECT_FALSE(hit_report().is_subresource);
+}
+
+// Irrespective of the threat_type classification, if the iframe URL is marked
+// as Malware, an interstitial should be shown.
+IN_PROC_BROWSER_TEST_P(V4SafeBrowsingServiceMetadataTest, MalwareIFrame) {
+  GURL main_url = embedded_test_server()->GetURL(kMalwarePage);
+  GURL iframe_url = embedded_test_server()->GetURL(kMalwareIFrame);
+
+  // Add the iframe url as malware and then load the parent page.
+  MarkUrlForMalwareUnexpired(iframe_url, GetParam());
+
+  EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(iframe_url)))
+      .Times(1);
+
+  ui_test_utils::NavigateToURL(browser(), main_url);
+  // All types should show the interstitial.
+  EXPECT_TRUE(ShowingInterstitialPage());
+
+  EXPECT_TRUE(got_hit_report());
+  EXPECT_EQ(iframe_url, hit_report().malicious_url);
+  EXPECT_EQ(main_url, hit_report().page_url);
+  EXPECT_EQ(GURL(), hit_report().referrer_url);
+  EXPECT_TRUE(hit_report().is_subresource);
+}
+
+// Depending on the threat_type classification, if an embedded resource is
+// marked as Malware, an interstitial may be shown.
+IN_PROC_BROWSER_TEST_P(V4SafeBrowsingServiceMetadataTest, MalwareImg) {
+  GURL main_url = embedded_test_server()->GetURL(kMalwarePage);
+  GURL img_url = embedded_test_server()->GetURL(kMalwareImg);
+
+  // Add the img url as malware and then load the parent page.
+  MarkUrlForMalwareUnexpired(img_url, GetParam());
+
+  switch (GetParam()) {
+    case ThreatPatternType::NONE:  // Falls through.
+    case ThreatPatternType::MALWARE_DISTRIBUTION:
+      EXPECT_CALL(observer_, OnSafeBrowsingHit(IsUnsafeResourceFor(img_url)))
+          .Times(1);
+      break;
+    case ThreatPatternType::MALWARE_LANDING:
+      // No interstitial shown, so no notifications expected.
+      break;
+    default:
+      break;
+  }
+
+  ui_test_utils::NavigateToURL(browser(), main_url);
+
+  // Subresource which is tagged as a landing page should not show an
+  // interstitial, the other types should.
+  switch (GetParam()) {
+    case ThreatPatternType::NONE:  // Falls through.
+    case ThreatPatternType::MALWARE_DISTRIBUTION:
+      EXPECT_TRUE(ShowingInterstitialPage());
+      EXPECT_TRUE(got_hit_report());
+      EXPECT_EQ(img_url, hit_report().malicious_url);
+      EXPECT_EQ(main_url, hit_report().page_url);
+      EXPECT_EQ(GURL(), hit_report().referrer_url);
+      EXPECT_TRUE(hit_report().is_subresource);
+      break;
+    case ThreatPatternType::MALWARE_LANDING:
+      EXPECT_FALSE(ShowingInterstitialPage());
+      EXPECT_FALSE(got_hit_report());
+      break;
+    default:
+      break;
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(
+    MaybeSetMetadata,
+    V4SafeBrowsingServiceMetadataTest,
+    testing::Values(ThreatPatternType::NONE,
+                    ThreatPatternType::MALWARE_LANDING,
+                    ThreatPatternType::MALWARE_DISTRIBUTION));
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/services_delegate.h b/chrome/browser/safe_browsing/services_delegate.h
index 50ee41a7..882828a 100644
--- a/chrome/browser/safe_browsing/services_delegate.h
+++ b/chrome/browser/safe_browsing/services_delegate.h
@@ -72,7 +72,7 @@
   v4_local_database_manager() const = 0;
 
   // Initializes internal state using the ServicesCreator.
-  virtual void Initialize() = 0;
+  virtual void Initialize(bool v4_enabled = false) = 0;
 
   // Creates the CSD service for the given |context_getter|.
   virtual void InitializeCsdService(
diff --git a/chrome/browser/safe_browsing/services_delegate_impl.cc b/chrome/browser/safe_browsing/services_delegate_impl.cc
index d18b40e..49e6d12 100644
--- a/chrome/browser/safe_browsing/services_delegate_impl.cc
+++ b/chrome/browser/safe_browsing/services_delegate_impl.cc
@@ -64,13 +64,15 @@
   return v4_local_database_manager_;
 }
 
-void ServicesDelegateImpl::Initialize() {
+void ServicesDelegateImpl::Initialize(bool v4_enabled) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  v4_local_database_manager_ = V4LocalDatabaseManager::Create(
-      SafeBrowsingService::GetBaseFilename(),
-      base::Bind(&ServicesDelegateImpl::GetEstimatedExtendedReportingLevel,
-                 base::Unretained(this)));
+  if (v4_enabled) {
+    v4_local_database_manager_ = V4LocalDatabaseManager::Create(
+        SafeBrowsingService::GetBaseFilename(),
+        base::Bind(&ServicesDelegateImpl::GetEstimatedExtendedReportingLevel,
+                   base::Unretained(this)));
+  }
 
   download_service_.reset(
       (services_creator_ &&
diff --git a/chrome/browser/safe_browsing/services_delegate_impl.h b/chrome/browser/safe_browsing/services_delegate_impl.h
index acd95d79..f0a2f6a5 100644
--- a/chrome/browser/safe_browsing/services_delegate_impl.h
+++ b/chrome/browser/safe_browsing/services_delegate_impl.h
@@ -30,7 +30,7 @@
   // ServicesDelegate:
   const scoped_refptr<SafeBrowsingDatabaseManager>& v4_local_database_manager()
       const override;
-  void Initialize() override;
+  void Initialize(bool v4_enabled) override;
   void InitializeCsdService(
       net::URLRequestContextGetter* context_getter) override;
   void ShutdownServices() override;
diff --git a/chrome/browser/safe_browsing/services_delegate_stub.cc b/chrome/browser/safe_browsing/services_delegate_stub.cc
index c1aa24f..52360e9 100644
--- a/chrome/browser/safe_browsing/services_delegate_stub.cc
+++ b/chrome/browser/safe_browsing/services_delegate_stub.cc
@@ -36,7 +36,7 @@
   return v4_local_database_manager_;
 }
 
-void ServicesDelegateStub::Initialize() {}
+void ServicesDelegateStub::Initialize(bool v4_enabled) {}
 
 void ServicesDelegateStub::ShutdownServices() {}
 
diff --git a/chrome/browser/safe_browsing/services_delegate_stub.h b/chrome/browser/safe_browsing/services_delegate_stub.h
index 31a6945..0a22bcb 100644
--- a/chrome/browser/safe_browsing/services_delegate_stub.h
+++ b/chrome/browser/safe_browsing/services_delegate_stub.h
@@ -20,7 +20,7 @@
   // ServicesDelegate:
   const scoped_refptr<SafeBrowsingDatabaseManager>& v4_local_database_manager()
       const override;
-  void Initialize() override;
+  void Initialize(bool v4_enabled = false) override;
   void InitializeCsdService(
       net::URLRequestContextGetter* context_getter) override;
   void ShutdownServices() override;
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
index 4941fe5..5f992dde 100644
--- a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.cc
@@ -8,13 +8,13 @@
 
 #include "base/json/json_reader.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "components/url_formatter/url_fixer.h"
-#include "components/variations/variations_associated_data.h"
 #include "crypto/sha2.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "url/gurl.h"
@@ -24,7 +24,6 @@
 namespace {
 
 constexpr char kSettingsResetPromptFeatureName[] = "SettingsResetPrompt";
-constexpr char kDomainHashesParamName[] = "domain_hashes";
 
 }  // namespace.
 
@@ -102,6 +101,14 @@
   return -1;
 }
 
+base::TimeDelta SettingsResetPromptConfig::delay_before_prompt() const {
+  return delay_before_prompt_;
+}
+
+bool SettingsResetPromptConfig::use_modal_dialog() const {
+  return use_modal_dialog_;
+}
+
 // Implements the hash function for SHA256Hash objects. Simply uses the
 // first bytes of the SHA256 hash as its own hash.
 size_t SettingsResetPromptConfig::SHA256HashHasher::operator()(
@@ -123,6 +130,8 @@
   CONFIG_ERROR_BAD_DOMAIN_HASH = 4,
   CONFIG_ERROR_BAD_DOMAIN_ID = 5,
   CONFIG_ERROR_DUPLICATE_DOMAIN_HASH = 6,
+  CONFIG_ERROR_BAD_DELAY_BEFORE_PROMPT_SECONDS_PARAM = 7,
+  CONFIG_ERROR_BAD_USE_MODAL_DIALOG_PARAM = 8,
   CONFIG_ERROR_MAX
 };
 
@@ -130,12 +139,48 @@
   if (!IsPromptEnabled())
     return false;
 
-  std::string domain_hashes_json = variations::GetVariationParamValueByFeature(
-      kSettingsResetPrompt, kDomainHashesParamName);
+  // Parse the domain_hashes feature parameter.
+  std::string domain_hashes_json = base::GetFieldTrialParamValueByFeature(
+      kSettingsResetPrompt, "domain_hashes");
   ConfigError error = ParseDomainHashes(domain_hashes_json);
-  UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.ConfigError", error,
+  if (error != CONFIG_ERROR_OK) {
+    UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.ConfigError", error,
+                              CONFIG_ERROR_MAX);
+    return false;
+  }
+
+  // Get the delay_before_prompt feature parameter.
+  int delay_before_prompt_seconds = base::GetFieldTrialParamByFeatureAsInt(
+      kSettingsResetPrompt, "delay_before_prompt_seconds", -1);
+  if (delay_before_prompt_seconds < 0) {
+    UMA_HISTOGRAM_ENUMERATION(
+        "SettingsResetPrompt.ConfigError",
+        CONFIG_ERROR_BAD_DELAY_BEFORE_PROMPT_SECONDS_PARAM, CONFIG_ERROR_MAX);
+    return false;
+  }
+  delay_before_prompt_ =
+      base::TimeDelta::FromSeconds(delay_before_prompt_seconds);
+
+  // Get the use_modal_dialog feature parameter. Since
+  // |GetFieldTrialParamByFeatureAsBool| always returns true or false and
+  // ignores any errors that are encountered, the parsing from string to bool is
+  // done explicitly here.
+  std::string use_modal_dialog_string = base::GetFieldTrialParamValueByFeature(
+      kSettingsResetPrompt, "use_modal_dialog");
+  if (use_modal_dialog_string == "true") {
+    use_modal_dialog_ = true;
+  } else if (use_modal_dialog_string == "false") {
+    use_modal_dialog_ = false;
+  } else {
+    UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.ConfigError",
+                              CONFIG_ERROR_BAD_USE_MODAL_DIALOG_PARAM,
+                              CONFIG_ERROR_MAX);
+    return false;
+  }
+
+  UMA_HISTOGRAM_ENUMERATION("SettingsResetPrompt.ConfigError", CONFIG_ERROR_OK,
                             CONFIG_ERROR_MAX);
-  return error == CONFIG_ERROR_OK;
+  return true;
 }
 
 SettingsResetPromptConfig::ConfigError
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h
index 799fefd..a2676ec5 100644
--- a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config.h
@@ -13,6 +13,7 @@
 
 #include "base/feature_list.h"
 #include "base/macros.h"
+#include "base/time/time.h"
 
 class GURL;
 
@@ -40,6 +41,11 @@
   // for and can be used for metrics reporting.
   virtual int UrlToResetDomainId(const GURL& url) const;
 
+  // The delay before showing the reset prompt after Chrome startup.
+  base::TimeDelta delay_before_prompt() const;
+  // Whether the prompt dialog should be modal.
+  bool use_modal_dialog() const;
+
   // TODO(alito): parameterize the set of things that we want to reset
   // for so that we can control it from the finch config. For example,
   // with functions like HomepageResetAllowed() etc.
@@ -59,6 +65,10 @@
   // Map of 32 byte SHA256 hashes to integer domain IDs.
   std::unordered_map<SHA256Hash, int, SHA256HashHasher> domain_hashes_;
 
+  // Other feature parameters.
+  base::TimeDelta delay_before_prompt_;
+  bool use_modal_dialog_;
+
   DISALLOW_COPY_AND_ASSIGN(SettingsResetPromptConfig);
 };
 
diff --git a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config_unittest.cc b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config_unittest.cc
index e9ed56c..4b27e8c 100644
--- a/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config_unittest.cc
+++ b/chrome/browser/safe_browsing/settings_reset_prompt/settings_reset_prompt_config_unittest.cc
@@ -9,6 +9,7 @@
 
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/time/time.h"
 #include "components/variations/variations_params_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -37,10 +38,11 @@
                                                               params, features);
   }
 
-  void SetDefaultFeatureParams() {
-    Parameters default_params = {
-        {"domain_hashes", base::StringPrintf("{\"%s\": \"1\"}", kDomainHash)}};
-    SetFeatureParams(default_params);
+  Parameters GetDefaultFeatureParams() {
+    return {
+        {"domain_hashes", base::StringPrintf("{\"%s\": \"1\"}", kDomainHash)},
+        {"delay_before_prompt_seconds", "42"},
+        {"use_modal_dialog", "true"}};
   }
 
   variations::testing::VariationParamsManager params_manager_;
@@ -50,77 +52,97 @@
 TEST_F(SettingsResetPromptConfigTest, IsPromptEnabled) {
   EXPECT_FALSE(SettingsResetPromptConfig::IsPromptEnabled());
 
-  SetDefaultFeatureParams();
+  SetFeatureParams(GetDefaultFeatureParams());
   EXPECT_TRUE(SettingsResetPromptConfig::IsPromptEnabled());
 }
 
 TEST_F(SettingsResetPromptConfigTest, Create) {
-  // Should return nullptr when feature is not enabled.
+  ASSERT_FALSE(SettingsResetPromptConfig::IsPromptEnabled());
+
+  // |Create()| should return nullptr when feature is not enabled.
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
+  // |Create()| should return false when feature is enabled, but parameters are
+  // |missing.
   scoped_feature_list_.InitAndEnableFeature(kSettingsResetPrompt);
-
-  // Check cases where |Create()| should return nullptr because of bad
-  // domain_hashes parameter.
-
-  // Parameter is missing.
+  ASSERT_TRUE(SettingsResetPromptConfig::IsPromptEnabled());
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
   SetFeatureParams(Parameters());
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
+  // |Create()| should return a config when parameters are all present.
+  // Individual parameters are tested separately.
+  SetFeatureParams(GetDefaultFeatureParams());
+  EXPECT_TRUE(SettingsResetPromptConfig::Create());
+}
+
+TEST_F(SettingsResetPromptConfigTest, DomainHashesParam) {
+  Parameters params = GetDefaultFeatureParams();
+
+  // First, test bad values for the "domain_hashes" parameter.
+
+  // Parameter is missing.
+  ASSERT_EQ(params.erase("domain_hashes"), 1U);
+  SetFeatureParams(params);
+  EXPECT_FALSE(SettingsResetPromptConfig::Create());
+
   // Parameter is an empty string.
-  SetFeatureParams(Parameters({{"domain_hashes", ""}}));
+  params["domain_hashes"] = "";
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Invalid JSON.
-  SetFeatureParams(Parameters({{"domain_hashes", "bad json"}}));
+  params["domain_hashes"] = "bad json";
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Parameter is not a JSON dictionary.
-  SetFeatureParams(Parameters({{"domain_hashes", "[3]"}}));
+  params["domain_hashes"] = "[3]";
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Bad dictionary key.
-  SetFeatureParams(Parameters({{"domain_hashes", "\"bad key\": \"1\""}}));
+  params["domain_hashes"] = "\"bad key\": \"1\"";
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Dictionary key is too short.
-  SetFeatureParams(Parameters({{"domain_hashes", "\"1234abc\": \"1\""}}));
+  params["domain_hashes"] = "\"1234abc\": \"1\"";
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Dictionary key has correct length, but is not a hex string.
   std::string non_hex_key(64, 'x');
-  SetFeatureParams(
-      Parameters({{"domain_hashes", base::StringPrintf("{\"%s\": \"1\"}",
-                                                       non_hex_key.c_str())}}));
+  params["domain_hashes"] =
+      base::StringPrintf("{\"%s\": \"1\"}", non_hex_key.c_str());
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Correct key but non-integer value.
-  SetFeatureParams(Parameters(
-      {{"domain_hashes",
-        base::StringPrintf("{\"%s\": \"not integer\"}", kDomainHash)}}));
+  params["domain_hashes"] =
+      base::StringPrintf("{\"%s\": \"not integer\"}", kDomainHash);
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Correct key but integer value that is too big.
   std::string too_big_int(99, '1');
-  SetFeatureParams(Parameters(
-      {{"domain_hashes", base::StringPrintf("{\"%s\": \"%s\"}", kDomainHash,
-                                            too_big_int.c_str())}}));
+  params["domain_hashes"] =
+      base::StringPrintf("{\"%s\": \"%s\"}", kDomainHash, too_big_int.c_str());
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Correct key but negative integer value.
-  SetFeatureParams(
-      Parameters({{"domain_hashes",
-                   base::StringPrintf("{\"%s\": \"-2\"}", kDomainHash)}}));
+  params["domain_hashes"] = base::StringPrintf("{\"%s\": \"-2\"}", kDomainHash);
+  SetFeatureParams(params);
   EXPECT_FALSE(SettingsResetPromptConfig::Create());
 
   // Should return non-nullptr with a correct set of parameters.
-  SetDefaultFeatureParams();
+  SetFeatureParams(GetDefaultFeatureParams());
   EXPECT_TRUE(SettingsResetPromptConfig::Create());
 }
 
 TEST_F(SettingsResetPromptConfigTest, UrlToResetDomainId) {
-  SetDefaultFeatureParams();
+  SetFeatureParams(GetDefaultFeatureParams());
   auto config = SettingsResetPromptConfig::Create();
   ASSERT_TRUE(config);
 
@@ -164,12 +186,12 @@
   const char kTLDHash5[] =
       "bffd48c8162466106a84f42945bfbbcfe501c9f0931219e02ce46e275f05ba51";
 
-  SetFeatureParams(Parameters(
-      {{"domain_hashes",
-        base::StringPrintf(
-            "{\"%s\": \"1\", \"%s\": \"2\", \"%s\": \"3\", \"%s\": \"4\", "
-            "\"%s\": \"5\"}",
-            kTLDHash1, kTLDHash2, kTLDHash3, kTLDHash4, kTLDHash5)}}));
+  Parameters params = GetDefaultFeatureParams();
+  params["domain_hashes"] = base::StringPrintf(
+      "{\"%s\": \"1\", \"%s\": \"2\", \"%s\": \"3\", \"%s\": \"4\", "
+      "\"%s\": \"5\"}",
+      kTLDHash1, kTLDHash2, kTLDHash3, kTLDHash4, kTLDHash5);
+  SetFeatureParams(params);
   auto config = SettingsResetPromptConfig::Create();
   ASSERT_TRUE(config);
 
@@ -186,4 +208,86 @@
   EXPECT_LT(config->UrlToResetDomainId(GURL("http://appspot.com")), 0);
 }
 
+TEST_F(SettingsResetPromptConfigTest, DelayBeforePromptSecondsParam) {
+  constexpr char kDelayParam[] = "delay_before_prompt_seconds";
+
+  Parameters params = GetDefaultFeatureParams();
+
+  // Missing parameter.
+  ASSERT_EQ(params.erase(kDelayParam), 1U);
+  SetFeatureParams(params);
+  EXPECT_FALSE(SettingsResetPromptConfig::Create());
+
+  // Empty parameter.
+  params[kDelayParam] = "";
+  SetFeatureParams(params);
+  EXPECT_FALSE(SettingsResetPromptConfig::Create());
+
+  // Bad parameter value.
+  params[kDelayParam] = "not-a-number";
+  SetFeatureParams(params);
+  EXPECT_FALSE(SettingsResetPromptConfig::Create());
+
+  // Negative parameter value.
+  params[kDelayParam] = "-3";
+  SetFeatureParams(params);
+  EXPECT_FALSE(SettingsResetPromptConfig::Create());
+
+  // Correct parameter value.
+  params[kDelayParam] = "12";
+  SetFeatureParams(params);
+  {
+    auto config = SettingsResetPromptConfig::Create();
+    ASSERT_TRUE(config);
+    EXPECT_EQ(config->delay_before_prompt(), base::TimeDelta::FromSeconds(12));
+  }
+
+  // Correct edge case parameter value.
+  params["delay_before_prompt_seconds"] = "0";
+  SetFeatureParams(params);
+  {
+    auto config = SettingsResetPromptConfig::Create();
+    ASSERT_TRUE(config);
+    EXPECT_EQ(config->delay_before_prompt(), base::TimeDelta::FromSeconds(0));
+  }
+}
+
+TEST_F(SettingsResetPromptConfigTest, UseModalDialogParam) {
+  constexpr char kModalParam[] = "use_modal_dialog";
+
+  Parameters params = GetDefaultFeatureParams();
+
+  // Missing parameter.
+  ASSERT_EQ(params.erase(kModalParam), 1U);
+  SetFeatureParams(params);
+  EXPECT_FALSE(SettingsResetPromptConfig::Create());
+
+  // Empty parameter.
+  params[kModalParam] = "";
+  SetFeatureParams(params);
+  EXPECT_FALSE(SettingsResetPromptConfig::Create());
+
+  // Bad parameter value.
+  params[kModalParam] = "not-a-boolean-value";
+  SetFeatureParams(params);
+  EXPECT_FALSE(SettingsResetPromptConfig::Create());
+
+  // Correct parameter value.
+  params[kModalParam] = "true";
+  SetFeatureParams(params);
+  {
+    auto config = SettingsResetPromptConfig::Create();
+    ASSERT_TRUE(config);
+    EXPECT_TRUE(config->use_modal_dialog());
+  }
+
+  params[kModalParam] = "false";
+  SetFeatureParams(params);
+  {
+    auto config = SettingsResetPromptConfig::Create();
+    ASSERT_TRUE(config);
+    EXPECT_FALSE(config->use_modal_dialog());
+  }
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_service.cc b/chrome/browser/safe_browsing/test_safe_browsing_service.cc
index b836b18..731a5ca 100644
--- a/chrome/browser/safe_browsing/test_safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/test_safe_browsing_service.cc
@@ -10,12 +10,15 @@
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "components/safe_browsing_db/database_manager.h"
 #include "components/safe_browsing_db/test_database_manager.h"
+#include "components/safe_browsing_db/v4_feature_list.h"
 
 namespace safe_browsing {
 
 // TestSafeBrowsingService functions:
-TestSafeBrowsingService::TestSafeBrowsingService()
-    : protocol_manager_delegate_disabled_(false),
+TestSafeBrowsingService::TestSafeBrowsingService(
+    V4FeatureList::V4UsageStatus v4_usage_status)
+    : SafeBrowsingService(v4_usage_status),
+      protocol_manager_delegate_disabled_(false),
       serialized_download_report_(base::EmptyString()) {}
 
 TestSafeBrowsingService::~TestSafeBrowsingService() {}
@@ -90,15 +93,18 @@
 }
 
 // TestSafeBrowsingServiceFactory functions:
-TestSafeBrowsingServiceFactory::TestSafeBrowsingServiceFactory()
-    : test_safe_browsing_service_(nullptr), test_protocol_config_(nullptr) {}
+TestSafeBrowsingServiceFactory::TestSafeBrowsingServiceFactory(
+    V4FeatureList::V4UsageStatus v4_usage_status)
+    : test_safe_browsing_service_(nullptr),
+      test_protocol_config_(nullptr),
+      v4_usage_status_(v4_usage_status) {}
 
 TestSafeBrowsingServiceFactory::~TestSafeBrowsingServiceFactory() {}
 
 SafeBrowsingService*
 TestSafeBrowsingServiceFactory::CreateSafeBrowsingService() {
   // Instantiate TestSafeBrowsingService.
-  test_safe_browsing_service_ = new TestSafeBrowsingService();
+  test_safe_browsing_service_ = new TestSafeBrowsingService(v4_usage_status_);
   // Plug-in test member clases accordingly.
   if (test_ui_manager_)
     test_safe_browsing_service_->SetUIManager(test_ui_manager_.get());
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_service.h b/chrome/browser/safe_browsing/test_safe_browsing_service.h
index facf791..533c748 100644
--- a/chrome/browser/safe_browsing/test_safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/test_safe_browsing_service.h
@@ -40,7 +40,8 @@
 //   test_sb_factory_.
 class TestSafeBrowsingService : public SafeBrowsingService {
  public:
-  TestSafeBrowsingService();
+  explicit TestSafeBrowsingService(
+      V4FeatureList::V4UsageStatus v4_usage_status);
   // SafeBrowsingService overrides
   SafeBrowsingProtocolConfig GetProtocolConfig() const override;
   V4ProtocolConfig GetV4ProtocolConfig() const override;
@@ -80,7 +81,9 @@
 
 class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory {
  public:
-  TestSafeBrowsingServiceFactory();
+  explicit TestSafeBrowsingServiceFactory(
+      V4FeatureList::V4UsageStatus v4_usage_status =
+          V4FeatureList::V4UsageStatus::V4_DISABLED);
   ~TestSafeBrowsingServiceFactory() override;
 
   // Creates test safe browsing service, and configures test UI manager,
@@ -101,6 +104,7 @@
   scoped_refptr<TestSafeBrowsingDatabaseManager> test_database_manager_;
   scoped_refptr<TestSafeBrowsingUIManager> test_ui_manager_;
   SafeBrowsingProtocolConfig* test_protocol_config_;
+  V4FeatureList::V4UsageStatus v4_usage_status_;
 
   DISALLOW_COPY_AND_ASSIGN(TestSafeBrowsingServiceFactory);
 };
diff --git a/chrome/browser/search_engines/OWNERS b/chrome/browser/search_engines/OWNERS
index 5513d7cb..b09c45cd 100644
--- a/chrome/browser/search_engines/OWNERS
+++ b/chrome/browser/search_engines/OWNERS
@@ -4,3 +4,5 @@
 per-file *_android.*=mariakhomenko@chromium.org
 
 per-file default_search_policy_handler*=atwilson@chromium.org
+
+# COMPONENT: UI>Browser>Search
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
index 334b702f..9724eae2 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -17,12 +17,14 @@
 #include "base/test/histogram_tester.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/metrics/subprocess_metrics_provider.h"
+#include "chrome/browser/page_load_metrics/observers/subresource_filter_metrics_observer.h"
 #include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
 #include "chrome/browser/subresource_filter/test_ruleset_publisher.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/safe_browsing_db/test_database_manager.h"
@@ -563,6 +565,25 @@
       static_cast<base::Histogram::Sample>(ActivationLevel::ENABLED), 2);
 }
 
+IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, PageLoadMetrics) {
+  GURL url(GetTestUrl("subresource_filter/frame_with_included_script.html"));
+  ConfigureAsPhishingURL(url);
+
+  ASSERT_NO_FATAL_FAILURE(
+      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+
+  base::HistogramTester histogram_tester;
+  ui_test_utils::NavigateToURL(browser(), url);
+  EXPECT_FALSE(WasParsedScriptElementLoaded(web_contents()->GetMainFrame()));
+
+  // Force a navigation to another page, which flushes page load metrics for the
+  // previous page load.
+  ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
+
+  histogram_tester.ExpectTotalCount(internal::kHistogramSubresourceFilterCount,
+                                    1);
+}
+
 IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
                        PRE_MainFrameActivationOnStartup) {
   SetRulesetToDisallowURLsWithPathSuffix("included_script.js");
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index ea1c1724..18a503d0 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -104,8 +104,8 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/chromeos/printing/printers_sync_bridge.h"
 #include "chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.h"
 #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service.h"
@@ -453,7 +453,7 @@
           ->AsWeakPtr();
 #if defined(OS_CHROMEOS)
     case syncer::PRINTERS:
-      return chromeos::PrinterPrefManagerFactory::GetForBrowserContext(profile_)
+      return chromeos::PrintersManagerFactory::GetForBrowserContext(profile_)
           ->GetSyncBridge()
           ->AsWeakPtr();
 #endif
diff --git a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
index f4c49e4..886c2a4 100644
--- a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
+++ b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
@@ -48,17 +48,6 @@
 
 namespace {
 
-const char kFoo1[] = "http://foo1/";
-const char kFoo2[] = "http://foo2/";
-const char kBar1[] = "http://bar1/";
-const char kBar2[] = "http://bar2/";
-const char kBaz1[] = "http://baz1/";
-const char kBaz2[] = "http://baz2/";
-
-std::string TabNodeIdToTag(const std::string& machine_tag, int tab_node_id) {
-  return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id);
-}
-
 class SessionNotificationObserver {
  public:
   SessionNotificationObserver()
@@ -139,7 +128,7 @@
   std::map<int, SyncedTabDelegate*> tab_overrides_;
   std::map<int, SessionID::id_type> tab_id_overrides_;
   const SyncedWindowDelegate* const wrapped_;
-  SessionID::id_type session_id_override_ = TabNodePool::kInvalidTabID;
+  SessionID::id_type session_id_override_ = -1;
 };
 
 class TestSyncedWindowDelegatesGetter : public SyncedWindowDelegatesGetter {
@@ -410,10 +399,6 @@
     return sessions_client_shim_.get();
   }
 
-  TabNodePool* GetTabPool() {
-    return &manager()->session_tracker_.local_tab_pool_;
-  }
-
   syncer::SyncPrefs* sync_prefs() { return sync_prefs_.get(); }
 
   SyncedWindowDelegatesGetter* get_synced_window_getter() {
@@ -517,32 +502,40 @@
 
 namespace {
 
-// A SyncedTabDelegate fake for testing. It simulates a normal
-// SyncedTabDelegate with a proper WebContents. For a SyncedTabDelegate without
-// a WebContents, see PlaceholderTabDelegate below.
 class SyncedTabDelegateFake : public SyncedTabDelegate {
  public:
-  SyncedTabDelegateFake() {}
+  SyncedTabDelegateFake()
+      : current_entry_index_(0), is_supervised_(false), sync_id_(-1) {}
   ~SyncedTabDelegateFake() override {}
 
-  // SyncedTabDelegate overrides.
   bool IsInitialBlankNavigation() const override {
     // This differs from NavigationControllerImpl, which has an initial blank
     // NavigationEntry.
     return GetEntryCount() == 0;
   }
   int GetCurrentEntryIndex() const override { return current_entry_index_; }
+  void set_current_entry_index(int i) {
+    current_entry_index_ = i;
+  }
+
+  void AppendEntry(std::unique_ptr<content::NavigationEntry> entry) {
+    entries_.push_back(std::move(entry));
+  }
+
   GURL GetVirtualURLAtIndex(int i) const override {
     if (static_cast<size_t>(i) >= entries_.size())
       return GURL();
     return entries_[i]->GetVirtualURL();
   }
+
   GURL GetFaviconURLAtIndex(int i) const override { return GURL(); }
+
   ui::PageTransition GetTransitionAtIndex(int i) const override {
     if (static_cast<size_t>(i) >= entries_.size())
       return ui::PAGE_TRANSITION_LINK;
     return entries_[i]->GetTransitionType();
   }
+
   void GetSerializedNavigationAtIndex(
       int i,
       sessions::SerializedNavigationEntry* serialized_entry) const override {
@@ -552,9 +545,17 @@
         sessions::ContentSerializedNavigationBuilder::FromNavigationEntry(
             i, *entries_[i]);
   }
+
   int GetEntryCount() const override { return entries_.size(); }
-  SessionID::id_type GetWindowId() const override { return window_id_; }
-  SessionID::id_type GetSessionId() const override { return tab_id_; }
+
+  SessionID::id_type GetWindowId() const override {
+    return SessionID::id_type();
+  }
+
+  SessionID::id_type GetSessionId() const override {
+    return SessionID::id_type();
+  }
+
   bool IsBeingDestroyed() const override { return false; }
   std::string GetExtensionAppId() const override { return std::string(); }
   bool ProfileIsSupervised() const override { return is_supervised_; }
@@ -563,23 +564,6 @@
   GetBlockedNavigations() const override {
     return &blocked_navigations_;
   }
-  bool IsPlaceholderTab() const override { return false; }
-  int GetSyncId() const override { return sync_id_; }
-  void SetSyncId(int sync_id) override { sync_id_ = sync_id; }
-  bool ShouldSync(SyncSessionsClient* sessions_client) override {
-    return false;
-  }
-
-  void AppendEntry(std::unique_ptr<content::NavigationEntry> entry) {
-    entries_.push_back(std::move(entry));
-  }
-
-  void set_current_entry_index(int i) { current_entry_index_ = i; }
-
-  void SetWindowId(SessionID::id_type window_id) { window_id_ = window_id; }
-
-  void SetSessionId(SessionID::id_type id) { tab_id_ = id; }
-
   void set_blocked_navigations(
       std::vector<const content::NavigationEntry*>* navs) {
     for (auto* entry : *navs) {
@@ -590,101 +574,31 @@
       blocked_navigations_.push_back(std::move(serialized_entry));
     }
   }
+  bool IsPlaceholderTab() const override { return true; }
+
+  // Session sync related methods.
+  int GetSyncId() const override { return sync_id_; }
+  void SetSyncId(int sync_id) override { sync_id_ = sync_id; }
+
+  bool ShouldSync(SyncSessionsClient* sessions_client) override {
+    return false;
+  }
 
   void reset() {
     current_entry_index_ = 0;
-    sync_id_ = TabNodePool::kInvalidTabNodeID;
+    sync_id_ = -1;
     entries_.clear();
   }
 
  private:
-  int current_entry_index_ = 0;
-  bool is_supervised_ = false;
-  int sync_id_ = -1;
-  SessionID::id_type tab_id_ = 0;
-  SessionID::id_type window_id_ = 0;
+  int current_entry_index_;
+  bool is_supervised_;
+  int sync_id_;
   std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>
       blocked_navigations_;
   std::vector<std::unique_ptr<content::NavigationEntry>> entries_;
 };
 
-// A placeholder delegate. These delegates have no WebContents, simulating a tab
-// that has been restored without bringing its state fully into memory (for
-// example on Android), or where the tab's contents have been evicted from
-// memory. See SyncedTabDelegate::IsPlaceHolderTab for more info.
-class PlaceholderTabDelegate : public SyncedTabDelegate {
- public:
-  PlaceholderTabDelegate(SessionID::id_type session_id, int sync_id)
-      : session_id_(session_id), sync_id_(sync_id) {}
-  ~PlaceholderTabDelegate() override {}
-
-  // SyncedTabDelegate overrides.
-  SessionID::id_type GetSessionId() const override { return session_id_; }
-  int GetSyncId() const override { return sync_id_; }
-  void SetSyncId(int sync_id) override { sync_id_ = sync_id; }
-  bool IsPlaceholderTab() const override { return true; }
-
-  // Everything else is invalid to invoke as it depends on a valid WebContents.
-  SessionID::id_type GetWindowId() const override {
-    NOTREACHED();
-    return 0;
-  }
-  bool IsBeingDestroyed() const override {
-    NOTREACHED();
-    return false;
-  }
-  std::string GetExtensionAppId() const override {
-    NOTREACHED();
-    return "";
-  }
-  bool IsInitialBlankNavigation() const override {
-    NOTREACHED();
-    return false;
-  }
-  int GetCurrentEntryIndex() const override {
-    NOTREACHED();
-    return 0;
-  }
-  int GetEntryCount() const override {
-    NOTREACHED();
-    return 0;
-  }
-  GURL GetVirtualURLAtIndex(int i) const override {
-    NOTREACHED();
-    return GURL();
-  }
-  GURL GetFaviconURLAtIndex(int i) const override {
-    NOTREACHED();
-    return GURL();
-  }
-  ui::PageTransition GetTransitionAtIndex(int i) const override {
-    NOTREACHED();
-    return ui::PageTransition();
-  }
-  void GetSerializedNavigationAtIndex(
-      int i,
-      sessions::SerializedNavigationEntry* serialized_entry) const override {
-    NOTREACHED();
-  }
-  bool ProfileIsSupervised() const override {
-    NOTREACHED();
-    return false;
-  }
-  const std::vector<std::unique_ptr<const sessions::SerializedNavigationEntry>>*
-  GetBlockedNavigations() const override {
-    NOTREACHED();
-    return nullptr;
-  }
-  bool ShouldSync(SyncSessionsClient* sessions_client) override {
-    NOTREACHED();
-    return false;
-  }
-
- private:
-  SessionID::id_type session_id_;
-  int sync_id_;
-};
-
 }  // namespace
 
 static const base::Time kTime0 = base::Time::FromInternalValue(100);
@@ -1039,31 +953,29 @@
 
 // Ensure model association associates the pre-existing tabs.
 TEST_F(SessionsSyncManagerTest, SwappedOutOnRestore) {
+  AddTab(browser(), GURL("http://foo1"));
+  NavigateAndCommitActiveTab(GURL("http://foo2"));
+  AddTab(browser(), GURL("http://bar1"));
+  NavigateAndCommitActiveTab(GURL("http://bar2"));
+  AddTab(browser(), GURL("http://baz1"));
+  NavigateAndCommitActiveTab(GURL("http://baz2"));
   const int kRestoredTabId = 1337;
   const int kNewTabId = 2468;
 
-  // AddTab inserts at index 0, so go in reverse order (tab 3 -> tab 1).
-  AddTab(browser(), GURL(kBaz1));
-  NavigateAndCommitActiveTab(GURL(kBaz2));
-  AddTab(browser(), GURL(kBar1));
-  NavigateAndCommitActiveTab(GURL(kBar2));
-  AddTab(browser(), GURL(kFoo1));
-  NavigateAndCommitActiveTab(GURL(kFoo2));
-
   syncer::SyncDataList in;
   syncer::SyncChangeList out;
   InitWithSyncDataTakeOutput(in, &out);
 
-  // Should be one header add, 3 tab adds, one header update.
-  ASSERT_EQ(5U, out.size());
+  // Should be one header add, 3 tab add/update pairs, one header update.
+  ASSERT_EQ(8U, out.size());
 
   // For input, we set up:
   // * one "normal" fully loaded tab
-  // * one placeholder tab with no WebContents and a tab_id change
-  // * one placeholder tab with no WebContents and no tab_id change
-  sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics();
-  sync_pb::EntitySpecifics t1_entity = out[2].sync_data().GetSpecifics();
-  sync_pb::EntitySpecifics t2_entity = out[3].sync_data().GetSpecifics();
+  // * one "frozen" tab with no WebContents and a tab_id change
+  // * one "frozen" tab with no WebContents and no tab_id change
+  sync_pb::EntitySpecifics t0_entity = out[2].sync_data().GetSpecifics();
+  sync_pb::EntitySpecifics t1_entity = out[4].sync_data().GetSpecifics();
+  sync_pb::EntitySpecifics t2_entity = out[6].sync_data().GetSpecifics();
   t1_entity.mutable_session()->mutable_tab()->set_tab_id(kRestoredTabId);
   in.push_back(CreateRemoteData(t0_entity));
   in.push_back(CreateRemoteData(t1_entity));
@@ -1074,8 +986,9 @@
   const std::set<const SyncedWindowDelegate*>& windows =
       manager()->synced_window_delegates_getter()->GetSyncedWindowDelegates();
   ASSERT_EQ(1U, windows.size());
-  PlaceholderTabDelegate t1_override(kNewTabId, 1);
-  PlaceholderTabDelegate t2_override(t2_entity.session().tab().tab_id(), 2);
+  SyncedTabDelegateFake t1_override, t2_override;
+  t1_override.SetSyncId(1);  // No WebContents by default.
+  t2_override.SetSyncId(2);  // No WebContents by default.
   SyncedWindowDelegateOverride window_override(*windows.begin());
   window_override.OverrideTabAt(1, &t1_override, kNewTabId);
   window_override.OverrideTabAt(2, &t2_override,
@@ -1092,39 +1005,26 @@
       std::unique_ptr<syncer::SyncErrorFactory>(
           new syncer::SyncErrorFactoryMock()));
 
-  // There should be three changes, one for the fully associated tab, and
-  // one each for the tab_id updates to t1 and t2.
-  ASSERT_EQ(3U, FilterOutLocalHeaderChanges(&out)->size());
+  // There should be two changes, one for the fully associated tab, and
+  // one for the tab_id update to t1.  t2 shouldn't need to be updated.
+  ASSERT_EQ(2U, FilterOutLocalHeaderChanges(&out)->size());
   EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type());
-  EXPECT_EQ(kFoo2, out[0]
-                       .sync_data()
-                       .GetSpecifics()
-                       .session()
-                       .tab()
-                       .navigation(1)
-                       .virtual_url());
-
   EXPECT_EQ(SyncChange::ACTION_UPDATE, out[1].change_type());
   EXPECT_EQ(kNewTabId,
             out[1].sync_data().GetSpecifics().session().tab().tab_id());
-  EXPECT_EQ(kBar2, out[1]
-                       .sync_data()
-                       .GetSpecifics()
-                       .session()
-                       .tab()
-                       .navigation(1)
-                       .virtual_url());
 
-  EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type());
-  EXPECT_EQ(t2_entity.session().tab().tab_id(),
-            out[2].sync_data().GetSpecifics().session().tab().tab_id());
-  EXPECT_EQ(kBaz2, out[2]
-                       .sync_data()
-                       .GetSpecifics()
-                       .session()
-                       .tab()
-                       .navigation(1)
-                       .virtual_url());
+  // Verify TabLinks.
+  SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_;
+  ASSERT_EQ(3U, tab_map.size());
+  int t2_tab_id = t2_entity.session().tab().tab_id();
+  EXPECT_EQ(2, tab_map.find(t2_tab_id)->second->tab_node_id());
+  EXPECT_EQ(1, tab_map.find(kNewTabId)->second->tab_node_id());
+  int t0_tab_id = out[0].sync_data().GetSpecifics().session().tab().tab_id();
+  EXPECT_EQ(0, tab_map.find(t0_tab_id)->second->tab_node_id());
+  // TODO(tim): Once bug 337057 is fixed, we can issue an OnLocalTabModified
+  // from here (using an override similar to above) to return a new tab id
+  // and verify that we don't see any node creations in the SyncChangeProcessor
+  // (similar to how SessionsSyncManagerTest.OnLocalTabModified works.)
 }
 
 // Ensure model association updates the window ID for tabs whose window's ID has
@@ -1135,22 +1035,21 @@
   syncer::SyncChangeList out;
 
   // Set up one tab and start sync with it.
-  AddTab(browser(), GURL(kFoo1));
-  NavigateAndCommitActiveTab(GURL(kFoo2));
+  AddTab(browser(), GURL("http://foo1"));
+  NavigateAndCommitActiveTab(GURL("http://foo2"));
   InitWithSyncDataTakeOutput(in, &out);
 
-  // Should be one header add, 1 tab add, and one header update.
-  ASSERT_EQ(3U, out.size());
-  const sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics();
-  ASSERT_TRUE(t0_entity.session().has_tab());
+  // Should be one header add, 1 tab add/update pair, and one header update.
+  ASSERT_EQ(4U, out.size());
+  const sync_pb::EntitySpecifics t0_entity = out[2].sync_data().GetSpecifics();
 
   in.push_back(CreateRemoteData(t0_entity));
   out.clear();
   manager()->StopSyncing(syncer::SESSIONS);
 
-  // Override the tab with a placeholder tab delegate.
-  PlaceholderTabDelegate t0_override(t0_entity.session().tab().tab_id(),
-                                     t0_entity.session().tab_node_id());
+  // SyncedTabDelegateFake is a placeholder (no WebContents) by default.
+  SyncedTabDelegateFake t0_override;
+  t0_override.SetSyncId(t0_entity.session().tab_node_id());
 
   // Set up the window override with the new window ID and placeholder tab.
   const std::set<const SyncedWindowDelegate*>& windows =
@@ -1179,64 +1078,6 @@
   EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type());
   EXPECT_EQ(kNewWindowId,
             out[0].sync_data().GetSpecifics().session().tab().window_id());
-  EXPECT_EQ(kFoo2, out[0]
-                       .sync_data()
-                       .GetSpecifics()
-                       .session()
-                       .tab()
-                       .navigation(1)
-                       .virtual_url());
-}
-
-// Ensure that the manager properly ignores a restored placeholder that refers
-// to a tab node that doesn't exist
-TEST_F(SessionsSyncManagerTest, RestoredPlacholderTabNodeDeleted) {
-  const int kNewWindowId = 1337;
-  syncer::SyncDataList in;
-  syncer::SyncChangeList out;
-
-  // Set up one tab and start sync with it.
-  AddTab(browser(), GURL(kFoo1));
-  NavigateAndCommitActiveTab(GURL(kFoo2));
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // Should be one header add, 1 tab add, and one header update.
-  ASSERT_EQ(3U, out.size());
-  const sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics();
-  ASSERT_TRUE(t0_entity.session().has_tab());
-
-  out.clear();
-  manager()->StopSyncing(syncer::SESSIONS);
-
-  // Override the tab with a placeholder tab delegate.
-  PlaceholderTabDelegate t0_override(t0_entity.session().tab().tab_id(),
-                                     t0_entity.session().tab_node_id());
-
-  // Set up the window override with the new window ID and placeholder tab.
-  const std::set<const SyncedWindowDelegate*>& windows =
-      get_synced_window_getter()->GetSyncedWindowDelegates();
-  ASSERT_EQ(1U, windows.size());
-  SyncedWindowDelegateOverride window_override(*windows.begin());
-  window_override.OverrideSessionId(kNewWindowId);
-  window_override.OverrideTabAt(0, &t0_override,
-                                t0_entity.session().tab().tab_id());
-
-  // Inject the window override.
-  std::set<const SyncedWindowDelegate*> delegates;
-  delegates.insert(&window_override);
-  std::unique_ptr<TestSyncedWindowDelegatesGetter> getter(
-      new TestSyncedWindowDelegatesGetter(delegates));
-  set_synced_window_getter(getter.get());
-
-  syncer::SyncMergeResult result = manager()->MergeDataAndStartSyncing(
-      syncer::SESSIONS, in, std::unique_ptr<syncer::SyncChangeProcessor>(
-                                new TestSyncProcessorStub(&out)),
-      std::unique_ptr<syncer::SyncErrorFactory>(
-          new syncer::SyncErrorFactoryMock()));
-
-  // Because no entities were passed in at associate time, there should be no
-  // tab changes.
-  ASSERT_EQ(0U, FilterOutLocalHeaderChanges(&out)->size());
 }
 
 // Tests MergeDataAndStartSyncing with sync data but no local data.
@@ -1299,8 +1140,7 @@
 
   syncer::SyncChangeList output;
   InitWithSyncDataTakeOutput(foreign_data, &output);
-  // Should be one header add, 1 tab add, and one header update.
-  ASSERT_EQ(3U, output.size());
+  ASSERT_EQ(4U, output.size());
 
   // Verify the local header.
   EXPECT_TRUE(output[0].IsValid());
@@ -1328,12 +1168,12 @@
   }
   EXPECT_EQ(SyncChange::ACTION_ADD, output[1].change_type());
   EXPECT_EQ(SyncChange::ACTION_UPDATE, output[2].change_type());
-  EXPECT_TRUE(output[1].sync_data().GetSpecifics().session().has_tab());
+  EXPECT_TRUE(output[2].sync_data().GetSpecifics().session().has_tab());
 
   // Verify the header was updated to reflect window state.
-  EXPECT_TRUE(output[2].IsValid());
-  EXPECT_EQ(SyncChange::ACTION_UPDATE, output[2].change_type());
-  const SyncData data_2(output[2].sync_data());
+  EXPECT_TRUE(output[3].IsValid());
+  EXPECT_EQ(SyncChange::ACTION_UPDATE, output[3].change_type());
+  const SyncData data_2(output[3].sync_data());
   EXPECT_EQ(manager()->current_machine_tag(),
             syncer::SyncDataLocal(data_2).GetTag());
   const sync_pb::SessionSpecifics& specifics2(data_2.GetSpecifics().session());
@@ -1376,9 +1216,7 @@
 
   syncer::SyncChangeList output1;
   InitWithSyncDataTakeOutput(foreign_data1, &output1);
-
-  // 1 header add, one tab add, one header update.
-  ASSERT_EQ(3U, output1.size());
+  ASSERT_EQ(4U, output1.size());
 
   // Add a second window to the foreign session.
   // TODO(tim): Bug 98892. Add local window too when observers are hooked up.
@@ -1469,10 +1307,10 @@
       tag, tab_nums1, &tabs));
 
   // Update associator with the session's meta node, window, and tabs.
-  manager()->UpdateTrackerWithSpecifics(meta, base::Time());
+  manager()->UpdateTrackerWithForeignSession(meta, base::Time());
   for (std::vector<sync_pb::SessionSpecifics>::iterator iter = tabs.begin();
        iter != tabs.end(); ++iter) {
-    manager()->UpdateTrackerWithSpecifics(*iter, base::Time());
+    manager()->UpdateTrackerWithForeignSession(*iter, base::Time());
   }
   ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
   ASSERT_EQ(1U, foreign_sessions.size());
@@ -1484,7 +1322,7 @@
   EXPECT_EQ(5U, changes.size());
   std::set<std::string> expected_tags(&tag, &tag + 1);
   for (int i = 0; i < 5; i++)
-    expected_tags.insert(TabNodeIdToTag(tag, i));
+    expected_tags.insert(TabNodePool::TabIdToTag(tag, i));
 
   for (int i = 0; i < 5; i++) {
     SCOPED_TRACE(changes[i].ToString());
@@ -1607,31 +1445,40 @@
   // committing the NavigationEntry. The first notification results in a tab
   // we don't associate although we do update the header node.  The second
   // notification triggers association of the tab, and the subsequent window
-  // update.  So we should see 3 changes at the SyncChangeProcessor.
-  ASSERT_EQ(3U, out.size());
+  // update.  So we should see 4 changes at the SyncChangeProcessor.
+  ASSERT_EQ(4U, out.size());
 
   EXPECT_EQ(SyncChange::ACTION_UPDATE, out[0].change_type());
   ASSERT_TRUE(out[0].sync_data().GetSpecifics().session().has_header());
   EXPECT_EQ(SyncChange::ACTION_ADD, out[1].change_type());
   int tab_node_id = out[1].sync_data().GetSpecifics().session().tab_node_id();
-  EXPECT_EQ(TabNodeIdToTag(manager()->current_machine_tag(), tab_node_id),
+  EXPECT_EQ(TabNodePool::TabIdToTag(
+                manager()->current_machine_tag(), tab_node_id),
             syncer::SyncDataLocal(out[1].sync_data()).GetTag());
   EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type());
-  ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_header());
+  ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_tab());
+  EXPECT_EQ(SyncChange::ACTION_UPDATE, out[3].change_type());
+  ASSERT_TRUE(out[3].sync_data().GetSpecifics().session().has_header());
 
   // Verify the actual content.
   const sync_pb::SessionHeader& session_header =
-      out[2].sync_data().GetSpecifics().session().header();
+      out[3].sync_data().GetSpecifics().session().header();
   ASSERT_EQ(1, session_header.window_size());
   EXPECT_EQ(1, session_header.window(0).tab_size());
   const sync_pb::SessionTab& tab1 =
-      out[1].sync_data().GetSpecifics().session().tab();
+      out[2].sync_data().GetSpecifics().session().tab();
   ASSERT_EQ(1, tab1.navigation_size());
   EXPECT_EQ(foo1.spec(), tab1.navigation(0).virtual_url());
 
   // Verify TabNodePool integrity.
-  EXPECT_EQ(1U, GetTabPool()->Capacity());
-  EXPECT_TRUE(GetTabPool()->Empty());
+  EXPECT_EQ(1U, manager()->local_tab_pool_.Capacity());
+  EXPECT_TRUE(manager()->local_tab_pool_.Empty());
+
+  // Verify TabLinks.
+  SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_;
+  ASSERT_EQ(1U, tab_map.size());
+  int tab_id = out[2].sync_data().GetSpecifics().session().tab().tab_id();
+  EXPECT_EQ(tab_node_id, tab_map.find(tab_id)->second->tab_node_id());
 }
 
 // Test that receiving a session delete from sync removes the session
@@ -1775,8 +1622,7 @@
       manager()->session_tracker_.LookupSessionTab(session_tag, 2, &tab));
 
   std::set<int> tab_node_ids;
-  manager()->session_tracker_.LookupForeignTabNodeIds(session_tag,
-                                                      &tab_node_ids);
+  manager()->session_tracker_.LookupTabNodeIds(session_tag, &tab_node_ids);
   EXPECT_EQ(6U, tab_node_ids.size());
   EXPECT_TRUE(tab_node_ids.find(tab1A.tab_node_id()) != tab_node_ids.end());
   EXPECT_TRUE(tab_node_ids.find(tab1B.tab_node_id()) != tab_node_ids.end());
@@ -1792,8 +1638,7 @@
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
   tab_node_ids.clear();
-  manager()->session_tracker_.LookupForeignTabNodeIds(session_tag,
-                                                      &tab_node_ids);
+  manager()->session_tracker_.LookupTabNodeIds(session_tag, &tab_node_ids);
   EXPECT_EQ(3U, tab_node_ids.size());
   EXPECT_TRUE(tab_node_ids.find(tab1C.tab_node_id()) != tab_node_ids.end());
   EXPECT_TRUE(tab_node_ids.find(tab2A.tab_node_id()) != tab_node_ids.end());
@@ -1831,8 +1676,7 @@
   output.clear();
 
   std::set<int> tab_node_ids;
-  manager()->session_tracker_.LookupForeignTabNodeIds(session_tag,
-                                                      &tab_node_ids);
+  manager()->session_tracker_.LookupTabNodeIds(session_tag, &tab_node_ids);
   EXPECT_EQ(2U, tab_node_ids.size());
   EXPECT_TRUE(tab_node_ids.find(tab_node_id_shared) != tab_node_ids.end());
   EXPECT_TRUE(tab_node_ids.find(tab_node_id_unique) != tab_node_ids.end());
@@ -1842,8 +1686,7 @@
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
   tab_node_ids.clear();
-  manager()->session_tracker_.LookupForeignTabNodeIds(session_tag,
-                                                      &tab_node_ids);
+  manager()->session_tracker_.LookupTabNodeIds(session_tag, &tab_node_ids);
   EXPECT_EQ(1U, tab_node_ids.size());
   EXPECT_TRUE(tab_node_ids.find(tab_node_id_unique) != tab_node_ids.end());
 
@@ -1851,87 +1694,51 @@
   EXPECT_EQ(1U, output.size());
 }
 
-TEST_F(SessionsSyncManagerTest, AssociationReusesNodes) {
+// TODO(shashishekhar): "Move this to TabNodePool unittests."
+TEST_F(SessionsSyncManagerTest, SaveUnassociatedNodesForReassociation) {
   syncer::SyncChangeList changes;
-  AddTab(browser(), GURL("http://foo1"));
-  InitWithSyncDataTakeOutput(syncer::SyncDataList(), &changes);
-  ASSERT_EQ(3U, changes.size());  // Header add, tab add, header update.
-  ASSERT_TRUE(changes[1].sync_data().GetSpecifics().session().has_tab());
-  int tab_node_id =
-      changes[1].sync_data().GetSpecifics().session().tab_node_id();
+  InitWithNoSyncData();
 
-  // Pass back the previous tab and header nodes at association, along with a
-  // second tab node (with a rewritten tab node id).
-  syncer::SyncDataList in;
-  in.push_back(
-      CreateRemoteData(changes[2].sync_data().GetSpecifics()));  // Header node.
-  sync_pb::SessionSpecifics new_tab(
-      changes[1].sync_data().GetSpecifics().session());
-  new_tab.set_tab_node_id(tab_node_id + 1);
-  in.push_back(CreateRemoteData(new_tab));  // New tab node.
-  in.push_back(CreateRemoteData(
-      changes[1].sync_data().GetSpecifics()));  // Old tab node.
+  std::string local_tag = manager()->current_machine_tag();
+  // Create a free node and then dissassociate sessions so that it ends up
+  // unassociated.
+  manager()->local_tab_pool_.GetFreeTabNode(&changes);
+
+  // Update the tab_id of the node, so that it is considered a valid
+  // unassociated node otherwise it will be mistaken for a corrupted node and
+  // will be deleted before being added to the tab node pool.
+  sync_pb::EntitySpecifics entity(changes[0].sync_data().GetSpecifics());
+  entity.mutable_session()->mutable_tab()->set_tab_id(1);
+  SyncData d = CreateRemoteData(entity);
+  syncer::SyncDataList in(&d, &d + 1);
   changes.clear();
-
-  // Reassociate (with the same single tab/window open).
-  manager()->StopSyncing(syncer::SESSIONS);
-  syncer::SyncMergeResult result = manager()->MergeDataAndStartSyncing(
+  SessionsSyncManager manager2(GetSyncSessionsClient(), sync_prefs(),
+                               local_device(), NewDummyRouter(),
+                               base::Closure(), base::Closure());
+  syncer::SyncMergeResult result = manager2.MergeDataAndStartSyncing(
       syncer::SESSIONS, in, std::unique_ptr<syncer::SyncChangeProcessor>(
                                 new TestSyncProcessorStub(&changes)),
       std::unique_ptr<syncer::SyncErrorFactory>(
           new syncer::SyncErrorFactoryMock()));
   ASSERT_FALSE(result.error().IsSet());
-
-  // No tab entities should be deleted. The original (lower) tab node id should
-  // be reused for association.
-  FilterOutLocalHeaderChanges(&changes);
-  ASSERT_EQ(1U, changes.size());
-  EXPECT_EQ(SyncChange::ACTION_UPDATE, changes[0].change_type());
-  EXPECT_TRUE(changes[0].sync_data().GetSpecifics().session().has_tab());
-  EXPECT_EQ(tab_node_id,
-            changes[0].sync_data().GetSpecifics().session().tab_node_id());
+  EXPECT_TRUE(FilterOutLocalHeaderChanges(&changes)->empty());
 }
 
-TEST_F(SessionsSyncManagerTest, MergeDeletesCorruptTabNodeId) {
+TEST_F(SessionsSyncManagerTest, MergeDeletesCorruptNode) {
   syncer::SyncChangeList changes;
   InitWithNoSyncData();
 
   std::string local_tag = manager()->current_machine_tag();
-  int tab_node_id = TabNodePool::kInvalidTabNodeID;
-  GetTabPool()->GetTabNodeForTab(0, &tab_node_id);
-  sync_pb::SessionSpecifics specifics;
-  specifics.set_session_tag(local_tag);
-  specifics.set_tab_node_id(tab_node_id);
-  SyncData d = CreateRemoteData(specifics);
+  int tab_node_id = manager()->local_tab_pool_.GetFreeTabNode(&changes);
+  SyncData d = CreateRemoteData(changes[0].sync_data().GetSpecifics());
   syncer::SyncDataList in(&d, &d + 1);
+  changes.clear();
   TearDown();
   SetUp();
   InitWithSyncDataTakeOutput(in, &changes);
   EXPECT_EQ(1U, FilterOutLocalHeaderChanges(&changes)->size());
   EXPECT_EQ(SyncChange::ACTION_DELETE, changes[0].change_type());
-  EXPECT_EQ(TabNodeIdToTag(local_tag, tab_node_id),
-            syncer::SyncDataLocal(changes[0].sync_data()).GetTag());
-}
-
-TEST_F(SessionsSyncManagerTest, MergeDeletesCorruptTabId) {
-  syncer::SyncChangeList changes;
-  InitWithNoSyncData();
-
-  std::string local_tag = manager()->current_machine_tag();
-  int tab_node_id = 0;
-  GetTabPool()->GetTabNodeForTab(0, &tab_node_id);
-  sync_pb::SessionSpecifics specifics;
-  specifics.set_session_tag(local_tag);
-  specifics.set_tab_node_id(tab_node_id);
-  specifics.mutable_tab()->set_tab_id(TabNodePool::kInvalidTabID);
-  SyncData d = CreateRemoteData(specifics);
-  syncer::SyncDataList in(&d, &d + 1);
-  TearDown();
-  SetUp();
-  InitWithSyncDataTakeOutput(in, &changes);
-  EXPECT_EQ(1U, FilterOutLocalHeaderChanges(&changes)->size());
-  EXPECT_EQ(SyncChange::ACTION_DELETE, changes[0].change_type());
-  EXPECT_EQ(TabNodeIdToTag(local_tag, tab_node_id),
+  EXPECT_EQ(TabNodePool::TabIdToTag(local_tag, tab_node_id),
             syncer::SyncDataLocal(changes[0].sync_data()).GetTag());
 }
 
@@ -2000,7 +1807,7 @@
   // Go to a sync-interesting URL.
   NavigateAndCommitActiveTab(GURL("http://foo2"));
 
-  EXPECT_EQ(2U, out.size());  // Tab add and header update.
+  EXPECT_EQ(3U, out.size());  // Tab add, update, and header update.
 
   EXPECT_TRUE(
       base::StartsWith(syncer::SyncDataLocal(out[0].sync_data()).GetTag(),
@@ -2010,9 +1817,18 @@
             out[0].sync_data().GetSpecifics().session().session_tag());
   EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type());
 
-  EXPECT_TRUE(out[1].IsValid());
+  EXPECT_TRUE(
+      base::StartsWith(syncer::SyncDataLocal(out[1].sync_data()).GetTag(),
+                       manager()->current_machine_tag(),
+                       base::CompareCase::SENSITIVE));
+  EXPECT_EQ(manager()->current_machine_tag(),
+            out[1].sync_data().GetSpecifics().session().session_tag());
+  EXPECT_TRUE(out[1].sync_data().GetSpecifics().session().has_tab());
   EXPECT_EQ(SyncChange::ACTION_UPDATE, out[1].change_type());
-  const SyncData data(out[1].sync_data());
+
+  EXPECT_TRUE(out[2].IsValid());
+  EXPECT_EQ(SyncChange::ACTION_UPDATE, out[2].change_type());
+  const SyncData data(out[2].sync_data());
   EXPECT_EQ(manager()->current_machine_tag(),
             syncer::SyncDataLocal(data).GetTag());
   const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
@@ -2044,17 +1860,17 @@
   AddTab(browser(), bar1);
   NavigateAndCommitActiveTab(bar2);
 
-  // Change type breakdown:
-  const size_t kChangesPerTabCreation = 3;  // 1 tab add + 2 header updates.
-  const size_t kChangesPerTabNav = 2;       // 1 tab update + 1 header update.
-  const size_t kChangesPerTab = kChangesPerTabNav + kChangesPerTabCreation;
-  const size_t kNumTabs = 2;
-  const size_t kTotalUpdates = kChangesPerTab * kNumTabs;
-  ASSERT_EQ(kTotalUpdates, out.size());
+  // One add, one update for each AddTab.
+  // One update for each NavigateAndCommit.
+  // = 6 total tab updates.
+  // One header update corresponding to each of those.
+  // = 6 total header updates.
+  // 12 total updates.
+  ASSERT_EQ(12U, out.size());
 
   // Verify the tab node creations and updates to ensure the SyncProcessor
   // sees the right operations.
-  for (size_t i = 0; i < kTotalUpdates; i++) {
+  for (int i = 0; i < 12; i++) {
     SCOPED_TRACE(i);
     EXPECT_TRUE(out[i].IsValid());
     const SyncData data(out[i].sync_data());
@@ -2063,30 +1879,40 @@
                                  base::CompareCase::SENSITIVE));
     const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
     EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
-    if (i % kChangesPerTab == 0) {
+    if (i % 6 == 0) {
       // First thing on an AddTab is a no-op header update for parented tab.
       EXPECT_EQ(header.SerializeAsString(),
                 data.GetSpecifics().SerializeAsString());
       EXPECT_EQ(manager()->current_machine_tag(),
                 syncer::SyncDataLocal(data).GetTag());
-    } else if (i % kChangesPerTab == 1) {
-      // Next, the tab should be added.
+    } else if (i % 6 == 1) {
+      // Next, the TabNodePool should create the tab node.
       EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type());
-      EXPECT_EQ(TabNodeIdToTag(manager()->current_machine_tag(),
-                               data.GetSpecifics().session().tab_node_id()),
+      EXPECT_EQ(TabNodePool::TabIdToTag(
+                    manager()->current_machine_tag(),
+                    data.GetSpecifics().session().tab_node_id()),
                 syncer::SyncDataLocal(data).GetTag());
-    } else if (i % kChangesPerTab == 2) {
+    } else if (i % 6 == 2) {
+      // Then we see the tab update to the URL.
+      EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
+      EXPECT_EQ(TabNodePool::TabIdToTag(
+                    manager()->current_machine_tag(),
+                    data.GetSpecifics().session().tab_node_id()),
+                syncer::SyncDataLocal(data).GetTag());
+      ASSERT_TRUE(specifics.has_tab());
+    } else if (i % 6 == 3) {
       // The header needs to be updated to reflect the new window state.
       EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
       EXPECT_TRUE(specifics.has_header());
-    } else if (i % kChangesPerTab == 3) {
+    } else if (i % 6 == 4) {
       // Now we move on to NavigateAndCommit.  Update the tab.
       EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
-      EXPECT_EQ(TabNodeIdToTag(manager()->current_machine_tag(),
-                               data.GetSpecifics().session().tab_node_id()),
+      EXPECT_EQ(TabNodePool::TabIdToTag(
+                    manager()->current_machine_tag(),
+                    data.GetSpecifics().session().tab_node_id()),
                 syncer::SyncDataLocal(data).GetTag());
       ASSERT_TRUE(specifics.has_tab());
-    } else if (i % kChangesPerTab == 4) {
+    } else if (i % 6 == 5) {
       // The header needs to be updated to reflect the new window state.
       EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
       ASSERT_TRUE(specifics.has_header());
@@ -2103,33 +1929,25 @@
   // ASSERT_TRUEs above allow us to dive in freely here.
   // Verify first tab.
   const sync_pb::SessionTab& tab1_1 =
-      out[1].sync_data().GetSpecifics().session().tab();
+      out[2].sync_data().GetSpecifics().session().tab();
   ASSERT_EQ(1, tab1_1.navigation_size());
   EXPECT_EQ(foo1.spec(), tab1_1.navigation(0).virtual_url());
   const sync_pb::SessionTab& tab1_2 =
-      out[3].sync_data().GetSpecifics().session().tab();
+      out[4].sync_data().GetSpecifics().session().tab();
   ASSERT_EQ(2, tab1_2.navigation_size());
   EXPECT_EQ(foo1.spec(), tab1_2.navigation(0).virtual_url());
   EXPECT_EQ(foo2.spec(), tab1_2.navigation(1).virtual_url());
 
   // Verify second tab.
   const sync_pb::SessionTab& tab2_1 =
-      out[6].sync_data().GetSpecifics().session().tab();
+      out[8].sync_data().GetSpecifics().session().tab();
   ASSERT_EQ(1, tab2_1.navigation_size());
   EXPECT_EQ(bar1.spec(), tab2_1.navigation(0).virtual_url());
   const sync_pb::SessionTab& tab2_2 =
-      out[8].sync_data().GetSpecifics().session().tab();
+      out[10].sync_data().GetSpecifics().session().tab();
   ASSERT_EQ(2, tab2_2.navigation_size());
   EXPECT_EQ(bar1.spec(), tab2_2.navigation(0).virtual_url());
   EXPECT_EQ(bar2.spec(), tab2_2.navigation(1).virtual_url());
-
-  // Verify tab delegates have Sync ids.
-  std::set<const SyncedWindowDelegate*> window_delegates =
-      get_synced_window_getter()->GetSyncedWindowDelegates();
-  // Sync ids are in reverse order because tabs are inserted at the beginning
-  // of the tab list.
-  EXPECT_EQ(1, (*window_delegates.begin())->GetTabAt(0)->GetSyncId());
-  EXPECT_EQ(0, (*window_delegates.begin())->GetTabAt(1)->GetSyncId());
 }
 
 // Check that if a tab becomes uninteresting (for example no syncable URLs),
@@ -2147,21 +1965,21 @@
 
   // Add an interesting tab.
   AddTab(browser(), kValidUrl);
-  // No-op header update, tab creation, header update.
-  ASSERT_EQ(3U, out.size());
+  // No-op header update, tab creation, tab update, header update.
+  ASSERT_EQ(4U, out.size());
   // The last two are the interesting updates.
-  ASSERT_TRUE(out[1].sync_data().GetSpecifics().session().has_tab());
-  EXPECT_EQ(kValidUrl.spec(), out[1]
+  ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_tab());
+  EXPECT_EQ(kValidUrl.spec(), out[2]
                                   .sync_data()
                                   .GetSpecifics()
                                   .session()
                                   .tab()
                                   .navigation(0)
                                   .virtual_url());
-  ASSERT_TRUE(out[2].sync_data().GetSpecifics().session().has_header());
+  ASSERT_TRUE(out[3].sync_data().GetSpecifics().session().has_header());
   ASSERT_EQ(1,
-            out[2].sync_data().GetSpecifics().session().header().window_size());
-  ASSERT_EQ(1, out[2]
+            out[3].sync_data().GetSpecifics().session().header().window_size());
+  ASSERT_EQ(1, out[3]
                    .sync_data()
                    .GetSpecifics()
                    .session()
@@ -2188,68 +2006,6 @@
             out[1].sync_data().GetSpecifics().session().header().window_size());
 }
 
-// Ensure that if there are tabs with duplicate ids, Sync ignores the
-// duplicates.
-TEST_F(SessionsSyncManagerTest, DuplicateTabIdFromNative) {
-  syncer::SyncDataList in;
-  syncer::SyncChangeList out;
-
-  // Set up two tabs. The second (kFoo2) will be the one at index 0.
-  AddTab(browser(), GURL(kFoo1));
-  AddTab(browser(), GURL(kFoo2));
-  InitWithSyncDataTakeOutput(in, &out);
-
-  // Should be one header add, 2 tab adds, and one header update.
-  ASSERT_EQ(4U, out.size());
-
-  // Grab the first tab.
-  const sync_pb::EntitySpecifics t0_entity = out[1].sync_data().GetSpecifics();
-  ASSERT_TRUE(t0_entity.session().has_tab());
-
-  in.clear();
-  out.clear();
-  manager()->StopSyncing(syncer::SESSIONS);
-
-  // Override the second tab with a placeholder tab delegate that matches
-  // the first tab.
-  PlaceholderTabDelegate t0_override(t0_entity.session().tab().tab_id(),
-                                     t0_entity.session().tab_node_id());
-
-  // Set up the window override with the new window ID and placeholder tab.
-  const std::set<const SyncedWindowDelegate*>& windows =
-      get_synced_window_getter()->GetSyncedWindowDelegates();
-  ASSERT_EQ(1U, windows.size());
-  SyncedWindowDelegateOverride window_override(*windows.begin());
-  window_override.OverrideTabAt(1, &t0_override,
-                                t0_entity.session().tab().tab_id());
-
-  // Inject the window override.
-  std::set<const SyncedWindowDelegate*> delegates;
-  delegates.insert(&window_override);
-  std::unique_ptr<TestSyncedWindowDelegatesGetter> getter(
-      new TestSyncedWindowDelegatesGetter(delegates));
-  set_synced_window_getter(getter.get());
-
-  // Resync without any existing nodes (simulating a first time sync).
-  syncer::SyncMergeResult result = manager()->MergeDataAndStartSyncing(
-      syncer::SESSIONS, in, std::unique_ptr<syncer::SyncChangeProcessor>(
-                                new TestSyncProcessorStub(&out)),
-      std::unique_ptr<syncer::SyncErrorFactory>(
-          new syncer::SyncErrorFactoryMock()));
-
-  // There should be only one tab change: an add.
-  ASSERT_EQ(1U, FilterOutLocalHeaderChanges(&out)->size());
-  EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type());
-  EXPECT_EQ(t0_entity.session().tab().navigation(0).virtual_url(),
-            out[0]
-                .sync_data()
-                .GetSpecifics()
-                .session()
-                .tab()
-                .navigation(0)
-                .virtual_url());
-}
-
 // Ensure model association associates the pre-existing tabs.
 TEST_F(SessionsSyncManagerTest, MergeLocalSessionExistingTabs) {
   AddTab(browser(), GURL("http://foo1"));
@@ -2259,7 +2015,7 @@
 
   syncer::SyncChangeList out;
   InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
-  ASSERT_EQ(4U, out.size());  // Header creation, add two tabs, header update
+  ASSERT_EQ(6U, out.size());
 
   // Check that this machine's data is not included in the foreign windows.
   std::vector<const SyncedSession*> foreign_sessions;
@@ -2280,7 +2036,7 @@
   EXPECT_EQ(0, header_s.window_size());
 
   // Verify the tab node creations and updates with content.
-  for (int i = 1; i < 3; i++) {
+  for (int i = 1; i < 5; i++) {
     EXPECT_TRUE(out[i].IsValid());
     const SyncData data(out[i].sync_data());
     EXPECT_TRUE(base::StartsWith(syncer::SyncDataLocal(data).GetTag(),
@@ -2288,13 +2044,18 @@
                                  base::CompareCase::SENSITIVE));
     const sync_pb::SessionSpecifics& specifics(data.GetSpecifics().session());
     EXPECT_EQ(manager()->current_machine_tag(), specifics.session_tag());
-    EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type());
+    if (i % 2 == 1) {
+      EXPECT_EQ(SyncChange::ACTION_ADD, out[i].change_type());
+    } else {
+      EXPECT_EQ(SyncChange::ACTION_UPDATE, out[i].change_type());
+      EXPECT_TRUE(specifics.has_tab());
+    }
   }
 
   // Verify the header was updated to reflect new window state.
-  EXPECT_TRUE(out[3].IsValid());
-  EXPECT_EQ(SyncChange::ACTION_UPDATE, out[3].change_type());
-  const SyncData data_2(out[3].sync_data());
+  EXPECT_TRUE(out[5].IsValid());
+  EXPECT_EQ(SyncChange::ACTION_UPDATE, out[5].change_type());
+  const SyncData data_2(out[5].sync_data());
   EXPECT_EQ(manager()->current_machine_tag(),
             syncer::SyncDataLocal(data_2).GetTag());
   const sync_pb::SessionSpecifics& specifics2(data_2.GetSpecifics().session());
@@ -2303,13 +2064,19 @@
   const sync_pb::SessionHeader& header_s2 = specifics2.header();
   EXPECT_EQ(1, header_s2.window_size());
 
-  // Verify tab delegates have Sync ids.
-  std::set<const SyncedWindowDelegate*> window_delegates =
-      get_synced_window_getter()->GetSyncedWindowDelegates();
-  // Sync ids are in same order as tabs because the association happens after
-  // the tabs are opened (and therefore iterates through same order).
-  EXPECT_EQ(0, (*window_delegates.begin())->GetTabAt(0)->GetSyncId());
-  EXPECT_EQ(1, (*window_delegates.begin())->GetTabAt(1)->GetSyncId());
+  // Verify TabLinks.
+  SessionsSyncManager::TabLinksMap tab_map = manager()->local_tab_map_;
+  ASSERT_EQ(2U, tab_map.size());
+  // Tabs are ordered by sessionid in tab_map, so should be able to traverse
+  // the tree based on order of tabs created
+  SessionsSyncManager::TabLinksMap::iterator iter = tab_map.begin();
+  ASSERT_EQ(2, iter->second->tab()->GetEntryCount());
+  EXPECT_EQ(GURL("http://foo1"), iter->second->tab()->GetVirtualURLAtIndex(0));
+  EXPECT_EQ(GURL("http://foo2"), iter->second->tab()->GetVirtualURLAtIndex(1));
+  iter++;
+  ASSERT_EQ(2, iter->second->tab()->GetEntryCount());
+  EXPECT_EQ(GURL("http://bar1"), iter->second->tab()->GetVirtualURLAtIndex(0));
+  EXPECT_EQ(GURL("http://bar2"), iter->second->tab()->GetVirtualURLAtIndex(1));
 }
 
 TEST_F(SessionsSyncManagerTest, ForeignSessionModifiedTime) {
@@ -2412,7 +2179,8 @@
   for (int i = 1; i < 5; i++) {
     EXPECT_EQ(SyncChange::ACTION_DELETE, output[i].change_type());
     const SyncData data(output[i].sync_data());
-    EXPECT_EQ(TabNodeIdToTag(tag1, i), syncer::SyncDataLocal(data).GetTag());
+    EXPECT_EQ(TabNodePool::TabIdToTag(tag1, i),
+              syncer::SyncDataLocal(data).GetTag());
   }
 
   ASSERT_TRUE(manager()->GetAllForeignSessions(&foreign_sessions));
@@ -2535,8 +2303,7 @@
 
   syncer::SyncChangeList out;
   InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
-  ASSERT_EQ(3U, out.size());  // Header ADD, tab ADD, header UPDATE.
-  out.clear();
+  ASSERT_EQ(4U, out.size());  // Header, tab ADD, tab UPDATE, header UPDATE.
 
   // To simulate WebContents swap during prerendering, create new WebContents
   // and swap with old WebContents.
@@ -2557,28 +2324,24 @@
       old_web_contents.get());
   browser()->tab_strip_model()->ReplaceWebContentsAt(index, new_web_contents);
 
-  ASSERT_EQ(4U, out.size());
-  EXPECT_EQ(SyncChange::ACTION_ADD, out[0].change_type());
-  out.clear();
+  ASSERT_EQ(9U, out.size());
+  EXPECT_EQ(SyncChange::ACTION_ADD, out[4].change_type());
+  EXPECT_EQ(SyncChange::ACTION_UPDATE, out[5].change_type());
 
-  // Navigate away. +1 tab updates, 1 header update.
+  // Navigate away.
   NavigateAndCommitActiveTab(GURL("http://bar2"));
 
   // Delete old WebContents. This should not crash.
-  // +1 no-op header update.
   old_web_contents.reset();
 
   // Try more navigations and verify output size. This can also reveal
   // bugs (leaks) on memcheck bots if the SessionSyncManager
   // didn't properly clean up the tab pool or session tracker.
-  // +1 tab updates, 1 header update.
   NavigateAndCommitActiveTab(GURL("http://bar3"));
 
-  // +1 no-op header update, tab add, header update.
   AddTab(browser(), GURL("http://bar4"));
-  // +1 tab update, header update.
   NavigateAndCommitActiveTab(GURL("http://bar5"));
-  ASSERT_EQ(10U, out.size());
+  ASSERT_EQ(19U, out.size());
 }
 
 // Test that NOTIFICATION_FOREIGN_SESSION_UPDATED is sent when processing
@@ -2823,7 +2586,8 @@
     sync_pb::EntitySpecifics entity;
     helper()->BuildTabSpecifics(kTag, 0, tab_list2[i],
                                 entity.mutable_session());
-    // Order the tabs oldest to most recent and left to right visually.
+    // Order the tabs oldest to most ReceiveDuplicateUnassociatedTabs and
+    // left to right visually.
     initial_data.push_back(
         CreateRemoteData(entity, base::Time::FromInternalValue(i + 1)));
   }
diff --git a/chrome/browser/sync/test/integration/printers_helper.cc b/chrome/browser/sync/test/integration/printers_helper.cc
index 2c0e3cc9..084e1d0 100644
--- a/chrome/browser/sync/test/integration/printers_helper.cc
+++ b/chrome/browser/sync/test/integration/printers_helper.cc
@@ -13,8 +13,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 
@@ -67,17 +67,17 @@
 
 }  // namespace
 
-void AddPrinter(chromeos::PrinterPrefManager* manager,
+void AddPrinter(chromeos::PrintersManager* manager,
                 const chromeos::Printer& printer) {
   manager->RegisterPrinter(base::MakeUnique<chromeos::Printer>(printer));
 }
 
-void RemovePrinter(chromeos::PrinterPrefManager* manager, int index) {
+void RemovePrinter(chromeos::PrintersManager* manager, int index) {
   chromeos::Printer testPrinter(CreateTestPrinter(index));
   manager->RemovePrinter(testPrinter.id());
 }
 
-bool EditPrinterDescription(chromeos::PrinterPrefManager* manager,
+bool EditPrinterDescription(chromeos::PrintersManager* manager,
                             int index,
                             const std::string& description) {
   PrinterList printers = manager->GetPrinters();
@@ -105,9 +105,9 @@
   return printer;
 }
 
-chromeos::PrinterPrefManager* GetVerifierPrinterStore() {
-  chromeos::PrinterPrefManager* manager =
-      chromeos::PrinterPrefManagerFactory::GetForBrowserContext(
+chromeos::PrintersManager* GetVerifierPrinterStore() {
+  chromeos::PrintersManager* manager =
+      chromeos::PrintersManagerFactory::GetForBrowserContext(
           sync_datatype_helper::test()->verifier());
   // Must wait for ModelTypeStore initialization.
   base::RunLoop().RunUntilIdle();
@@ -115,9 +115,9 @@
   return manager;
 }
 
-chromeos::PrinterPrefManager* GetPrinterStore(int index) {
-  chromeos::PrinterPrefManager* manager =
-      chromeos::PrinterPrefManagerFactory::GetForBrowserContext(
+chromeos::PrintersManager* GetPrinterStore(int index) {
+  chromeos::PrintersManager* manager =
+      chromeos::PrintersManagerFactory::GetForBrowserContext(
           sync_datatype_helper::test()->GetProfile(index));
   // Must wait for ModelTypeStore initialization.
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/sync/test/integration/printers_helper.h b/chrome/browser/sync/test/integration/printers_helper.h
index 3a676dc..a88265c 100644
--- a/chrome/browser/sync/test/integration/printers_helper.h
+++ b/chrome/browser/sync/test/integration/printers_helper.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
 #include "chrome/browser/sync/test/integration/await_match_status_change_checker.h"
 #include "chromeos/printing/printer_configuration.h"
 
@@ -22,23 +22,23 @@
 chromeos::Printer CreateTestPrinter(int index);
 
 // Add printer to the supplied store.
-void AddPrinter(chromeos::PrinterPrefManager* manager,
+void AddPrinter(chromeos::PrintersManager* manager,
                 const chromeos::Printer& printer);
 
 // Remove printer |index| from the |manager|.
-void RemovePrinter(chromeos::PrinterPrefManager* manager, int index);
+void RemovePrinter(chromeos::PrintersManager* manager, int index);
 
 // Change the description of the printer at |index| with |description|.  Returns
 // false if the printer is not tracked by the manager.
-bool EditPrinterDescription(chromeos::PrinterPrefManager* manager,
+bool EditPrinterDescription(chromeos::PrintersManager* manager,
                             int index,
                             const std::string& description);
 
 // Returns the verifier store.
-chromeos::PrinterPrefManager* GetVerifierPrinterStore();
+chromeos::PrintersManager* GetVerifierPrinterStore();
 
 // Returns printer store at |index|.
-chromeos::PrinterPrefManager* GetPrinterStore(int index);
+chromeos::PrintersManager* GetPrinterStore(int index);
 
 // Returns the number of printers in the verifier store.
 int GetVerifierPrinterCount();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 2ee1234..c32974bd 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -724,14 +724,6 @@
       "content_settings/content_setting_bubble_model_delegate.h",
       "content_settings/content_setting_image_model.cc",
       "content_settings/content_setting_image_model.h",
-      "desktop_ios_promotion/desktop_ios_promotion_controller.cc",
-      "desktop_ios_promotion/desktop_ios_promotion_controller.h",
-      "desktop_ios_promotion/desktop_ios_promotion_util.cc",
-      "desktop_ios_promotion/desktop_ios_promotion_util.h",
-      "desktop_ios_promotion/sms_service.cc",
-      "desktop_ios_promotion/sms_service.h",
-      "desktop_ios_promotion/sms_service_factory.cc",
-      "desktop_ios_promotion/sms_service_factory.h",
       "exclusive_access/exclusive_access_bubble.cc",
       "exclusive_access/exclusive_access_bubble.h",
       "exclusive_access/exclusive_access_bubble_type.cc",
@@ -822,6 +814,8 @@
       "signin_view_controller_delegate.h",
       "singleton_tabs.cc",
       "singleton_tabs.h",
+      "startup/automation_infobar_delegate.cc",
+      "startup/automation_infobar_delegate.h",
       "startup/bad_flags_prompt.cc",
       "startup/bad_flags_prompt.h",
       "startup/google_api_keys_infobar_delegate.cc",
@@ -1691,8 +1685,6 @@
         "views/constrained_web_dialog_delegate_views.cc",
         "views/create_application_shortcut_view.cc",
         "views/create_application_shortcut_view.h",
-        "views/desktop_ios_promotion/desktop_ios_promotion_view.cc",
-        "views/desktop_ios_promotion/desktop_ios_promotion_view.h",
         "views/download/download_feedback_dialog_view.cc",
         "views/download/download_feedback_dialog_view.h",
         "views/download/download_in_progress_dialog_view.cc",
@@ -3026,6 +3018,14 @@
 
   if (is_win) {
     sources += [
+      "desktop_ios_promotion/desktop_ios_promotion_controller.cc",
+      "desktop_ios_promotion/desktop_ios_promotion_controller.h",
+      "desktop_ios_promotion/desktop_ios_promotion_util.cc",
+      "desktop_ios_promotion/desktop_ios_promotion_util.h",
+      "desktop_ios_promotion/sms_service.cc",
+      "desktop_ios_promotion/sms_service.h",
+      "desktop_ios_promotion/sms_service_factory.cc",
+      "desktop_ios_promotion/sms_service_factory.h",
       "input_method/input_method_engine.cc",
       "input_method/input_method_engine.h",
       "input_method/input_method_engine_base.cc",
@@ -3036,6 +3036,8 @@
       "views/color_chooser_dialog.h",
       "views/critical_notification_bubble_view.cc",
       "views/critical_notification_bubble_view.h",
+      "views/desktop_ios_promotion/desktop_ios_promotion_view.cc",
+      "views/desktop_ios_promotion/desktop_ios_promotion_view.h",
       "views/frame/browser_desktop_window_tree_host.h",
       "views/frame/browser_desktop_window_tree_host_win.cc",
       "views/frame/browser_desktop_window_tree_host_win.h",
diff --git a/chrome/browser/ui/OWNERS b/chrome/browser/ui/OWNERS
index a7559f81..2928b08e 100644
--- a/chrome/browser/ui/OWNERS
+++ b/chrome/browser/ui/OWNERS
@@ -14,3 +14,5 @@
 
 # Instant/Search files.
 per-file browser_instant_controller*=file://chrome/browser/search/OWNERS
+
+# COMPONENT: UI>Browser
diff --git a/chrome/browser/ui/blocked_content/blocked_window_params.cc b/chrome/browser/ui/blocked_content/blocked_window_params.cc
index 2266367d..4a4c7e6 100644
--- a/chrome/browser/ui/blocked_content/blocked_window_params.cc
+++ b/chrome/browser/ui/blocked_content/blocked_window_params.cc
@@ -9,7 +9,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
-#include "third_party/WebKit/public/web/WebWindowFeatures.h"
 #include "url/gurl.h"
 
 BlockedWindowParams::BlockedWindowParams(
@@ -17,7 +16,7 @@
     const content::Referrer& referrer,
     const std::string& frame_name,
     WindowOpenDisposition disposition,
-    const blink::WebWindowFeatures& features,
+    const blink::mojom::WindowFeatures& features,
     bool user_gesture,
     bool opener_suppressed,
     int render_process_id,
@@ -30,8 +29,7 @@
       user_gesture_(user_gesture),
       opener_suppressed_(opener_suppressed),
       render_process_id_(render_process_id),
-      opener_render_frame_id_(opener_render_frame_id) {
-}
+      opener_render_frame_id_(opener_render_frame_id) {}
 
 BlockedWindowParams::BlockedWindowParams(const BlockedWindowParams& other) =
     default;
@@ -55,13 +53,13 @@
   nav_params.user_gesture = user_gesture_;
   nav_params.created_with_opener = !opener_suppressed_;
   nav_params.window_bounds = web_contents->GetContainerBounds();
-  if (features_.xSet)
+  if (features_.has_x)
     nav_params.window_bounds.set_x(features_.x);
-  if (features_.ySet)
+  if (features_.has_y)
     nav_params.window_bounds.set_y(features_.y);
-  if (features_.widthSet)
+  if (features_.has_width)
     nav_params.window_bounds.set_width(features_.width);
-  if (features_.heightSet)
+  if (features_.has_height)
     nav_params.window_bounds.set_height(features_.height);
 
   nav_params.disposition = disposition_;
diff --git a/chrome/browser/ui/blocked_content/blocked_window_params.h b/chrome/browser/ui/blocked_content/blocked_window_params.h
index 535a91b..80835f1 100644
--- a/chrome/browser/ui/blocked_content/blocked_window_params.h
+++ b/chrome/browser/ui/blocked_content/blocked_window_params.h
@@ -7,7 +7,7 @@
 
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "content/public/common/referrer.h"
-#include "third_party/WebKit/public/web/WebWindowFeatures.h"
+#include "third_party/WebKit/public/web/window_features.mojom.h"
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 
@@ -21,7 +21,7 @@
                       const content::Referrer& referrer,
                       const std::string& frame_name_,
                       WindowOpenDisposition disposition,
-                      const blink::WebWindowFeatures& features,
+                      const blink::mojom::WindowFeatures& features,
                       bool user_gesture,
                       bool opener_suppressed,
                       int render_process_id,
@@ -32,9 +32,7 @@
   chrome::NavigateParams CreateNavigateParams(
       content::WebContents* web_contents) const;
 
-  blink::WebWindowFeatures features() const {
-    return features_;
-  }
+  blink::mojom::WindowFeatures features() const { return features_; }
 
   int opener_render_frame_id() const {
     return opener_render_frame_id_;
@@ -53,7 +51,7 @@
   content::Referrer referrer_;
   std::string frame_name_;
   WindowOpenDisposition disposition_;
-  blink::WebWindowFeatures features_;
+  blink::mojom::WindowFeatures features_;
   bool user_gesture_;
   bool opener_suppressed_;
   int render_process_id_;
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
index 35f36bf7..c072c16 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
@@ -18,25 +18,22 @@
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
-#include "third_party/WebKit/public/web/WebWindowFeatures.h"
 
 #if defined(OS_ANDROID)
 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
 #endif
 
-using blink::WebWindowFeatures;
-
 const size_t kMaximumNumberOfPopups = 25;
 
 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PopupBlockerTabHelper);
 
 struct PopupBlockerTabHelper::BlockedRequest {
   BlockedRequest(const chrome::NavigateParams& params,
-                 const WebWindowFeatures& window_features)
+                 const blink::mojom::WindowFeatures& window_features)
       : params(params), window_features(window_features) {}
 
   chrome::NavigateParams params;
-  WebWindowFeatures window_features;
+  blink::mojom::WindowFeatures window_features;
 };
 
 PopupBlockerTabHelper::PopupBlockerTabHelper(
@@ -75,7 +72,7 @@
 
 bool PopupBlockerTabHelper::MaybeBlockPopup(
     const chrome::NavigateParams& params,
-    const WebWindowFeatures& window_features) {
+    const blink::mojom::WindowFeatures& window_features) {
   // A page can't spawn popups (or do anything else, either) until its load
   // commits, so when we reach here, the popup was spawned by the
   // NavigationController's last committed entry, not the active entry.  For
@@ -107,7 +104,7 @@
 
 void PopupBlockerTabHelper::AddBlockedPopup(
     const chrome::NavigateParams& params,
-    const WebWindowFeatures& window_features) {
+    const blink::mojom::WindowFeatures& window_features) {
   if (blocked_popups_.size() >= kMaximumNumberOfPopups)
     return;
 
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
index 0e0fabc..a43f8d14 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h
@@ -20,10 +20,6 @@
 struct NavigateParams;
 }
 
-namespace blink {
-struct WebWindowFeatures;
-}
-
 class GURL;
 
 // Per-tab class to manage blocked popups.
@@ -39,7 +35,7 @@
   // Returns true if the popup request defined by |params| should be blocked.
   // In that case, it is also added to the |blocked_popups_| container.
   bool MaybeBlockPopup(const chrome::NavigateParams& params,
-                       const blink::WebWindowFeatures& window_features);
+                       const blink::mojom::WindowFeatures& window_features);
 
   // Adds a popup request to the |blocked_popups_| container.
   void AddBlockedPopup(const BlockedWindowParams& params);
@@ -63,7 +59,7 @@
   explicit PopupBlockerTabHelper(content::WebContents* web_contents);
 
   void AddBlockedPopup(const chrome::NavigateParams& params,
-                       const blink::WebWindowFeatures& window_features);
+                       const blink::mojom::WindowFeatures& window_features);
 
   // Called when the blocked popup notification is shown or hidden.
   void PopupNotificationVisibilityChanged(bool visible);
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 8761fc9..6382fbec 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -204,7 +204,6 @@
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/url_request/url_request_context.h"
-#include "third_party/WebKit/public/web/WebWindowFeatures.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/gfx/geometry/point.h"
@@ -241,7 +240,6 @@
 using extensions::Extension;
 using ui::WebDialogDelegate;
 using web_modal::WebContentsModalDialogManager;
-using blink::WebWindowFeatures;
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -1414,8 +1412,8 @@
         !params.user_gesture &&
         !base::CommandLine::ForCurrentProcess()->HasSwitch(
             switches::kDisablePopupBlocking)) {
-      if (popup_blocker_helper->MaybeBlockPopup(nav_params,
-                                                WebWindowFeatures())) {
+      if (popup_blocker_helper->MaybeBlockPopup(
+              nav_params, blink::mojom::WindowFeatures())) {
         return NULL;
       }
     }
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 09699ec..b59372d 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -299,20 +299,20 @@
       if (base::FeatureList::IsEnabled(features::kBackspaceGoesBackFeature))
         GoBack(browser_, disposition);
       else
-        browser_->window()->MaybeShowNewBackShortcutBubble(false);
+        window()->MaybeShowNewBackShortcutBubble(false);
       break;
     case IDC_BACK:
-      browser_->window()->HideNewBackShortcutBubble();
+      window()->HideNewBackShortcutBubble();
       GoBack(browser_, disposition);
       break;
     case IDC_BACKSPACE_FORWARD:
       if (base::FeatureList::IsEnabled(features::kBackspaceGoesBackFeature))
         GoForward(browser_, disposition);
       else
-        browser_->window()->MaybeShowNewBackShortcutBubble(true);
+        window()->MaybeShowNewBackShortcutBubble(true);
       break;
     case IDC_FORWARD:
-      browser_->window()->HideNewBackShortcutBubble();
+      window()->HideNewBackShortcutBubble();
       GoForward(browser_, disposition);
       break;
     case IDC_RELOAD:
@@ -396,13 +396,13 @@
 #if defined(OS_CHROMEOS)
     case IDC_VISIT_DESKTOP_OF_LRU_USER_2:
     case IDC_VISIT_DESKTOP_OF_LRU_USER_3:
-      ExecuteVisitDesktopCommand(id, browser_->window()->GetNativeWindow());
+      ExecuteVisitDesktopCommand(id, window()->GetNativeWindow());
       break;
 #endif
 
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
     case IDC_USE_SYSTEM_TITLE_BAR: {
-      PrefService* prefs = browser_->profile()->GetPrefs();
+      PrefService* prefs = profile()->GetPrefs();
       prefs->SetBoolean(prefs::kUseCustomChromeFrame,
                         !prefs->GetBoolean(prefs::kUseCustomChromeFrame));
       break;
diff --git a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
index be23725..c04cf5d 100644
--- a/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.mm
@@ -41,7 +41,7 @@
 const float kFindBarCloseDuration = 0.15;
 const float kFindBarMoveDuration = 0.15;
 const float kRightEdgeOffset = 25;
-
+const int kMaxCharacters = 4000;
 
 @interface FindBarCocoaController (PrivateMethods) <NSAnimationDelegate>
 // Returns the appropriate frame for a hidden find bar.
@@ -228,6 +228,10 @@
     return;
   FindTabHelper* findTabHelper = FindTabHelper::FromWebContents(webContents);
 
+  // The find bar stops functioning if too many characters are used.
+  if ([[findText_ stringValue] length] > kMaxCharacters)
+    [findText_ setStringValue:[[findText_ stringValue]
+                                  substringToIndex:kMaxCharacters]];
   NSString* findText = [findText_ stringValue];
   if (![self isOffTheRecordProfile]) {
     base::AutoReset<BOOL> suppressReset(&suppressPboardUpdateActions_, YES);
diff --git a/chrome/browser/ui/cocoa/image_button_cell.mm b/chrome/browser/ui/cocoa/image_button_cell.mm
index 5e58cc8b..39ff8fb 100644
--- a/chrome/browser/ui/cocoa/image_button_cell.mm
+++ b/chrome/browser/ui/cocoa/image_button_cell.mm
@@ -17,14 +17,58 @@
 // slightly lighter color. We do this by just reducing the alpha.
 const CGFloat kImageNoFocusAlpha = 0.65;
 
+const CGFloat kHoverAnimationDuration = 0.2;  // seconds
+
+namespace {
+
+NSRect CenterImageInFrame(NSImage* image, NSRect frame) {
+  NSRect rect;
+  rect.size = [image size];
+  rect.origin.x =
+      frame.origin.x + std::round((NSWidth(frame) - NSWidth(rect)) / 2.0);
+  rect.origin.y =
+      frame.origin.y + std::round((NSHeight(frame) - NSHeight(rect)) / 2.0);
+  return rect;
+}
+}
+
 @interface ImageButtonCell (Private)
 - (void)sharedInit;
 - (image_button_cell::ButtonState)currentButtonState;
 - (NSImage*)imageForID:(NSInteger)imageID
            controlView:(NSView*)controlView;
+- (void)animationDidProgress;
 @end
 
-@implementation ImageButtonCell
+@interface HoverAnimation : NSAnimation
+- (id)initWithOwner:(ImageButtonCell*)owner;
+- (void)setCurrentProgress:(NSAnimationProgress)progress;
+@end
+
+@implementation HoverAnimation {
+  ImageButtonCell* owner_;
+}
+
+- (id)initWithOwner:(ImageButtonCell*)owner {
+  if ((self = [super initWithDuration:kHoverAnimationDuration
+                       animationCurve:NSAnimationEaseInOut])) {
+    [self setAnimationBlockingMode:NSAnimationNonblocking];
+    owner_ = owner;
+  }
+  return self;
+}
+
+- (void)setCurrentProgress:(NSAnimationProgress)progress {
+  [super setCurrentProgress:progress];
+  [owner_ animationDidProgress];
+}
+
+@end
+
+@implementation ImageButtonCell {
+  NSAnimation* hoverAnimation_;
+  image_button_cell::ButtonState oldState_;
+}
 
 @synthesize isMouseInside = isMouseInside_;
 
@@ -50,6 +94,13 @@
   // We need to set this so that we can override |-mouseEntered:| and
   // |-mouseExited:| to change the button image on hover states.
   [self setShowsBorderOnlyWhileMouseInside:YES];
+
+  hoverAnimation_ = [[HoverAnimation alloc] initWithOwner:self];
+}
+
+- (void)dealloc {
+  [hoverAnimation_ release];
+  [super dealloc];
 }
 
 - (NSImage*)imageForState:(image_button_cell::ButtonState)state
@@ -65,6 +116,8 @@
                         [[controlView window] isKeyWindow];
   CGFloat alpha = [self imageAlphaForWindowState:[controlView window]];
   NSImage* image = [self imageForState:state view:controlView];
+  NSImage* oldImage = nil;
+  CGFloat oldAlpha = 0.0;
 
   if (!windowHasFocus) {
     NSImage* defaultImage = [self
@@ -84,19 +137,33 @@
     }
   }
 
-  NSRect imageRect;
-  imageRect.size = [image size];
-  imageRect.origin.x = cellFrame.origin.x +
-    roundf((NSWidth(cellFrame) - NSWidth(imageRect)) / 2.0);
-  imageRect.origin.y = cellFrame.origin.y +
-    roundf((NSHeight(cellFrame) - NSHeight(imageRect)) / 2.0);
+  if ([hoverAnimation_ isAnimating]) {
+    oldImage = [self imageForState:oldState_ view:controlView];
+    oldAlpha = 1.0 - [hoverAnimation_ currentValue] * alpha;
+    alpha *= [hoverAnimation_ currentValue];
+  }
+
+  NSRect imageRect = CenterImageInFrame(image, cellFrame);
+  NSCompositingOperation op = [[controlView window] hasDarkTheme]
+                                  ? NSCompositePlusLighter
+                                  : NSCompositePlusDarker;
+
+  if (oldImage) {
+    NSRect oldImageRect = CenterImageInFrame(oldImage, cellFrame);
+    [oldImage drawInRect:oldImageRect
+                fromRect:NSZeroRect
+               operation:op
+                fraction:oldAlpha
+          respectFlipped:YES
+                   hints:nil];
+  }
 
   [image drawInRect:imageRect
-           fromRect:NSZeroRect
-          operation:NSCompositeSourceOver
-           fraction:alpha
-     respectFlipped:YES
-              hints:nil];
+            fromRect:NSZeroRect
+           operation:op
+            fraction:alpha
+      respectFlipped:YES
+               hints:nil];
 }
 
 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
@@ -160,9 +227,17 @@
   return themeProvider->GetNSImageNamed(imageID);
 }
 
+- (void)animationDidProgress {
+  NSView<ImageButton>* control =
+      static_cast<NSView<ImageButton>*>([self controlView]);
+  [control setNeedsDisplay:YES];
+}
+
 - (void)setIsMouseInside:(BOOL)isMouseInside {
   if (isMouseInside_ != isMouseInside) {
+    oldState_ = [self currentButtonState];
     isMouseInside_ = isMouseInside;
+    [hoverAnimation_ startAnimation];
     NSView<ImageButton>* control =
         static_cast<NSView<ImageButton>*>([self controlView]);
     if ([control respondsToSelector:@selector(mouseInsideStateDidChange:)]) {
diff --git a/chrome/browser/ui/cocoa/profiles/signin_view_controller_delegate_mac.h b/chrome/browser/ui/cocoa/profiles/signin_view_controller_delegate_mac.h
index 4823853..f190ae0 100644
--- a/chrome/browser/ui/cocoa/profiles/signin_view_controller_delegate_mac.h
+++ b/chrome/browser/ui/cocoa/profiles/signin_view_controller_delegate_mac.h
@@ -86,12 +86,6 @@
   // The web contents displayed in the constrained window.
   std::unique_ptr<content::WebContents> web_contents_;
   base::scoped_nsobject<ConstrainedWindowCustomWindow> window_;
-
-  // wait_for_size_ stores whether the dialog should only be shown after its
-  // content's size has been laid out and measured so that the constrained
-  // window is sized to the content.
-  bool wait_for_size_;
-
   Browser* browser_;
 
   // The dialog modal presentation type.
diff --git a/chrome/browser/ui/cocoa/profiles/signin_view_controller_delegate_mac.mm b/chrome/browser/ui/cocoa/profiles/signin_view_controller_delegate_mac.mm
index c680b31..9741d0f1 100644
--- a/chrome/browser/ui/cocoa/profiles/signin_view_controller_delegate_mac.mm
+++ b/chrome/browser/ui/cocoa/profiles/signin_view_controller_delegate_mac.mm
@@ -59,7 +59,6 @@
     bool wait_for_size)
     : SigninViewControllerDelegate(signin_view_controller, web_contents.get()),
       web_contents_(std::move(web_contents)),
-      wait_for_size_(wait_for_size),
       browser_(browser),
       dialog_modal_type_(dialog_modal_type),
       window_frame_(frame) {
@@ -67,7 +66,7 @@
   DCHECK(browser_->tab_strip_model()->GetActiveWebContents())
       << "A tab must be active to present the sign-in modal dialog.";
 
-  if (!wait_for_size_)
+  if (!wait_for_size)
     DisplayModal();
 }
 
@@ -168,16 +167,15 @@
 }
 
 void SigninViewControllerDelegateMac::ResizeNativeView(int height) {
-  if (wait_for_size_) {
-    [window_.get().contentView
-        setFrameSize:NSMakeSize(kModalDialogWidth,
-                                height)];
+  if (!window_) {
     window_frame_.size = NSMakeSize(kModalDialogWidth, height);
     DisplayModal();
   }
 }
 
 void SigninViewControllerDelegateMac::DisplayModal() {
+  DCHECK(!window_);
+
   content::WebContents* host_web_contents =
       browser_->tab_strip_model()->GetActiveWebContents();
 
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
index 1953c44..6e7e612 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
@@ -16,6 +16,7 @@
 #include "ui/base/theme_provider.h"
 #include "ui/gfx/image/image_skia_util_mac.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/vector_icons/vector_icons.h"
 
 namespace {
 
@@ -209,9 +210,9 @@
   BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
   switch ([self viewID]) {
     case VIEW_ID_BACK_BUTTON:
-      return isRTL ? &kNavigateForwardIcon : &kNavigateBackIcon;
+      return isRTL ? &ui::kForwardArrowIcon : &ui::kBackArrowIcon;
     case VIEW_ID_FORWARD_BUTTON:
-      return isRTL ? &kNavigateBackIcon : &kNavigateForwardIcon;
+      return isRTL ? &ui::kBackArrowIcon : &ui::kForwardArrowIcon;
     case VIEW_ID_HOME_BUTTON:
       return &kNavigateHomeIcon;
     case VIEW_ID_APP_MENU:
diff --git a/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.cc b/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.cc
index 77154ae..8f46fc1f 100644
--- a/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.cc
+++ b/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.cc
@@ -3,12 +3,44 @@
 // found in the LICENSE file.
 
 #include "chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.h"
+
+#include "base/i18n/rtl.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
 
 namespace desktop_ios_promotion {
 
-bool IsEligibleForIOSPromotion() {
-  return false;
+// Default Impression cap. for each entry point.
+const int kEntryPointImpressionCap[] = {2, 2, 5, 10};
+
+bool IsEligibleForIOSPromotion(
+    PrefService* prefs,
+    const syncer::SyncService* sync_service,
+    desktop_ios_promotion::PromotionEntryPoint entry_point) {
+  // Promotion should only show for english locale.
+  std::string locale = base::i18n::GetConfiguredLocale();
+  if (locale != "en-US" && locale != "en-CA")
+    return false;
+  if (!base::FeatureList::IsEnabled(features::kDesktopIOSPromotion) ||
+      !sync_service || !sync_service->IsSyncAllowed())
+    return false;
+  // TODO(crbug.com/676655): Check if the specific entrypoint is enabled by
+  // Finch.
+  bool is_dismissed =
+      prefs->GetBoolean(kEntryPointLocalPrefs[(int)entry_point][1]);
+  int show_count =
+      prefs->GetInteger(kEntryPointLocalPrefs[(int)entry_point][0]);
+  // TODO(crbug.com/676655): Get the impression cap. from Finch and replace the
+  // value from the entryPointImpressionCap array.
+  if (is_dismissed || show_count >= kEntryPointImpressionCap[(int)entry_point])
+    return false;
+  bool is_user_eligible = prefs->GetBoolean(prefs::kIOSPromotionEligible);
+  bool did_promo_done_before = prefs->GetBoolean(prefs::kIOSPromotionDone);
+  return is_user_eligible && !did_promo_done_before;
 }
 
 base::string16 GetPromoBubbleText(
@@ -21,4 +53,29 @@
   return base::string16();
 }
 
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
+  registry->RegisterBooleanPref(
+      prefs::kIOSPromotionEligible, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kIOSPromotionDone, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
+}
+
+void RegisterLocalPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterIntegerPref(prefs::kNumberSavePasswordsBubbleIOSPromoShown,
+                                0);
+  registry->RegisterBooleanPref(prefs::kSavePasswordsBubbleIOSPromoDismissed,
+                                false);
+  registry->RegisterIntegerPref(prefs::kNumberBookmarksBubbleIOSPromoShown, 0);
+  registry->RegisterBooleanPref(prefs::kBookmarksBubbleIOSPromoDismissed,
+                                false);
+  registry->RegisterIntegerPref(prefs::kNumberBookmarksFootNoteIOSPromoShown,
+                                0);
+  registry->RegisterBooleanPref(prefs::kBookmarksFootNoteIOSPromoDismissed,
+                                false);
+  registry->RegisterIntegerPref(prefs::kNumberHistoryPageIOSPromoShown, 0);
+  registry->RegisterBooleanPref(prefs::kHistoryPageIOSPromoDismissed, false);
+}
+
 }  // namespace desktop_ios_promotion
diff --git a/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.h b/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.h
index 8560984..72b400e 100644
--- a/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.h
+++ b/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.h
@@ -6,8 +6,20 @@
 #define CHROME_BROWSER_UI_DESKTOP_IOS_PROMOTION_DESKTOP_IOS_PROMOTION_UTIL_H_
 
 #include "base/macros.h"
+#include "chrome/common/pref_names.h"
 #include "ui/base/l10n/l10n_util.h"
 
+namespace syncer {
+class SyncService;
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+class PrefRegistrySimple;
+class PrefService;
+
 namespace desktop_ios_promotion {
 
 // Represents the reason that the Desktop to iOS promotion was dismissed for.
@@ -24,16 +36,38 @@
 enum class PromotionEntryPoint {
   SAVE_PASSWORD_BUBBLE = 0,
   BOOKMARKS_BUBBLE,
-  BOOKMARKS_LINK,
+  BOOKMARKS_FOOTNOTE,
   HISTORY_PAGE
 };
 
-bool IsEligibleForIOSPromotion();
+// Entry points local prefs, each entry point has a preference for impressions
+// count and a preference for whether user dismissed it or not.
+// Do not change the order of this array, as it's indexed using
+// desktop_ios_promotion::PromotionEntryPoint.
+const char* const kEntryPointLocalPrefs[4][2] = {
+    {prefs::kNumberSavePasswordsBubbleIOSPromoShown,
+     prefs::kSavePasswordsBubbleIOSPromoDismissed},
+    {prefs::kNumberBookmarksBubbleIOSPromoShown,
+     prefs::kBookmarksBubbleIOSPromoDismissed},
+    {prefs::kNumberBookmarksFootNoteIOSPromoShown,
+     prefs::kBookmarksFootNoteIOSPromoDismissed},
+    {prefs::kNumberHistoryPageIOSPromoShown,
+     prefs::kHistoryPageIOSPromoDismissed}};
+
+bool IsEligibleForIOSPromotion(PrefService* prefs,
+                               const syncer::SyncService* sync_service,
+                               desktop_ios_promotion::PromotionEntryPoint);
 
 // Returns the Bubble text based on the promotion entry point.
 base::string16 GetPromoBubbleText(
     desktop_ios_promotion::PromotionEntryPoint entry_point);
 
+// Register all Priority Sync preferences.
+void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+// Register all local only Preferences.
+void RegisterLocalPrefs(PrefRegistrySimple* registry);
+
 }  // namespace desktop_ios_promotion
 
 #endif  // CHROME_BROWSER_UI_DESKTOP_IOS_PROMOTION_DESKTOP_IOS_PROMOTION_UTIL_H_
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_factory.cc b/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
index ddbfadf..384fcae 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_factory.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/common/channel_info.h"
+#include "chrome/common/chrome_switches.h"
 #include "components/version_info/version_info.h"
 #include "extensions/common/feature_switch.h"
 
@@ -84,6 +85,14 @@
   if (extensions::FeatureSwitch::force_dev_mode_highlighting()->IsEnabled())
     return true;
 
+  // If an automated test is controlling the browser, we don't show the dev mode
+  // bubble because it interferes with focus. This isn't a security concern
+  // because we'll instead show an (even scarier) infobar. See also
+  // AutomationInfoBarDelegate.
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableAutomation))
+    return false;
+
 #if defined(OS_WIN)
   if (chrome::GetChannel() >= version_info::Channel::BETA)
     return true;
diff --git a/chrome/browser/ui/omnibox/OWNERS b/chrome/browser/ui/omnibox/OWNERS
index 3363c143..48c43f2 100644
--- a/chrome/browser/ui/omnibox/OWNERS
+++ b/chrome/browser/ui/omnibox/OWNERS
@@ -1,2 +1,4 @@
 pkasting@chromium.org
 sky@chromium.org
+
+# COMPONENT: UI>Browser>Omnibox
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
index 3a9a891..d275afe 100644
--- a/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
 #include "chrome/grit/chromium_strings.h"
@@ -32,6 +31,10 @@
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util.h"
+#endif
+
 namespace metrics_util = password_manager::metrics_util;
 
 namespace {
@@ -446,8 +449,11 @@
     interaction_keeper_->set_sign_in_promo_shown_count(show_count);
     return true;
   }
-  // Desktop to mobile promotion.
-  if (desktop_ios_promotion::IsEligibleForIOSPromotion()) {
+#if defined(OS_WIN)
+  // Desktop to mobile promotion only enabled on windows.
+  if (desktop_ios_promotion::IsEligibleForIOSPromotion(
+          prefs, sync_service,
+          desktop_ios_promotion::PromotionEntryPoint::SAVE_PASSWORD_BUBBLE)) {
     interaction_keeper_->ReportInteractions(this);
     title_brand_link_range_ = gfx::Range();
     title_ = l10n_util::GetStringUTF16(
@@ -457,6 +463,7 @@
     // TODO(crbug.com/676655): Add required logging.
     return true;
   }
+#endif
   return false;
 }
 
diff --git a/chrome/browser/ui/search_engines/OWNERS b/chrome/browser/ui/search_engines/OWNERS
index 3363c143..83814ad 100644
--- a/chrome/browser/ui/search_engines/OWNERS
+++ b/chrome/browser/ui/search_engines/OWNERS
@@ -1,2 +1,4 @@
 pkasting@chromium.org
 sky@chromium.org
+
+# COMPONENT: UI>Browser>Search
diff --git a/chrome/browser/ui/startup/automation_infobar_delegate.cc b/chrome/browser/ui/startup/automation_infobar_delegate.cc
new file mode 100644
index 0000000..c7da2cd
--- /dev/null
+++ b/chrome/browser/ui/startup/automation_infobar_delegate.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/startup/automation_infobar_delegate.h"
+
+#include "chrome/browser/devtools/global_confirm_info_bar.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/infobars/core/infobar.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// static
+void AutomationInfoBarDelegate::Create() {
+  std::unique_ptr<ConfirmInfoBarDelegate> delegate(
+      new AutomationInfoBarDelegate());
+  GlobalConfirmInfoBar::Show(std::move(delegate));
+}
+
+AutomationInfoBarDelegate::AutomationInfoBarDelegate() {}
+
+AutomationInfoBarDelegate::~AutomationInfoBarDelegate() {}
+
+infobars::InfoBarDelegate::InfoBarIdentifier
+AutomationInfoBarDelegate::GetIdentifier() const {
+  return AUTOMATION_INFOBAR_DELEGATE;
+}
+
+bool AutomationInfoBarDelegate::ShouldExpire(
+    const NavigationDetails& details) const {
+  return false;
+}
+
+base::string16 AutomationInfoBarDelegate::GetMessageText() const {
+  return l10n_util::GetStringUTF16(IDS_CONTROLLED_BY_AUTOMATION);
+}
+
+int AutomationInfoBarDelegate::GetButtons() const {
+  return BUTTON_NONE;
+}
diff --git a/chrome/browser/ui/startup/automation_infobar_delegate.h b/chrome/browser/ui/startup/automation_infobar_delegate.h
new file mode 100644
index 0000000..bf60e2f4
--- /dev/null
+++ b/chrome/browser/ui/startup/automation_infobar_delegate.h
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_STARTUP_AUTOMATION_INFOBAR_DELEGATE_H_
+#define CHROME_BROWSER_UI_STARTUP_AUTOMATION_INFOBAR_DELEGATE_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/infobars/core/confirm_infobar_delegate.h"
+#include "ui/gfx/vector_icons_public.h"
+#include "url/gurl.h"
+
+// An infobar to inform users if their browser is being controlled by an
+// automated test.
+class AutomationInfoBarDelegate : public ConfirmInfoBarDelegate {
+ public:
+  static void Create();
+
+ private:
+  AutomationInfoBarDelegate();
+  ~AutomationInfoBarDelegate() override;
+
+  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
+  bool ShouldExpire(const NavigationDetails& details) const override;
+  base::string16 GetMessageText() const override;
+  int GetButtons() const override;
+
+  DISALLOW_COPY_AND_ASSIGN(AutomationInfoBarDelegate);
+};
+
+#endif  // CHROME_BROWSER_UI_STARTUP_AUTOMATION_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index ce566de36..930ed0c3 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -33,6 +33,7 @@
 #include "base/strings/string_tokenizer.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -673,8 +674,12 @@
     base::FilePath output_file(
         command_line.GetSwitchValuePath(switches::kDumpBrowserHistograms));
     if (!output_file.empty()) {
-      BrowserThread::PostBlockingPoolTask(
+      base::PostTaskWithTraits(
           FROM_HERE,
+          base::TaskTraits()
+              .MayBlock()
+              .WithPriority(base::TaskPriority::BACKGROUND)
+              .WithShutdownBehavior(base::TaskShutdownBehavior::BLOCK_SHUTDOWN),
           base::Bind(&DumpBrowserHistograms, output_file));
     }
     silent_launch = true;
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 237ccc7..bd234d54 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -66,6 +66,7 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/session_crashed_bubble.h"
+#include "chrome/browser/ui/startup/automation_infobar_delegate.h"
 #include "chrome/browser/ui/startup/bad_flags_prompt.h"
 #include "chrome/browser/ui/startup/default_browser_prompt.h"
 #include "chrome/browser/ui/startup/google_api_keys_infobar_delegate.h"
@@ -816,11 +817,19 @@
 #endif
   }
 
+  if (command_line_.HasSwitch(switches::kEnableAutomation))
+    AutomationInfoBarDelegate::Create();
+
   // The below info bars are only added to the first profile which is launched.
   // Other profiles might be restoring the browsing sessions asynchronously,
   // so we cannot add the info bars to the focused tabs here.
+  //
+  // These info bars are not shown when the browser is being controlled by
+  // automated tests, so that they don't interfere with tests that assume no
+  // info bars.
   if (is_process_startup == chrome::startup::IS_PROCESS_STARTUP &&
-      !command_line_.HasSwitch(switches::kTestType)) {
+      !command_line_.HasSwitch(switches::kTestType) &&
+      !command_line_.HasSwitch(switches::kEnableAutomation)) {
     chrome::ShowBadFlagsPrompt(browser);
     GoogleApiKeysInfoBarDelegate::Create(InfoBarService::FromWebContents(
         browser->tab_strip_model()->GetActiveWebContents()));
diff --git a/chrome/browser/ui/views/OWNERS b/chrome/browser/ui/views/OWNERS
index 163fbf6..94ffd42 100644
--- a/chrome/browser/ui/views/OWNERS
+++ b/chrome/browser/ui/views/OWNERS
@@ -5,3 +5,5 @@
 per-file drag_and_drop_interactive_uitest.*=lukasza@chromium.org
 per-file drag_and_drop_interactive_uitest.*=paulmeyer@chromium.org
 per-file drag_and_drop_interactive_uitest.*=file://content/OWNERS
+
+# COMPONENT: UI>Browser
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
index 8e29d52..c5e3931 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -301,6 +301,10 @@
 
     bb_view_.reset(new BookmarkBarView(browser_.get(), NULL));
     bb_view_->set_owned_by_client();
+    // Real bookmark bars get a BookmarkBarViewBackground. Set an opaque
+    // background here just to avoid triggering subpixel rendering issues.
+    bb_view_->set_background(
+        views::Background::CreateSolidBackground(SK_ColorWHITE));
     bb_view_->SetPageNavigator(&navigator_);
 
     AddTestData(CreateBigMenu());
diff --git a/chrome/browser/ui/views/frame/OWNERS b/chrome/browser/ui/views/frame/OWNERS
index 4da594a68..d589f40 100644
--- a/chrome/browser/ui/views/frame/OWNERS
+++ b/chrome/browser/ui/views/frame/OWNERS
@@ -3,3 +3,5 @@
 
 per-file immersive_mode_controller*=pkotwicz@chromium.org
 per-file *x11*=erg@chromium.org
+
+# COMPONENT: UI>Browser
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash.cc b/chrome/browser/ui/views/frame/browser_frame_ash.cc
index 1ec42a0..d40bb822 100644
--- a/chrome/browser/ui/views/frame/browser_frame_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_ash.cc
@@ -178,9 +178,10 @@
 // BrowserFrameAsh, private:
 
 void BrowserFrameAsh::SetWindowAutoManaged() {
-  if (!browser_view_->browser()->is_type_popup() ||
-      browser_view_->browser()->is_app()) {
-    ash::wm::GetWindowState(GetNativeWindow())->
-        set_window_position_managed(true);
+  // For browser window in Chrome OS, we should only enable the auto window
+  // management logic for tabbed browser.
+  if (!browser_view_->browser()->is_type_popup()) {
+    ash::wm::GetWindowState(GetNativeWindow())
+        ->set_window_position_managed(true);
   }
 }
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
new file mode 100644
index 0000000..5c7ca15
--- /dev/null
+++ b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
@@ -0,0 +1,79 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/frame/browser_frame_ash.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "ui/aura/window.h"
+#include "ui/display/display.h"
+#include "ui/display/screen.h"
+
+namespace {
+
+class BrowserTestParam : public InProcessBrowserTest,
+                         public testing::WithParamInterface<bool> {
+ public:
+  BrowserTestParam() {}
+  ~BrowserTestParam() {}
+
+  bool CreateV1App() { return GetParam(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BrowserTestParam);
+};
+
+}  // namespace
+
+// Test that in Chrome OS, for app browser (v1app) windows, the auto management
+// logic is disabled while for tabbed browser windows, it is enabled.
+IN_PROC_BROWSER_TEST_P(BrowserTestParam,
+                       TabbedOrAppBrowserWindowAutoManagementTest) {
+  // Default |browser()| is not used by this test.
+  browser()->window()->Close();
+
+  // Open a new browser window (app or tabbed depending on a parameter).
+  bool test_app = CreateV1App();
+  Browser::CreateParams params =
+      test_app ? Browser::CreateParams::CreateForApp(
+                     "test_browser_app", true /* trusted_source */, gfx::Rect(),
+                     browser()->profile())
+               : Browser::CreateParams(browser()->profile());
+  params.initial_show_state = ui::SHOW_STATE_DEFAULT;
+  Browser* browser = new Browser(params);
+  gfx::NativeWindow window = browser->window()->GetNativeWindow();
+  gfx::Rect original_bounds(gfx::Rect(150, 250, 400, 100));
+  window->SetBounds(original_bounds);
+  window->Show();
+
+  // For tabbed browser window, it will be centered to work area by auto window
+  // mangement logic; for app browser window, it will remain the given bounds.
+  gfx::Rect work_area = display::Screen::GetScreen()
+                            ->GetDisplayNearestPoint(window->bounds().origin())
+                            .work_area();
+  gfx::Rect tabbed_expected_bounds = work_area;
+  tabbed_expected_bounds.ClampToCenteredSize(original_bounds.size());
+  tabbed_expected_bounds.set_y(original_bounds.y());
+  if (test_app)
+    EXPECT_EQ(original_bounds, window->bounds());
+  else
+    EXPECT_EQ(tabbed_expected_bounds, window->bounds());
+
+  // Close the browser and re-create the browser window with the same app name.
+  browser->window()->Close();
+  browser = new Browser(params);
+  browser->window()->Show();
+
+  // The newly created browser window should remain the same bounds for each.
+  window = browser->window()->GetNativeWindow();
+  if (test_app)
+    EXPECT_EQ(original_bounds, window->bounds());
+  else
+    EXPECT_EQ(tabbed_expected_bounds, window->bounds());
+}
+
+INSTANTIATE_TEST_CASE_P(BrowserTestTabbedOrApp,
+                        BrowserTestParam,
+                        testing::Bool());
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index f4dbf87a..ec32f86 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -124,7 +124,6 @@
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/content_accelerators/accelerator_util.h"
@@ -1275,14 +1274,9 @@
     content::WebContents* web_contents,
     const GURL& virtual_url,
     const security_state::SecurityInfo& security_info) {
-  views::View* popup_anchor = nullptr;
-  if (ui::MaterialDesignController::IsSecondaryUiMaterial())
-    popup_anchor = toolbar_->location_bar();
-  else
-    popup_anchor = GetLocationBarView()->location_icon_view()->GetImageView();
-
-  WebsiteSettingsPopupView::ShowPopup(popup_anchor, gfx::Rect(), profile,
-                                      web_contents, virtual_url, security_info);
+  WebsiteSettingsPopupView::ShowPopup(
+      GetLocationBarView()->GetSecurityBubbleAnchorView(), gfx::Rect(), profile,
+      web_contents, virtual_url, security_info);
 }
 
 void BrowserView::ShowAppMenu() {
@@ -2018,7 +2012,7 @@
 
 bool BrowserView::DrawInfoBarArrows(int* x) const {
   if (x) {
-    gfx::Point anchor(toolbar_->location_bar()->GetLocationBarAnchorPoint());
+    gfx::Point anchor(toolbar_->location_bar()->GetInfoBarAnchorPoint());
     ConvertPointToTarget(toolbar_->location_bar(), this, &anchor);
     *x = anchor.x();
   }
@@ -2566,8 +2560,7 @@
   // popup.
   if (!IsFullscreen() &&
       !GetLocationBar()->GetOmniboxView()->model()->popup_model()->IsOpen()) {
-    gfx::Point icon_bottom(
-        toolbar_->location_bar()->GetLocationBarAnchorPoint());
+    gfx::Point icon_bottom(toolbar_->location_bar()->GetInfoBarAnchorPoint());
     ConvertPointToTarget(toolbar_->location_bar(), this, &icon_bottom);
     gfx::Point infobar_top;
     ConvertPointToTarget(infobar_container_, this, &infobar_top);
diff --git a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
index 8dda539..9226bf3e 100644
--- a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
@@ -18,10 +18,7 @@
 #if defined(USE_AURA)
 #include "chrome/browser/ui/browser_window_state.h"
 #include "ui/aura/client/aura_constants.h"
-#include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
 #endif
 
 using views::FocusManager;
@@ -86,15 +83,11 @@
 
   // Create a new app browser
   Browser* browser = new Browser(params);
-  ASSERT_TRUE(browser);
   gfx::NativeWindow window = browser->window()->GetNativeWindow();
   gfx::Rect original_bounds(gfx::Rect(150, 250, 400, 100));
   window->SetBounds(original_bounds);
   window->Show();
   // Dock the browser window using |kShowStateKey| property.
-  gfx::Rect work_area = display::Screen::GetScreen()
-                            ->GetDisplayNearestPoint(window->bounds().origin())
-                            .work_area();
   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_DOCKED);
 
   // Saved placement should reflect docked state (for app windows only in Ash).
@@ -109,58 +102,26 @@
   if (!kIsAsh)
     return;
 
-  // Saved placement should reflect restore bounds.
-  ASSERT_NE(nullptr, window->GetProperty(aura::client::kRestoreBoundsKey));
-  original_bounds = *window->GetProperty(aura::client::kRestoreBoundsKey);
-  gfx::Rect expected_bounds = work_area;
-  expected_bounds.ClampToCenteredSize(original_bounds.size());
-  expected_bounds.set_y(original_bounds.y());
-  EXPECT_EQ(expected_bounds.ToString(), bounds.ToString());
-  EXPECT_EQ(expected_bounds.ToString(), original_bounds.ToString());
-
-  // Browser window should be docked.
-  int width = 250;  // same as DockedWindowLayoutManager::kIdealWidth.
-  if (window->delegate() && window->delegate()->GetMinimumSize().width() != 0)
-    width = std::max(width, window->delegate()->GetMinimumSize().width());
-  expected_bounds = work_area;
-  expected_bounds.set_width(width);
-  expected_bounds.set_x(work_area.right() - expected_bounds.width());
-  EXPECT_EQ(expected_bounds.ToString(), window->GetTargetBounds().ToString());
-  EXPECT_EQ(ui::SHOW_STATE_DOCKED,
-            window->GetProperty(aura::client::kShowStateKey));
-  browser->window()->Close();
-
   // Newly created browser with the same app name should retain docked state
   // for app browser window but leave it as normal for a tabbed browser.
   browser = new Browser(params);
-  ASSERT_TRUE(browser);
   browser->window()->Show();
   window = browser->window()->GetNativeWindow();
-  EXPECT_EQ(test_app ? expected_bounds.ToString() : original_bounds.ToString(),
-            window->GetTargetBounds().ToString());
   EXPECT_EQ(test_app ? ui::SHOW_STATE_DOCKED : ui::SHOW_STATE_NORMAL,
             window->GetProperty(aura::client::kShowStateKey));
 
-  // Undocking the browser window should restore original size and vertical
-  // offset while centering the window horizontally.
-  // Tabbed window is already not docked.
-  expected_bounds = work_area;
-  expected_bounds.ClampToCenteredSize(original_bounds.size());
-  expected_bounds.set_y(original_bounds.y());
+  // Undocking the browser window.
   window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
-  EXPECT_EQ(expected_bounds.ToString(), window->GetTargetBounds().ToString());
   EXPECT_EQ(ui::SHOW_STATE_NORMAL,
             window->GetProperty(aura::client::kShowStateKey));
   browser->window()->Close();
 
   // Re-create the browser window with the same app name.
   browser = new Browser(params);
-  ASSERT_TRUE(browser);
   browser->window()->Show();
 
-  // Newly created browser should retain undocked state and bounds.
+  // Newly created browser should retain undocked state.
   window = browser->window()->GetNativeWindow();
-  EXPECT_EQ(expected_bounds.ToString(), window->GetTargetBounds().ToString());
   EXPECT_EQ(ui::SHOW_STATE_NORMAL,
             window->GetProperty(aura::client::kShowStateKey));
 }
diff --git a/chrome/browser/ui/views/frame/system_menu_model_delegate.cc b/chrome/browser/ui/views/frame/system_menu_model_delegate.cc
index aa6e7055..1ca899e 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_delegate.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_delegate.cc
@@ -45,13 +45,18 @@
   if (command_id != IDC_RESTORE_TAB)
     return true;
 
+  sessions::TabRestoreService* trs =
+      TabRestoreServiceFactory::GetForProfile(browser_->profile());
+
+  // The Service is not available in Guest Profiles or Incognito mode.
+  if (!trs)
+    return false;
+
   // chrome::IsCommandEnabled(IDC_RESTORE_TAB) returns true if TabRestoreService
   // hasn't been loaded yet. Return false if this is the case as we don't have
   // a good way to dynamically update the menu when TabRestoreService finishes
   // loading.
   // TODO(sky): add a way to update menu.
-  sessions::TabRestoreService* trs =
-      TabRestoreServiceFactory::GetForProfile(browser_->profile());
   if (!trs->IsLoaded()) {
     trs->LoadTabsFromLastSession();
     return false;
@@ -77,8 +82,9 @@
   if (IsCommandIdEnabled(command_id)) {
     sessions::TabRestoreService* trs =
         TabRestoreServiceFactory::GetForProfile(browser_->profile());
+    DCHECK(trs);
     trs->LoadTabsFromLastSession();
-    if (trs && !trs->entries().empty() &&
+    if (!trs->entries().empty() &&
         trs->entries().front()->type == sessions::TabRestoreService::WINDOW)
       string_id = IDS_RESTORE_WINDOW;
   }
diff --git a/chrome/browser/ui/views/infobars/OWNERS b/chrome/browser/ui/views/infobars/OWNERS
index bf426d6..550d854f 100644
--- a/chrome/browser/ui/views/infobars/OWNERS
+++ b/chrome/browser/ui/views/infobars/OWNERS
@@ -1 +1,3 @@
 pkasting@chromium.org
+
+# COMPONENT: UI>Browser>Infobars
diff --git a/chrome/browser/ui/views/location_bar/OWNERS b/chrome/browser/ui/views/location_bar/OWNERS
index bf426d6..fc03347 100644
--- a/chrome/browser/ui/views/location_bar/OWNERS
+++ b/chrome/browser/ui/views/location_bar/OWNERS
@@ -1 +1,3 @@
 pkasting@chromium.org
+
+# COMPONENT: UI>Browser>Omnibox
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index a37de8a5..e55e2024 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -75,6 +75,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/theme_provider.h"
 #include "ui/compositor/paint_recorder.h"
@@ -291,7 +292,7 @@
   return gfx::kPlaceholderColor;
 }
 
-SkColor LocationBarView::GetOpaqueBorderColor(bool incognito) {
+SkColor LocationBarView::GetOpaqueBorderColor(bool incognito) const {
   return color_utils::GetResultingPaintColor(
       GetBorderColor(), ThemeProperties::GetDefaultColor(
                             ThemeProperties::COLOR_TOOLBAR, incognito));
@@ -363,7 +364,7 @@
   omnibox_view_->SelectAll(true);
 }
 
-gfx::Point LocationBarView::GetLocationBarAnchorPoint() const {
+gfx::Point LocationBarView::GetInfoBarAnchorPoint() const {
   const views::ImageView* image = location_icon_view_->GetImageView();
   const gfx::Rect image_bounds(image->GetImageBounds());
   gfx::Point point(image_bounds.CenterPoint().x(), image_bounds.bottom());
@@ -371,6 +372,12 @@
   return point;
 }
 
+views::View* LocationBarView::GetSecurityBubbleAnchorView() {
+  if (ui::MaterialDesignController::IsSecondaryUiMaterial())
+    return this;
+  return location_icon_view()->GetImageView();
+}
+
 void LocationBarView::GetOmniboxPopupPositioningInfo(
     gfx::Point* top_left_screen_coord,
     int* popup_width,
@@ -662,7 +669,7 @@
                          : 0;
 }
 
-SkColor LocationBarView::GetBorderColor() {
+SkColor LocationBarView::GetBorderColor() const {
   return GetThemeProvider()->GetColor(
       ThemeProperties::COLOR_LOCATION_BAR_BORDER);
 }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 54f184de..d1719b17 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -139,7 +139,7 @@
 
   // Returns the location bar border color blended with the toolbar color.
   // It's guaranteed to be opaque.
-  SkColor GetOpaqueBorderColor(bool incognito);
+  SkColor GetOpaqueBorderColor(bool incognito) const;
 
   // Returns the color to be used for security text in the context of
   // |security_level|.
@@ -197,9 +197,13 @@
 
   LocationIconView* location_icon_view() { return location_icon_view_; }
 
-  // Return the point suitable for anchoring location-bar-anchored bubbles at.
-  // The point will be returned in the coordinates of the LocationBarView.
-  gfx::Point GetLocationBarAnchorPoint() const;
+  // Where InfoBar arrows should point. The point will be returned in the
+  // coordinates of the LocationBarView.
+  gfx::Point GetInfoBarAnchorPoint() const;
+
+  // The anchor view for security-related bubbles. That is, those anchored to
+  // the leading edge of the Omnibox, under the padlock.
+  views::View* GetSecurityBubbleAnchorView();
 
   OmniboxViewViews* omnibox_view() { return omnibox_view_; }
   const OmniboxViewViews* omnibox_view() const { return omnibox_view_; }
@@ -256,7 +260,7 @@
   int IncrementalMinimumWidth(views::View* view) const;
 
   // The border color, drawn on top of the toolbar.
-  SkColor GetBorderColor();
+  SkColor GetBorderColor() const;
 
   // Returns the thickness of any visible edge, in pixels.
   int GetHorizontalEdgeThickness() const;
diff --git a/chrome/browser/ui/views/omnibox/OWNERS b/chrome/browser/ui/views/omnibox/OWNERS
index bf426d6..fc03347 100644
--- a/chrome/browser/ui/views/omnibox/OWNERS
+++ b/chrome/browser/ui/views/omnibox/OWNERS
@@ -1 +1,3 @@
 pkasting@chromium.org
+
+# COMPONENT: UI>Browser>Omnibox
diff --git a/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc b/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc
index e32de0d..96fd286ed 100644
--- a/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc
+++ b/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/outdated_upgrade_bubble_view.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "base/task_scheduler/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/layout_constants.h"
@@ -14,7 +15,6 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/prefs/pref_service.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/user_metrics.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -132,9 +132,13 @@
           prefs::kAttemptedToEnableAutoupdate, true);
     }
 
-    // Re-enable updates by shelling out to setup.exe in the blocking pool.
-    content::BrowserThread::PostBlockingPoolTask(
+    // Re-enable updates by shelling out to setup.exe asynchronously.
+    base::PostTaskWithTraits(
         FROM_HERE,
+        base::TaskTraits()
+            .MayBlock()
+            .WithPriority(base::TaskPriority::BACKGROUND)
+            .WithShutdownBehavior(base::TaskShutdownBehavior::BLOCK_SHUTDOWN),
         base::Bind(&google_update::ElevateIfNeededToReenableUpdates));
 #endif  // defined(OS_WIN)
   }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
index c06b1ab..4979c58 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
 #include "chrome/browser/ui/passwords/password_dialog_prompts.h"
 #include "chrome/browser/ui/passwords/passwords_model_delegate.h"
-#include "chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/passwords/credentials_item_view.h"
 #include "chrome/browser/ui/views/passwords/credentials_selection_view.h"
@@ -37,6 +36,10 @@
 #include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 
+#if defined(OS_WIN)
+#include "chrome/browser/ui/views/desktop_ios_promotion/desktop_ios_promotion_view.h"
+#endif
+
 int ManagePasswordsBubbleView::auto_signin_toast_timeout_ = 3;
 
 // Helpers --------------------------------------------------------------------
@@ -824,10 +827,12 @@
   } else if (model_.state() ==
              password_manager::ui::CHROME_SIGN_IN_PROMO_STATE) {
     AddChildView(new SignInPromoView(this));
+#if defined(OS_WIN)
   } else if (model_.state() ==
              password_manager::ui::CHROME_DESKTOP_IOS_PROMO_STATE) {
     AddChildView(new DesktopIOSPromotionView(
         desktop_ios_promotion::PromotionEntryPoint::SAVE_PASSWORD_BUBBLE));
+#endif
   } else {
     AddChildView(new ManageView(this));
   }
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.cc b/chrome/browser/ui/views/payments/payment_request_views_util.cc
index a4f2c29..21e5fa1 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.cc
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.cc
@@ -9,7 +9,6 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_type.h"
@@ -19,6 +18,7 @@
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/vector_icons/vector_icons.h"
 #include "ui/views/border.h"
 #include "ui/views/bubble/bubble_frame_view.h"
 #include "ui/views/controls/button/button.h"
@@ -100,7 +100,7 @@
     layout->SkipColumns(1);
   } else {
     views::VectorIconButton* back_arrow = new views::VectorIconButton(delegate);
-    back_arrow->SetIcon(kNavigateBackIcon);
+    back_arrow->SetIcon(ui::kBackArrowIcon);
     back_arrow->SetSize(back_arrow->GetPreferredSize());
     back_arrow->set_tag(static_cast<int>(
         PaymentRequestCommonTags::BACK_BUTTON_TAG));
diff --git a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
index 83f947e..452fd9e9 100644
--- a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
+++ b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
@@ -49,7 +49,6 @@
       content_view_(content_view.release()),
       modal_signin_widget_(nullptr),
       dialog_modal_type_(dialog_modal_type),
-      wait_for_size_(wait_for_size),
       browser_(browser) {
   DCHECK(browser_);
   DCHECK(browser_->tab_strip_model()->GetActiveWebContents())
@@ -57,7 +56,7 @@
   DCHECK(dialog_modal_type == ui::MODAL_TYPE_CHILD ||
          dialog_modal_type == ui::MODAL_TYPE_WINDOW)
       << "Unsupported dialog modal type " << dialog_modal_type;
-  if (!wait_for_size_)
+  if (!wait_for_size)
     DisplayModal();
 }
 
@@ -107,7 +106,7 @@
       gfx::Size(kModalDialogWidth, std::min(height, max_height)));
   content_view_->Layout();
 
-  if (wait_for_size_) {
+  if (!modal_signin_widget_) {
     // The modal wasn't displayed yet so just show it with the already resized
     // view.
     DisplayModal();
@@ -115,6 +114,8 @@
 }
 
 void SigninViewControllerDelegateViews::DisplayModal() {
+  DCHECK(!modal_signin_widget_);
+
   content::WebContents* host_web_contents =
       browser_->tab_strip_model()->GetActiveWebContents();
 
diff --git a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
index 5cb52ce..81240a32a 100644
--- a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
+++ b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
@@ -77,11 +77,6 @@
   views::WebView* content_view_;
   views::Widget* modal_signin_widget_;  // Not owned.
   ui::ModalType dialog_modal_type_;
-
-  // wait_for_size_ stores whether the dialog should only be shown after its
-  // content's size has been laid out and measured so that the constrained
-  // window is sized to the content.
-  bool wait_for_size_;
   Browser* browser_;
 
   DISALLOW_COPY_AND_ASSIGN(SigninViewControllerDelegateViews);
diff --git a/chrome/browser/ui/views/tabs/OWNERS b/chrome/browser/ui/views/tabs/OWNERS
index 4ecca5d..cc960fa 100644
--- a/chrome/browser/ui/views/tabs/OWNERS
+++ b/chrome/browser/ui/views/tabs/OWNERS
@@ -3,3 +3,5 @@
 
 # For changes related to the tab alert indicator/button.
 miu@chromium.org
+
+# COMPONENT: UI>Browser>TabStrip
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 59d15a7..b4b700be 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -6,7 +6,7 @@
 
 #include "base/auto_reset.h"
 #include "base/macros.h"
-#include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/browser_process.h"
@@ -418,13 +418,12 @@
 }
 
 void BrowserTabStripController::CheckFileSupported(const GURL& url) {
-  base::PostTaskAndReplyWithResult(
-      content::BrowserThread::GetBlockingPool(),
-      FROM_HERE,
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, base::TaskTraits().MayBlock().WithPriority(
+                     base::TaskPriority::USER_VISIBLE),
       base::Bind(&FindURLMimeType, url),
       base::Bind(&BrowserTabStripController::OnFindURLMimeTypeCompleted,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 url));
+                 weak_ptr_factory_.GetWeakPtr(), url));
 }
 
 SkColor BrowserTabStripController::GetToolbarTopSeparatorColor() const {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 27f632ddb..1018f3e 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -71,6 +71,7 @@
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/keyboard/keyboard_controller.h"
 #include "ui/native_theme/native_theme_aura.h"
+#include "ui/vector_icons/vector_icons.h"
 #include "ui/views/focus/view_storage.h"
 #include "ui/views/widget/tooltip_manager.h"
 #include "ui/views/widget/widget.h"
@@ -742,18 +743,16 @@
   const SkColor disabled_color =
       tp->GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON_INACTIVE);
 
-  back_->SetImage(
-      views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(kNavigateBackIcon, normal_color));
-  back_->SetImage(
-      views::Button::STATE_DISABLED,
-      gfx::CreateVectorIcon(kNavigateBackIcon, disabled_color));
+  back_->SetImage(views::Button::STATE_NORMAL,
+                  gfx::CreateVectorIcon(ui::kBackArrowIcon, normal_color));
+  back_->SetImage(views::Button::STATE_DISABLED,
+                  gfx::CreateVectorIcon(ui::kBackArrowIcon, disabled_color));
   forward_->SetImage(
       views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(kNavigateForwardIcon, normal_color));
+      gfx::CreateVectorIcon(ui::kForwardArrowIcon, normal_color));
   forward_->SetImage(
       views::Button::STATE_DISABLED,
-      gfx::CreateVectorIcon(kNavigateForwardIcon, disabled_color));
+      gfx::CreateVectorIcon(ui::kForwardArrowIcon, disabled_color));
   home_->SetImage(views::Button::STATE_NORMAL,
                   gfx::CreateVectorIcon(kNavigateHomeIcon, normal_color));
   app_menu_button_->UpdateIcon();
diff --git a/chrome/browser/ui/views/website_settings/permission_prompt_impl.cc b/chrome/browser/ui/views/website_settings/permission_prompt_impl.cc
index cd97f68..eeb7254 100644
--- a/chrome/browser/ui/views/website_settings/permission_prompt_impl.cc
+++ b/chrome/browser/ui/views/website_settings/permission_prompt_impl.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
 #include "chrome/browser/ui/views/harmony/layout_delegate.h"
 #include "chrome/browser/ui/views/website_settings/permission_selector_row.h"
@@ -423,6 +424,11 @@
   bubble_delegate_->set_parent_window(
       platform_util::GetViewForWindow(browser_->window()->GetNativeWindow()));
 
+  // Compensate for vertical padding in the anchor view's image. Note this is
+  // ignored whenever the anchor view is null.
+  bubble_delegate_->set_anchor_view_insets(gfx::Insets(
+      GetLayoutConstant(LOCATION_BAR_BUBBLE_ANCHOR_VERTICAL_INSET), 0));
+
   views::BubbleDialogDelegateView::CreateBubble(bubble_delegate_)->Show();
   bubble_delegate_->SizeToContents();
 
diff --git a/chrome/browser/ui/views/website_settings/permission_prompt_impl_views.cc b/chrome/browser/ui/views/website_settings/permission_prompt_impl_views.cc
index d231511b..cf1117e 100644
--- a/chrome/browser/ui/views/website_settings/permission_prompt_impl_views.cc
+++ b/chrome/browser/ui/views/website_settings/permission_prompt_impl_views.cc
@@ -26,15 +26,11 @@
 const int kFullscreenLeftMargin = 40;
 
 views::View* PermissionPromptImpl::GetAnchorView() {
+  if (!browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR))
+    return nullptr;  // Fall back to GetAnchorPoint().
+
   BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser_);
-
-  if (browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR))
-    return browser_view->GetLocationBarView()
-        ->location_icon_view()
-        ->GetImageView();
-
-  // Fall back to GetAnchorPoint().
-  return nullptr;
+  return browser_view->GetLocationBarView()->GetSecurityBubbleAnchorView();
 }
 
 gfx::Point PermissionPromptImpl::GetAnchorPoint() {
diff --git a/chrome/browser/ui/website_settings/website_settings_ui.cc b/chrome/browser/ui/website_settings/website_settings_ui.cc
index eb5d6ae..926d87d 100644
--- a/chrome/browser/ui/website_settings/website_settings_ui.cc
+++ b/chrome/browser/ui/website_settings/website_settings_ui.cc
@@ -160,8 +160,9 @@
 
   switch (identity_status) {
     case WebsiteSettings::SITE_IDENTITY_STATUS_INTERNAL_PAGE:
-      return CreateSecurityDescription(IDS_WEBSITE_SETTINGS_INTERNAL_PAGE,
-                                       IDS_WEBSITE_SETTINGS_INTERNAL_PAGE);
+      // Internal pages have their own UI implementations which should never
+      // call this function.
+      NOTREACHED();
     case WebsiteSettings::SITE_IDENTITY_STATUS_CERT:
     case WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT:
     case WebsiteSettings::SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN:
diff --git a/chrome/browser/ui/webui/browsing_history_handler.cc b/chrome/browser/ui/webui/browsing_history_handler.cc
index a951127..c7accdef 100644
--- a/chrome/browser/ui/webui/browsing_history_handler.cc
+++ b/chrome/browser/ui/webui/browsing_history_handler.cc
@@ -522,6 +522,8 @@
       "queryEndTime",
       GetRelativeDateLocalized(clock_.get(), query_results_info->end_time));
 
+  // TODO(calamity): Clean up grouped-specific fields once grouped history is
+  // removed.
   results_info.SetString(
       "queryStartMonth",
       base::TimeFormatMonthAndYear(query_results_info->start_time));
diff --git a/chrome/browser/ui/webui/md_history_ui.cc b/chrome/browser/ui/webui/md_history_ui.cc
index 4b5a577..a68fc33 100644
--- a/chrome/browser/ui/webui/md_history_ui.cc
+++ b/chrome/browser/ui/webui/md_history_ui.cc
@@ -132,11 +132,6 @@
   source->AddBoolean("allowDeletingHistory", allow_deleting_history);
 
   source->AddBoolean(kShowMenuPromoKey, !MenuPromoShown(profile));
-
-  bool group_by_domain = base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kHistoryEnableGroupByDomain) || profile->IsSupervised();
-  source->AddBoolean("groupByDomain", group_by_domain);
-
   source->AddBoolean("isGuestSession", profile->IsGuestSession());
 
   source->AddBoolean(kIsUserSignedInKey, IsUserSignedIn(profile));
@@ -158,8 +153,6 @@
     {"app.js", IDR_MD_HISTORY_APP_JS},
     {"browser_service.html", IDR_MD_HISTORY_BROWSER_SERVICE_HTML},
     {"browser_service.js", IDR_MD_HISTORY_BROWSER_SERVICE_JS},
-    {"grouped_list.html", IDR_MD_HISTORY_GROUPED_LIST_HTML},
-    {"grouped_list.js", IDR_MD_HISTORY_GROUPED_LIST_JS},
     {"history_item.html", IDR_MD_HISTORY_HISTORY_ITEM_HTML},
     {"history_item.js", IDR_MD_HISTORY_HISTORY_ITEM_JS},
     {"history_list.html", IDR_MD_HISTORY_HISTORY_LIST_HTML},
@@ -242,8 +235,7 @@
 
 // static
 bool MdHistoryUI::IsEnabled(Profile* profile) {
-  return base::FeatureList::IsEnabled(features::kMaterialDesignHistory) &&
-         !profile->IsSupervised();
+  return base::FeatureList::IsEnabled(features::kMaterialDesignHistory);
 }
 
 // static
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 5b9b1d4..0a8c79c 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -509,6 +509,35 @@
     { "mouseSpeed", IDS_OPTIONS_SETTINGS_MOUSE_SPEED_DESCRIPTION },
     { "noPointingDevices", IDS_OPTIONS_NO_POINTING_DEVICES },
     { "confirm", IDS_CONFIRM },
+    {"configureFingerprintTitle", IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_TITLE},
+    {"configureFingerprintInstructionLocateScannerStep",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER},
+    {"configureFingerprintInstructionMoveFingerStep",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_MOVE_FINGER},
+    {"configureFingerprintInstructionReadyStep",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_READY},
+    {"configureFingerprintLiftFinger",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_LIFT_FINGER},
+    {"configureFingerprintPartialData",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_PARTIAL_DATA},
+    {"configureFingerprintInsufficientData",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSUFFICIENT_DATA},
+    {"configureFingerprintSensorDirty",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_SENSOR_DIRTY},
+    {"configureFingerprintTooSlow",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_FINGER_TOO_SLOW},
+    {"configureFingerprintTooFast",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_FINGER_TOO_FAST},
+    {"configureFingerprintCancelButton",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_CANCEL_BUTTON},
+    {"configureFingerprintDoneButton",
+      IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_DONE_BUTTON},
+    {"configurePinChoosePinTitle",
+      IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CHOOSE_PIN_TITLE},
+    {"configurePinConfirmPinTitle",
+      IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CONFIRM_PIN_TITLE},
+    {"configurePinContinueButton",
+      IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CONTINUE_BUTTON},
     { "configurePinChoosePinTitle",
       IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CHOOSE_PIN_TITLE },
     { "configurePinConfirmPinTitle",
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index 91aca4e..b6bc1383 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -141,6 +141,10 @@
 constexpr char kSetupPinJSPath[] = "people_page/setup_pin_dialog.js";
 constexpr char kFingerprintListHTMLPath[] = "people_page/fingerprint_list.html";
 constexpr char kFingerprintListJSPath[] = "people_page/fingerprint_list.js";
+constexpr char kSetupFingerprintHTMLPath[] =
+    "people_page/setup_fingerprint_dialog.html";
+constexpr char kSetupFingerprintJSPath[] =
+    "people_page/setup_fingerprint_dialog.js";
 constexpr char kSettingsRouteHTMLPath[] = "route.html";
 constexpr char kSettingsRouteJSPath[] = "route.js";
 constexpr char kSettingsSharedCSSHTMLPath[] = "settings_shared_css.html";
@@ -294,6 +298,10 @@
   path_to_idr_map_[kFingerprintListHTMLPath] =
       IDR_OPTIONS_FINGERPRINT_LIST_HTML;
   path_to_idr_map_[kFingerprintListJSPath] = IDR_OPTIONS_FINGERPRINT_LIST_JS;
+  path_to_idr_map_[kSetupFingerprintHTMLPath] =
+      IDR_OPTIONS_SETUP_FINGERPRINT_DIALOG_HTML;
+  path_to_idr_map_[kSetupFingerprintJSPath] =
+      IDR_OPTIONS_SETUP_FINGERPRINT_DIALOG_JS;
 
   path_to_idr_map_[kSettingsRouteHTMLPath] = IDR_OPTIONS_ROUTE_HTML;
   path_to_idr_map_[kSettingsRouteJSPath] = IDR_OPTIONS_ROUTE_JS;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index 17f33ab..9257c9bd 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -88,8 +88,8 @@
 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 #include "chrome/common/url_constants.h"
diff --git a/chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc b/chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc
index b41cffa6..df9bc55c 100644
--- a/chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc
+++ b/chrome/browser/ui/webui/print_preview/printer_backend_proxy_chromeos.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/chromeos/printing/cups_print_job_manager.h"
 #include "chrome/browser/chromeos/printing/cups_print_job_manager_factory.h"
 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/print_preview/printer_capabilities.h"
 #include "chrome/common/chrome_switches.h"
@@ -160,7 +160,7 @@
 class PrinterBackendProxyChromeos : public PrinterBackendProxy {
  public:
   explicit PrinterBackendProxyChromeos(Profile* profile) {
-    prefs_ = chromeos::PrinterPrefManagerFactory::GetForBrowserContext(profile);
+    prefs_ = chromeos::PrintersManagerFactory::GetForBrowserContext(profile);
     ppd_provider_ = chromeos::printing::CreateProvider(profile);
 
     // Construct the CupsPrintJobManager to listen for printing events.
@@ -180,7 +180,7 @@
   };
 
   void EnumeratePrinters(const EnumeratePrintersCallback& cb) override {
-    // PrinterPrefManager is not thread safe and must be called from the UI
+    // PrintersManager is not thread safe and must be called from the UI
     // thread.
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
@@ -222,7 +222,7 @@
   };
 
  private:
-  chromeos::PrinterPrefManager* prefs_;
+  chromeos::PrintersManager* prefs_;
   scoped_refptr<chromeos::printing::PpdProvider> ppd_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(PrinterBackendProxyChromeos);
diff --git a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
index 8c9f448..2a03ad8 100644
--- a/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/printing/fake_printer_discoverer.h"
 #include "chrome/browser/chromeos/printing/ppd_provider_factory.h"
-#include "chrome/browser/chromeos/printing/printer_pref_manager_factory.h"
+#include "chrome/browser/chromeos/printing/printers_manager_factory.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -134,7 +134,7 @@
   CHECK(args->GetString(0, &callback_id));
 
   std::vector<std::unique_ptr<Printer>> printers =
-      PrinterPrefManagerFactory::GetForBrowserContext(profile_)->GetPrinters();
+      PrintersManagerFactory::GetForBrowserContext(profile_)->GetPrinters();
 
   base::ListValue* printers_list = new base::ListValue;
   for (const std::unique_ptr<Printer>& printer : printers) {
@@ -157,7 +157,7 @@
 
   std::unique_ptr<Printer> printer = base::MakeUnique<Printer>(printer_id);
   printer->set_display_name(printer_name);
-  PrinterPrefManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter(
+  PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter(
       std::move(printer));
 }
 
@@ -166,7 +166,7 @@
   std::string printer_name;
   CHECK(args->GetString(0, &printer_id));
   CHECK(args->GetString(1, &printer_name));
-  PrinterPrefManagerFactory::GetForBrowserContext(profile_)->RemovePrinter(
+  PrintersManagerFactory::GetForBrowserContext(profile_)->RemovePrinter(
       printer_id);
 
   chromeos::DebugDaemonClient* client =
@@ -258,7 +258,7 @@
   std::string printer_name = printer->display_name();
   bool success = (result_code == 0);
   if (success) {
-    PrinterPrefManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter(
+    PrintersManagerFactory::GetForBrowserContext(profile_)->RegisterPrinter(
         std::move(printer));
   }
   CallJavascriptFunction(
diff --git a/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.cc b/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.cc
index 3d68dc90..7e2ebbc1 100644
--- a/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/device_storage_handler.cc
@@ -217,7 +217,8 @@
   updating_drive_cache_size_ = false;
   CallJavascriptFunction("cr.webUIListenerCallback",
                          base::StringValue("storage-drive-cache-size-changed"),
-                         base::StringValue(ui::FormatBytes(size)));
+                         base::StringValue(ui::FormatBytes(size)),
+                         base::FundamentalValue(size > 0));
 }
 
 void StorageHandler::UpdateBrowsingDataSize() {
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 5eb38dee..5523307 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1100,6 +1100,29 @@
     {"manageSupervisedUsersDescription",
      IDS_SETTINGS_PEOPLE_MANAGE_SUPERVISED_USERS_DESCRIPTION},
 #if defined(OS_CHROMEOS)
+    {"configureFingerprintTitle", IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_TITLE},
+    {"configureFingerprintInstructionLocateScannerStep",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_LOCATE_SCANNER},
+    {"configureFingerprintInstructionMoveFingerStep",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_MOVE_FINGER},
+    {"configureFingerprintInstructionReadyStep",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSTRUCTION_READY},
+    {"configureFingerprintLiftFinger",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_LIFT_FINGER},
+    {"configureFingerprintPartialData",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_PARTIAL_DATA},
+    {"configureFingerprintInsufficientData",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_INSUFFICIENT_DATA},
+    {"configureFingerprintSensorDirty",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_SENSOR_DIRTY},
+    {"configureFingerprintTooSlow",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_FINGER_TOO_SLOW},
+    {"configureFingerprintTooFast",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_FINGER_TOO_FAST},
+    {"configureFingerprintCancelButton",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_CANCEL_BUTTON},
+    {"configureFingerprintDoneButton",
+     IDS_SETTINGS_ADD_FINGERPRINT_DIALOG_DONE_BUTTON},
     {"configurePinChoosePinTitle",
      IDS_SETTINGS_PEOPLE_CONFIGURE_PIN_CHOOSE_PIN_TITLE},
     {"configurePinConfirmPinTitle",
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
index 60ac090..ed672f45 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
@@ -42,7 +42,7 @@
   std::unique_ptr<Browser> browser =
       chrome::CreateBrowserWithAuraTestWindowForParams(base::WrapUnique(window),
                                                        params);
-  if (browser->is_type_tabbed() || browser->is_app()) {
+  if (!browser->is_type_popup()) {
     ash::wm::GetWindowState(browser->window()->GetNativeWindow())
         ->set_window_position_managed(true);
   }
diff --git a/chrome/browser/webshare/share_service_impl.cc b/chrome/browser/webshare/share_service_impl.cc
index eadfe7e..281a082 100644
--- a/chrome/browser/webshare/share_service_impl.cc
+++ b/chrome/browser/webshare/share_service_impl.cc
@@ -123,30 +123,18 @@
     const std::vector<std::pair<base::string16, GURL>>& targets,
     const base::Callback<void(base::Optional<std::string>)>& callback) {
 // TODO(mgiuca): Get the browser window as |parent_window|.
-#if defined(OS_LINUX) || defined(OS_WIN)
   chrome::ShowWebShareTargetPickerDialog(nullptr /* parent_window */, targets,
                                          callback);
-#else
-  callback.Run(base::nullopt);
-#endif
 }
 
 Browser* ShareServiceImpl::GetBrowser() {
-// TODO(constantina): Prevent this code from being run/compiled in android.
-#if defined(OS_LINUX) || defined(OS_WIN)
   return BrowserList::GetInstance()->GetLastActive();
-#else
-  return nullptr;
-#endif
 }
 
 void ShareServiceImpl::OpenTargetURL(const GURL& target_url) {
-// TODO(constantina): Prevent this code from being run/compiled in android.
-#if defined(OS_LINUX) || defined(OS_WIN)
   Browser* browser = GetBrowser();
   chrome::AddTabAt(browser, target_url,
                    browser->tab_strip_model()->active_index() + 1, true);
-#endif
 }
 
 std::string ShareServiceImpl::GetTargetTemplate(
@@ -162,24 +150,14 @@
 }
 
 PrefService* ShareServiceImpl::GetPrefService() {
-// TODO(constantina): Prevent this code from being run/compiled in android.
-#if defined(OS_LINUX) || defined(OS_WIN)
   return GetBrowser()->profile()->GetPrefs();
-#else
-  return nullptr;
-#endif
 }
 
 blink::mojom::EngagementLevel ShareServiceImpl::GetEngagementLevel(
     const GURL& url) {
-// TODO(constantina): Prevent this code from being run/compiled in android.
-#if defined(OS_LINUX) || defined(OS_WIN)
   SiteEngagementService* site_engagement_service =
       SiteEngagementService::Get(GetBrowser()->profile());
   return site_engagement_service->GetEngagementLevel(url);
-#else
-  return blink::mojom::EngagementLevel::NONE;
-#endif
 }
 
 // static
@@ -216,14 +194,9 @@
                              const ShareCallback& callback) {
   std::unique_ptr<base::DictionaryValue> share_targets;
 
-// TODO(constantina): Prevent this code from being run/compiled in android.
-#if defined(OS_LINUX) || defined(OS_WIN)
   share_targets = GetPrefService()
                       ->GetDictionary(prefs::kWebShareVisitedTargets)
                       ->CreateDeepCopy();
-#else
-  return;
-#endif
 
   std::vector<std::pair<base::string16, GURL>> sufficiently_engaged_targets =
       GetTargetsWithSufficientEngagement(*share_targets);
diff --git a/chrome/browser/webshare/share_service_impl.h b/chrome/browser/webshare/share_service_impl.h
index b2de060..ed1cde81 100644
--- a/chrome/browser/webshare/share_service_impl.h
+++ b/chrome/browser/webshare/share_service_impl.h
@@ -40,9 +40,8 @@
   Browser* GetBrowser();
 
   // Returns the URL template of the target identified by |target_url|
-  std::string GetTargetTemplate(
-      const std::string& target_url,
-      const base::DictionaryValue& share_targets);
+  std::string GetTargetTemplate(const std::string& target_url,
+                                const base::DictionaryValue& share_targets);
 
   // Virtual for testing purposes.
   virtual PrefService* GetPrefService();
diff --git a/chrome/browser/webshare/share_service_impl_unittest.cc b/chrome/browser/webshare/share_service_impl_unittest.cc
index c47c106..11f4be7 100644
--- a/chrome/browser/webshare/share_service_impl_unittest.cc
+++ b/chrome/browser/webshare/share_service_impl_unittest.cc
@@ -154,8 +154,6 @@
 
 }  // namespace
 
-#if defined(OS_LINUX) || defined(OS_WIN)
-
 // Basic test to check the Share method calls the callback with the expected
 // parameters.
 TEST_F(ShareServiceImplUnittest, ShareCallbackParams) {
@@ -265,8 +263,6 @@
   run_loop.Run();
 }
 
-#endif  // defined(OS_LINUX) || defined(OS_WIN)
-
 // Replace various numbers of placeholders in various orders. Placeholders are
 // adjacent to eachother; there are no padding characters.
 TEST_F(ShareServiceImplUnittest, ReplacePlaceholders) {
diff --git a/chrome/browser/win/chrome_elf_init_unittest.cc b/chrome/browser/win/chrome_elf_init_unittest.cc
index dbf65159..3735610 100644
--- a/chrome/browser/win/chrome_elf_init_unittest.cc
+++ b/chrome/browser/win/chrome_elf_init_unittest.cc
@@ -30,7 +30,8 @@
   void SetUp() override {
     testing::Test::SetUp();
 
-    override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
 
     blacklist_registry_key_.reset(
         new base::win::RegKey(HKEY_CURRENT_USER,
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 608e7cc..174c574f 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -72,6 +72,11 @@
 #endif
 
 #if defined(OS_WIN)
+// Enables or disables desktop ios promotion, which shows a promotion to the
+// user promoting Chrome for iOS.
+const base::Feature kDesktopIOSPromotion{"DesktopIOSPromotion",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Disables the AutoImport feature on first run. See crbug.com/555550
 const base::Feature kDisableFirstRunAutoImportWin{
     "DisableFirstRunAutoImport", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index af02252..8ba7f41 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -51,6 +51,7 @@
 #endif
 
 #if defined(OS_WIN)
+extern const base::Feature kDesktopIOSPromotion;
 extern const base::Feature kDisableFirstRunAutoImportWin;
 #endif  // defined(OS_WIN)
 
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 73bc421..b0d7e66 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -304,6 +304,9 @@
 const char kEnableAudioDebugRecordingsFromExtension[] =
     "enable-audio-debug-recordings-from-extension";
 
+// Inform users that their browser is being controlled by an automated test.
+const char kEnableAutomation[] = "enable-automation";
+
 // Enables the benchmarking extensions.
 const char kEnableBenchmarking[]            = "enable-benchmarking";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index df69b26..49b9680 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -102,6 +102,7 @@
 extern const char kEasyUnlockAppPath[];
 extern const char kEnableAddToShelf[];
 extern const char kEnableAudioDebugRecordingsFromExtension[];
+extern const char kEnableAutomation[];
 extern const char kEnableBenchmarking[];
 extern const char kEnableBookmarkUndo[];
 extern const char kEnableClearBrowsingDataCounters[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 737b7a5e..b667f6f5 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2386,4 +2386,51 @@
 // value.
 const char kWebShareVisitedTargets[] = "profile.web_share.visited_targets";
 
+#if defined(OS_WIN)
+// True if the user is eligible to recieve "desktop to iOS" promotion.
+const char kIOSPromotionEligible[] = "ios.desktoptomobileeligible";
+
+// True if the "desktop to iOS" promotion was successful, i.e. user installed
+// the application and signed in after seeing the promotion and receiving the
+// SMS.
+const char kIOSPromotionDone[] = "ios.desktop_ios_promo_done";
+
+// Number of times user has seen the "desktop to iOS" save passwords bubble
+// promotion.
+const char kNumberSavePasswordsBubbleIOSPromoShown[] =
+    "savepasswords_bubble_ios_promo_shown_count";
+
+// True if the user has dismissed the "desktop to iOS" save passwords bubble
+// promotion.
+const char kSavePasswordsBubbleIOSPromoDismissed[] =
+    "savepasswords_bubble_ios_promo_dismissed";
+
+// Number of times the user has seen the "desktop to iOS" bookmarks bubble
+// promotion.
+const char kNumberBookmarksBubbleIOSPromoShown[] =
+    "bookmarks_bubble_ios_promo_shown_count";
+
+// True if the user has dismissed the "desktop to iOS" bookmarks bubble
+// promotion.
+const char kBookmarksBubbleIOSPromoDismissed[] =
+    "bookmarks_bubble_ios_promo_dismissed";
+
+// Number of times user has seen the "desktop to iOS" bookmarks foot note
+// promotion.
+const char kNumberBookmarksFootNoteIOSPromoShown[] =
+    "bookmarks_footnote_ios_promo_shown_count";
+
+// True if the user has dismissed the "desktop to iOS" bookmarks foot note
+// promotion.
+const char kBookmarksFootNoteIOSPromoDismissed[] =
+    "bookmarks_footnote_ios_promo_dismissed";
+
+// Number of times user has seen the "desktop to iOS" history page promotion.
+const char kNumberHistoryPageIOSPromoShown[] =
+    "history_page_ios_promo_shown_count";
+
+// True if the user has dismissed the "desktop to iOS" history page promotion.
+const char kHistoryPageIOSPromoDismissed[] = "history_page_ios_promo_dismissed";
+#endif
+
 }  // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index bd9ace0f..74c231d 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -878,6 +878,19 @@
 
 extern const char kWebShareVisitedTargets[];
 
+#if defined(OS_WIN)
+extern const char kIOSPromotionEligible[];
+extern const char kIOSPromotionDone[];
+extern const char kNumberSavePasswordsBubbleIOSPromoShown[];
+extern const char kSavePasswordsBubbleIOSPromoDismissed[];
+extern const char kNumberBookmarksBubbleIOSPromoShown[];
+extern const char kBookmarksBubbleIOSPromoDismissed[];
+extern const char kNumberBookmarksFootNoteIOSPromoShown[];
+extern const char kBookmarksFootNoteIOSPromoDismissed[];
+extern const char kNumberHistoryPageIOSPromoShown[];
+extern const char kHistoryPageIOSPromoDismissed[];
+#endif
+
 }  // namespace prefs
 
 #endif  // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 6060b43c..5eab22a 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -28,7 +28,7 @@
 #include "ipc/ipc_platform_file.h"
 #include "ppapi/features/features.h"
 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
-#include "third_party/WebKit/public/web/WebWindowFeatures.h"
+#include "third_party/WebKit/public/web/window_features.mojom.h"
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 #include "url/ipc/url_param_traits.h"
@@ -157,7 +157,7 @@
 
 // Updates the window features of the render view.
 IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetWindowFeatures,
-                    blink::WebWindowFeatures /* window_features */)
+                    blink::mojom::WindowFeatures /* window_features */)
 
 // Responds to the request for a thumbnail.
 // Thumbnail data will be empty is a thumbnail could not be produced.
diff --git a/chrome/install_static/install_util_unittest.cc b/chrome/install_static/install_util_unittest.cc
index de378b2..0f85d65 100644
--- a/chrome/install_static/install_util_unittest.cc
+++ b/chrome/install_static/install_util_unittest.cc
@@ -273,18 +273,18 @@
         scoped_install_details_(system_level_, std::get<0>(GetParam())),
         mode_(&InstallDetails::Get().mode()),
         root_key_(system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER),
-        nt_root_key_(system_level_ ? nt::HKLM : nt::HKCU) {
-    base::string16 path;
-    override_manager_.OverrideRegistry(root_key_, &path);
-    nt::SetTestingOverride(nt_root_key_, path);
-  }
-
-  ~InstallStaticUtilTest() {
-    nt::SetTestingOverride(nt_root_key_, base::string16());
-  }
+        nt_root_key_(system_level_ ? nt::HKLM : nt::HKCU) {}
 
   void SetUp() override {
     ASSERT_TRUE(!system_level_ || mode_->supports_system_level);
+    base::string16 path;
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(root_key_, &path));
+    nt::SetTestingOverride(nt_root_key_, path);
+  }
+
+  void TearDown() override {
+    nt::SetTestingOverride(nt_root_key_, base::string16());
   }
 
   bool system_level() const { return system_level_; }
diff --git a/chrome/install_static/product_install_details_unittest.cc b/chrome/install_static/product_install_details_unittest.cc
index cdea80c..c64c900 100644
--- a/chrome/install_static/product_install_details_unittest.cc
+++ b/chrome/install_static/product_install_details_unittest.cc
@@ -173,15 +173,19 @@
         root_key_(test_data_.system_level ? HKEY_LOCAL_MACHINE
                                           : HKEY_CURRENT_USER),
         nt_root_key_(test_data_.system_level ? nt::HKLM : nt::HKCU) {
-    base::string16 path;
-    override_manager_.OverrideRegistry(root_key_, &path);
-    nt::SetTestingOverride(nt_root_key_, path);
   }
 
   ~MakeProductDetailsTest() {
     nt::SetTestingOverride(nt_root_key_, base::string16());
   }
 
+  void SetUp() override {
+    base::string16 path;
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(root_key_, &path));
+    nt::SetTestingOverride(nt_root_key_, path);
+  }
+
   const TestData& test_data() const { return test_data_; }
 
   void SetAp(const wchar_t* value) {
diff --git a/chrome/install_static/user_data_dir_win_unittest.cc b/chrome/install_static/user_data_dir_win_unittest.cc
index 30afd02..8029203b2 100644
--- a/chrome/install_static/user_data_dir_win_unittest.cc
+++ b/chrome/install_static/user_data_dir_win_unittest.cc
@@ -71,7 +71,8 @@
   // precedence over the command line in both implementations.
   registry_util::RegistryOverrideManager override_manager;
   base::string16 temp;
-  override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE, &temp);
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE, &temp));
   ScopedNTRegistryTestingOverride nt_override(nt::HKLM, temp);
 
   base::win::RegKey key(HKEY_LOCAL_MACHINE, kPolicyRegistryKey, KEY_WRITE);
@@ -92,7 +93,8 @@
   // precedence over the command line in both implementations.
   registry_util::RegistryOverrideManager override_manager;
   base::string16 temp;
-  override_manager.OverrideRegistry(HKEY_CURRENT_USER, &temp);
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager.OverrideRegistry(HKEY_CURRENT_USER, &temp));
   ScopedNTRegistryTestingOverride nt_override(nt::HKCU, temp);
 
   base::win::RegKey key(HKEY_CURRENT_USER, kPolicyRegistryKey, KEY_WRITE);
@@ -113,14 +115,16 @@
   // precedence.
   registry_util::RegistryOverrideManager override_manager;
   base::string16 temp;
-  override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE, &temp);
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE, &temp));
   ScopedNTRegistryTestingOverride nt_override(nt::HKLM, temp);
   LONG rv;
   base::win::RegKey key1(HKEY_LOCAL_MACHINE, kPolicyRegistryKey, KEY_WRITE);
   rv = key1.WriteValue(kUserDataDirRegistryKey, L"111");
   ASSERT_EQ(rv, ERROR_SUCCESS);
 
-  override_manager.OverrideRegistry(HKEY_CURRENT_USER, &temp);
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager.OverrideRegistry(HKEY_CURRENT_USER, &temp));
   ScopedNTRegistryTestingOverride nt_override2(nt::HKCU, temp);
   base::win::RegKey key2(HKEY_CURRENT_USER, kPolicyRegistryKey, KEY_WRITE);
   rv = key2.WriteValue(kUserDataDirRegistryKey, L"222");
@@ -138,7 +142,8 @@
 
   registry_util::RegistryOverrideManager override_manager;
   base::string16 temp;
-  override_manager.OverrideRegistry(HKEY_CURRENT_USER, &temp);
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager.OverrideRegistry(HKEY_CURRENT_USER, &temp));
   ScopedNTRegistryTestingOverride nt_override(nt::HKCU, temp);
   base::win::RegKey key(HKEY_CURRENT_USER, kPolicyRegistryKey, KEY_WRITE);
   LONG rv = key.WriteValue(kUserDataDirRegistryKey, L"${windows}");
diff --git a/chrome/installer/gcapi/BUILD.gn b/chrome/installer/gcapi/BUILD.gn
index 0c79315..c9a87388 100644
--- a/chrome/installer/gcapi/BUILD.gn
+++ b/chrome/installer/gcapi/BUILD.gn
@@ -66,8 +66,6 @@
     "gcapi_reactivation_test.cc",
     "gcapi_test.cc",
     "gcapi_test.rc",
-    "gcapi_test_registry_overrider.cc",
-    "gcapi_test_registry_overrider.h",
     "resource.h",
   ]
 
diff --git a/chrome/installer/gcapi/gcapi_last_run_test.cc b/chrome/installer/gcapi/gcapi_last_run_test.cc
index 4652f361..309a8c0 100644
--- a/chrome/installer/gcapi/gcapi_last_run_test.cc
+++ b/chrome/installer/gcapi/gcapi_last_run_test.cc
@@ -26,7 +26,8 @@
  protected:
   void SetUp() override {
     // Override keys - this is undone during destruction.
-    override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
 
     // Create the client state key in the right places.
     std::wstring reg_path(google_update::kRegPathClientState);
diff --git a/chrome/installer/gcapi/gcapi_omaha_experiment_test.cc b/chrome/installer/gcapi/gcapi_omaha_experiment_test.cc
index 958a538..a9020708 100644
--- a/chrome/installer/gcapi/gcapi_omaha_experiment_test.cc
+++ b/chrome/installer/gcapi/gcapi_omaha_experiment_test.cc
@@ -7,8 +7,8 @@
 #include <stdint.h>
 
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/test_reg_util_win.h"
 #include "chrome/installer/gcapi/gcapi.h"
-#include "chrome/installer/gcapi/gcapi_test_registry_overrider.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/google_update_settings.h"
 #include "components/variations/variations_experiment_util.h"
@@ -35,6 +35,13 @@
             kBrand, gcapi_internals::kRelaunchLabel)) {
   }
 
+  void SetUp() override {
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
+  }
+
   void VerifyExperimentLabels(const base::string16& expected_labels) {
     base::string16 actual_labels;
     EXPECT_TRUE(GoogleUpdateSettings::ReadExperimentLabels(false,
@@ -42,11 +49,10 @@
     EXPECT_EQ(expected_labels, actual_labels);
   }
 
+  registry_util::RegistryOverrideManager override_manager_;
   base::string16 brand_;
   base::string16 reactivation_label_;
   base::string16 relaunch_label_;
-
-  const GCAPITestRegistryOverrider gcapi_test_registry_overrider_;
 };
 
 TEST_F(GCAPIOmahaExperimentTest, SetReactivationLabelFromEmptyExperiments) {
diff --git a/chrome/installer/gcapi/gcapi_reactivation_test.cc b/chrome/installer/gcapi/gcapi_reactivation_test.cc
index 4bfd4b4..c4d93992 100644
--- a/chrome/installer/gcapi/gcapi_reactivation_test.cc
+++ b/chrome/installer/gcapi/gcapi_reactivation_test.cc
@@ -7,12 +7,12 @@
 #include <string>
 
 #include "base/strings/string_number_conversions.h"
+#include "base/test/test_reg_util_win.h"
 #include "base/time/time.h"
 #include "base/win/registry.h"
 #include "chrome/installer/gcapi/gcapi.h"
 #include "chrome/installer/gcapi/gcapi_omaha_experiment.h"
 #include "chrome/installer/gcapi/gcapi_reactivation.h"
-#include "chrome/installer/gcapi/gcapi_test_registry_overrider.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -24,6 +24,13 @@
  protected:
   GCAPIReactivationTest() {}
 
+  void SetUp() override {
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
+  }
+
   bool SetChromeInstallMarker(HKEY hive) {
     // Create the client state keys in the right places.
     std::wstring reg_path(google_update::kRegPathClients);
@@ -91,7 +98,7 @@
     return L"ERROR";
   }
 
-  const GCAPITestRegistryOverrider gcapi_test_registry_overrider_;
+  registry_util::RegistryOverrideManager override_manager_;
 };
 
 TEST_F(GCAPIReactivationTest, CheckSetReactivationBrandCode) {
diff --git a/chrome/installer/gcapi/gcapi_test_registry_overrider.cc b/chrome/installer/gcapi/gcapi_test_registry_overrider.cc
deleted file mode 100644
index ef97da36..0000000
--- a/chrome/installer/gcapi/gcapi_test_registry_overrider.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/installer/gcapi/gcapi_test_registry_overrider.h"
-
-#include "base/guid.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-
-GCAPITestRegistryOverrider::GCAPITestRegistryOverrider() {
-  // Override keys - this is undone during destruction.
-  override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
-  override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE);
-}
-
-GCAPITestRegistryOverrider::~GCAPITestRegistryOverrider() {
-}
diff --git a/chrome/installer/gcapi/gcapi_test_registry_overrider.h b/chrome/installer/gcapi/gcapi_test_registry_overrider.h
deleted file mode 100644
index b164b623..0000000
--- a/chrome/installer/gcapi/gcapi_test_registry_overrider.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_INSTALLER_GCAPI_GCAPI_TEST_REGISTRY_OVERRIDER_H_
-#define CHROME_INSTALLER_GCAPI_GCAPI_TEST_REGISTRY_OVERRIDER_H_
-
-#include "base/macros.h"
-#include "base/test/test_reg_util_win.h"
-
-// Overrides the registry throughout its lifetime; used by GCAPI tests
-// overriding the registry.
-class GCAPITestRegistryOverrider {
- public:
-  GCAPITestRegistryOverrider();
-  ~GCAPITestRegistryOverrider();
-
- private:
-  registry_util::RegistryOverrideManager override_manager_;
-
-  DISALLOW_COPY_AND_ASSIGN(GCAPITestRegistryOverrider);
-};
-
-#endif  // CHROME_INSTALLER_GCAPI_GCAPI_TEST_REGISTRY_OVERRIDER_H_
diff --git a/chrome/installer/linux/BUILD.gn b/chrome/installer/linux/BUILD.gn
index b16c723..406a8a2 100644
--- a/chrome/installer/linux/BUILD.gn
+++ b/chrome/installer/linux/BUILD.gn
@@ -194,6 +194,7 @@
   }
   if (current_cpu == "x86" || current_cpu == "x64") {
     public_deps += [
+      "//third_party/widevine/cdm:widevine_signature_scripts",
       "//third_party/widevine/cdm:widevinecdm",
       "//third_party/widevine/cdm:widevinecdmadapter",
     ]
diff --git a/chrome/installer/linux/common/installer.include b/chrome/installer/linux/common/installer.include
index d606238..96fa9f9 100644
--- a/chrome/installer/linux/common/installer.include
+++ b/chrome/installer/linux/common/installer.include
@@ -160,6 +160,20 @@
   if [ -f "${BUILDDIR}/libwidevinecdmadapter.so" ]; then
     install -m 644 -s "${BUILDDIR}/libwidevinecdmadapter.so" "${STAGEDIR}/${INSTALLDIR}/"
     install -m 644 "${BUILDDIR}/libwidevinecdm.so" "${STAGEDIR}/${INSTALLDIR}/"
+
+    if [ -f "${BUILDDIR}/installer/widevine/signature_generator.py" ]; then
+      # Create Widevine signature files for the stripped binaries.
+      echo Widevine signing "${STAGEDIR}/${INSTALLDIR}/${PROGNAME}"
+      ${BUILDDIR}/installer/widevine/signature_generator.py \
+        --input_file "${STAGEDIR}/${INSTALLDIR}/${PROGNAME}" \
+        --output_file "${STAGEDIR}/${INSTALLDIR}/${PROGNAME}.sig"
+      echo Widevine signing "${STAGEDIR}/${INSTALLDIR}/libwidevinecdmadapter.so"
+      ${BUILDDIR}/installer/widevine/signature_generator.py \
+        --input_file "${STAGEDIR}/${INSTALLDIR}/libwidevinecdmadapter.so" \
+        --output_file "${STAGEDIR}/${INSTALLDIR}/libwidevinecdmadapter.so.sig"
+      # Widevine signature file already exists for libwidevinecdm.so.
+      cp "${BUILDDIR}/libwidevinecdm.so.sig" "${STAGEDIR}/${INSTALLDIR}/"
+    fi
   fi
 
   # ANGLE
diff --git a/chrome/installer/mini_installer/configuration_test.cc b/chrome/installer/mini_installer/configuration_test.cc
index 89b6ffe6..b1f3400 100644
--- a/chrome/installer/mini_installer/configuration_test.cc
+++ b/chrome/installer/mini_installer/configuration_test.cc
@@ -52,9 +52,13 @@
 
 class MiniInstallerConfigurationTest : public ::testing::Test {
  protected:
-  MiniInstallerConfigurationTest() {
-    registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER);
-    registry_overrides_.OverrideRegistry(HKEY_LOCAL_MACHINE);
+  MiniInstallerConfigurationTest() = default;
+
+  void SetUp() override {
+    ASSERT_NO_FATAL_FAILURE(
+        registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_NO_FATAL_FAILURE(
+        registry_overrides_.OverrideRegistry(HKEY_LOCAL_MACHINE));
   }
 
   // Adds sufficient state in the registry for Configuration to think that
diff --git a/chrome/installer/setup/installer_state_unittest.cc b/chrome/installer/setup/installer_state_unittest.cc
index 8e60e258..f4d36e3 100644
--- a/chrome/installer/setup/installer_state_unittest.cc
+++ b/chrome/installer/setup/installer_state_unittest.cc
@@ -87,7 +87,7 @@
 
   {
     RegistryOverrideManager override_manager;
-    override_manager.OverrideRegistry(root);
+    ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(root));
     BrowserDistribution* dist = BrowserDistribution::GetDistribution();
     RegKey chrome_key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS);
     EXPECT_TRUE(chrome_key.Valid());
@@ -123,7 +123,7 @@
   };
   for (const wchar_t* command_line : kCommandLines) {
     RegistryOverrideManager override_manager;
-    override_manager.OverrideRegistry(root);
+    ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(root));
     base::CommandLine cmd_line = base::CommandLine::FromString(command_line);
     const MasterPreferences prefs(cmd_line);
     InstallationState machine_state;
@@ -164,8 +164,9 @@
   base::ScopedPathOverride local_app_data_override(base::DIR_LOCAL_APP_DATA,
                                                    temp);
   registry_util::RegistryOverrideManager override_manager;
-  override_manager.OverrideRegistry(HKEY_CURRENT_USER);
-  override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE);
+  ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(HKEY_CURRENT_USER));
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE));
 
   InstallationState machine_state;
   machine_state.Initialize();
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index db88da66..6f60b59 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -197,7 +197,8 @@
 
 TEST(SetupUtilTest, RegisterEventLogProvider) {
   registry_util::RegistryOverrideManager registry_override_manager;
-  registry_override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE);
+  ASSERT_NO_FATAL_FAILURE(
+      registry_override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE));
 
   const base::Version version("1.2.3.4");
   const base::FilePath install_directory(
@@ -374,8 +375,10 @@
 
   void SetUp() override {
     ASSERT_TRUE(test_dir_.CreateUniqueTempDir());
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
-    registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
     product_version_ = base::Version("30.0.1559.0");
     max_version_ = base::Version("47.0.1559.0");
 
@@ -530,7 +533,7 @@
   using RegKey = base::win::RegKey;
 
   void SetUp() override {
-    _registry_override_manager.OverrideRegistry(root_);
+    ASSERT_NO_FATAL_FAILURE(_registry_override_manager.OverrideRegistry(root_));
     to_preserve_.push_back(L"preSERve1");
     to_preserve_.push_back(L"1evRESerp");
   }
@@ -641,7 +644,8 @@
   LegacyCleanupsTest() = default;
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
     installer_state_ =
         base::MakeUnique<FakeInstallerState>(temp_dir_.GetPath());
     // Create the state to be cleared.
diff --git a/chrome/installer/setup/update_active_setup_version_work_item_unittest.cc b/chrome/installer/setup/update_active_setup_version_work_item_unittest.cc
index bf3ca46e..03daf7a 100644
--- a/chrome/installer/setup/update_active_setup_version_work_item_unittest.cc
+++ b/chrome/installer/setup/update_active_setup_version_work_item_unittest.cc
@@ -80,7 +80,8 @@
   UpdateActiveSetupVersionWorkItemTest() {}
 
   void SetUp() override {
-    registry_override_manager_.OverrideRegistry(kActiveSetupRoot);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(kActiveSetupRoot));
   }
 
  private:
diff --git a/chrome/installer/util/beacons_unittest.cc b/chrome/installer/util/beacons_unittest.cc
index a8d93ad..1ca2a8ad 100644
--- a/chrome/installer/util/beacons_unittest.cc
+++ b/chrome/installer/util/beacons_unittest.cc
@@ -41,10 +41,14 @@
                 beacon_type_,
                 beacon_scope_,
                 system_install_,
-                app_registration_data_) {
+                app_registration_data_) {}
+
+  void SetUp() override {
     // Override the registry so that tests can freely push state to it.
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
-    registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
   }
 
   TestAppRegistrationData app_registration_data_;
@@ -177,8 +181,10 @@
     }
 
     // Override the registry so that tests can freely push state to it.
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
-    registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
 
     // Ensure that IsPerUserInstall returns the proper value.
     ASSERT_EQ(!system_install_, InstallUtil::IsPerUserInstall(chrome_exe_));
diff --git a/chrome/installer/util/delete_reg_value_work_item_unittest.cc b/chrome/installer/util/delete_reg_value_work_item_unittest.cc
index 55ce612..0ffb1f1 100644
--- a/chrome/installer/util/delete_reg_value_work_item_unittest.cc
+++ b/chrome/installer/util/delete_reg_value_work_item_unittest.cc
@@ -28,7 +28,8 @@
   DeleteRegValueWorkItemTest() {}
 
   void SetUp() override {
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
   }
 
  private:
diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc
index 53cebb4..17a93bf9 100644
--- a/chrome/installer/util/google_update_settings_unittest.cc
+++ b/chrome/installer/util/google_update_settings_unittest.cc
@@ -52,9 +52,13 @@
 
   GoogleUpdateSettingsTest()
       : program_files_override_(base::DIR_PROGRAM_FILES),
-        program_files_x86_override_(base::DIR_PROGRAM_FILESX86) {
-    registry_overrides_.OverrideRegistry(HKEY_LOCAL_MACHINE);
-    registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER);
+        program_files_x86_override_(base::DIR_PROGRAM_FILESX86) {}
+
+  void SetUp() override {
+    ASSERT_NO_FATAL_FAILURE(
+        registry_overrides_.OverrideRegistry(HKEY_LOCAL_MACHINE));
+    ASSERT_NO_FATAL_FAILURE(
+        registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER));
   }
 
   void SetApField(SystemUserInstall is_system, const wchar_t* value) {
@@ -1203,8 +1207,10 @@
 // Install the registry override and apply the settings to the registry.
 void CollectStatsConsent::SetUp() {
   // Override both HKLM and HKCU as tests may touch either/both.
-  override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE);
-  override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE));
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
 
   const StatsState& stats_state = GetParam();
   const HKEY root_key = stats_state.root_key();
diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc
index eb962a4..ad1fbff 100644
--- a/chrome/installer/util/install_util_unittest.cc
+++ b/chrome/installer/util/install_util_unittest.cc
@@ -47,15 +47,15 @@
  protected:
   InstallUtilTest() {}
 
-  void SetUp() override {
-    ResetRegistryOverrides();
-  }
+  void SetUp() override { ASSERT_NO_FATAL_FAILURE(ResetRegistryOverrides()); }
 
   void ResetRegistryOverrides() {
     registry_override_manager_.reset(
         new registry_util::RegistryOverrideManager);
-    registry_override_manager_->OverrideRegistry(HKEY_CURRENT_USER);
-    registry_override_manager_->OverrideRegistry(HKEY_LOCAL_MACHINE);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_->OverrideRegistry(HKEY_CURRENT_USER));
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_->OverrideRegistry(HKEY_LOCAL_MACHINE));
   }
 
  private:
@@ -207,7 +207,7 @@
   const wchar_t value[] = L"hi mom";
 
   {
-    ResetRegistryOverrides();
+    ASSERT_NO_FATAL_FAILURE(ResetRegistryOverrides());
     // Nothing to delete if the key isn't even there.
     {
       MockRegistryValuePredicate pred;
@@ -270,7 +270,7 @@
   }
 
   {
-    ResetRegistryOverrides();
+    ASSERT_NO_FATAL_FAILURE(ResetRegistryOverrides());
     // Default value matches: delete using empty string.
     {
       MockRegistryValuePredicate pred;
@@ -290,7 +290,7 @@
   }
 
   {
-    ResetRegistryOverrides();
+    ASSERT_NO_FATAL_FAILURE(ResetRegistryOverrides());
     // Default value matches: delete using NULL.
     {
       MockRegistryValuePredicate pred;
diff --git a/chrome/installer/util/product_state_unittest.cc b/chrome/installer/util/product_state_unittest.cc
index 37fbc5d..1d07b51 100644
--- a/chrome/installer/util/product_state_unittest.cc
+++ b/chrome/installer/util/product_state_unittest.cc
@@ -19,6 +19,8 @@
  protected:
   ProductStateTest();
 
+  void SetUp() override;
+
   void ApplyUninstallCommand(const wchar_t* exe_path, const wchar_t* args);
   void MinimallyInstallProduct(const wchar_t* version);
 
@@ -31,14 +33,17 @@
 
 ProductStateTest::ProductStateTest()
     : system_install_(GetParam()),
-      overridden_(system_install_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER) {
-  registry_override_manager_.OverrideRegistry(overridden_);
+      overridden_(system_install_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER) {}
+
+void ProductStateTest::SetUp() {
+  ASSERT_NO_FATAL_FAILURE(
+      registry_override_manager_.OverrideRegistry(overridden_));
 
   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-  EXPECT_EQ(ERROR_SUCCESS,
+  ASSERT_EQ(ERROR_SUCCESS,
             clients_.Create(overridden_, dist->GetVersionKey().c_str(),
                             KEY_ALL_ACCESS | KEY_WOW64_32KEY));
-  EXPECT_EQ(ERROR_SUCCESS,
+  ASSERT_EQ(ERROR_SUCCESS,
             client_state_.Create(overridden_, dist->GetStateKey().c_str(),
                                  KEY_ALL_ACCESS | KEY_WOW64_32KEY));
 }
diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc
index 8302c47..8cf2b8b9 100644
--- a/chrome/installer/util/product_unittest.cc
+++ b/chrome/installer/util/product_unittest.cc
@@ -46,7 +46,7 @@
   HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
   {
     RegistryOverrideManager override_manager;
-    override_manager.OverrideRegistry(root);
+    ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(root));
 
     // There should be no installed version in the registry.
     machine_state.Initialize();
diff --git a/chrome/installer/util/scoped_user_protocol_entry_unittest.cc b/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
index b7e3eea1..2cef9eee 100644
--- a/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
+++ b/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
@@ -21,7 +21,8 @@
   static const wchar_t kProtocolEntryFakeValue[];
 
   void SetUp() override {
-    registry_overrides_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_overrides_manager_.OverrideRegistry(HKEY_CURRENT_USER));
     ASSERT_FALSE(RegistryEntry(kProtocolEntryKeyPath, kProtocolEntryName,
                                base::string16())
                      .KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU));
diff --git a/chrome/installer/util/set_reg_value_work_item_unittest.cc b/chrome/installer/util/set_reg_value_work_item_unittest.cc
index 598f49ce..10e5b69 100644
--- a/chrome/installer/util/set_reg_value_work_item_unittest.cc
+++ b/chrome/installer/util/set_reg_value_work_item_unittest.cc
@@ -34,7 +34,8 @@
   SetRegValueWorkItemTest() {}
 
   void SetUp() override {
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
 
     // Create a temporary key for testing.
     ASSERT_NE(ERROR_SUCCESS,
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index ec3bac5..9294208 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -816,7 +816,8 @@
 
  protected:
   void SetUp() override {
-    registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_overrides_.OverrideRegistry(HKEY_CURRENT_USER));
 
     // .test2 files already have a default application.
     base::win::RegKey key;
diff --git a/chrome/renderer/autofill/fake_content_password_manager_driver.cc b/chrome/renderer/autofill/fake_content_password_manager_driver.cc
index 01e700aa..30e61704 100644
--- a/chrome/renderer/autofill/fake_content_password_manager_driver.cc
+++ b/chrome/renderer/autofill/fake_content_password_manager_driver.cc
@@ -64,10 +64,6 @@
   called_show_not_secure_warning_ = true;
 }
 
-void FakeContentPasswordManagerDriver::PasswordAutofillAgentConstructed() {
-  called_agent_constructed_ = true;
-}
-
 void FakeContentPasswordManagerDriver::RecordSavePasswordProgress(
     const std::string& log) {
   called_record_save_progress_ = true;
diff --git a/chrome/renderer/autofill/fake_content_password_manager_driver.h b/chrome/renderer/autofill/fake_content_password_manager_driver.h
index 4388ecd..5aac096 100644
--- a/chrome/renderer/autofill/fake_content_password_manager_driver.h
+++ b/chrome/renderer/autofill/fake_content_password_manager_driver.h
@@ -82,8 +82,6 @@
     return called_record_save_progress_;
   }
 
-  bool called_agent_constructed() const { return called_agent_constructed_; }
-
   bool called_save_generation_field() const {
     return called_save_generation_field_;
   }
@@ -142,8 +140,6 @@
   void ShowNotSecureWarning(base::i18n::TextDirection text_direction,
                             const gfx::RectF& bounds) override;
 
-  void PasswordAutofillAgentConstructed() override;
-
   void RecordSavePasswordProgress(const std::string& log) override;
 
   void SaveGenerationFieldDetectedByClassifier(
@@ -172,8 +168,6 @@
   base::Optional<std::vector<autofill::PasswordForm>> password_forms_rendered_;
   // Records whether RecordSavePasswordProgress() gets called.
   bool called_record_save_progress_ = false;
-  // Records whether PasswordAutofillAgentConstructed() gets called.
-  bool called_agent_constructed_ = false;
   // Records whether SaveGenerationFieldDetectedByClassifier() gets called.
   bool called_save_generation_field_ = false;
   // Records data received via SaveGenerationFieldDetectedByClassifier() call.
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
index ae056a5c..aa0e1b4 100644
--- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -1299,13 +1299,6 @@
   EXPECT_FALSE(fake_driver_.called_record_save_progress());
 }
 
-// Test that the agent sends an IPC call to get the current activity state of
-// password saving logging soon after construction.
-TEST_F(PasswordAutofillAgentTest, SendsLoggingStateUpdatePingOnConstruction) {
-  base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(fake_driver_.called_agent_constructed());
-}
-
 // Tests that one user click on a username field is sufficient to bring up a
 // credential suggestion popup, and the user can autocomplete the password by
 // selecting the credential from the popup.
diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc
index 5692c0b9..5e3c48f 100644
--- a/chrome/renderer/chrome_render_view_observer.cc
+++ b/chrome/renderer/chrome_render_view_observer.cc
@@ -27,10 +27,12 @@
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
+#include "content/public/renderer/window_features_converter.h"
 #include "extensions/features/features.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebView.h"
+#include "third_party/WebKit/public/web/WebWindowFeatures.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/common/extensions/chrome_extension_messages.h"
@@ -134,8 +136,9 @@
 }
 
 void ChromeRenderViewObserver::OnSetWindowFeatures(
-    const WebWindowFeatures& window_features) {
-  render_view()->GetWebView()->setWindowFeatures(window_features);
+    const blink::mojom::WindowFeatures& window_features) {
+  render_view()->GetWebView()->setWindowFeatures(
+      content::ConvertMojoWindowFeaturesToWebWindowFeatures(window_features));
 }
 
 void ChromeRenderViewObserver::Navigate(const GURL& url) {
diff --git a/chrome/renderer/chrome_render_view_observer.h b/chrome/renderer/chrome_render_view_observer.h
index af5de50..f6473b0 100644
--- a/chrome/renderer/chrome_render_view_observer.h
+++ b/chrome/renderer/chrome_render_view_observer.h
@@ -15,12 +15,9 @@
 #include "content/public/common/browser_controls_state.h"
 #include "content/public/renderer/render_view_observer.h"
 #include "extensions/features/features.h"
+#include "third_party/WebKit/public/web/window_features.mojom.h"
 #include "url/gurl.h"
 
-namespace blink {
-struct WebWindowFeatures;
-}
-
 namespace web_cache {
 class WebCacheImpl;
 }
@@ -55,7 +52,7 @@
                                     bool animate);
 #endif
   void OnGetWebApplicationInfo();
-  void OnSetWindowFeatures(const blink::WebWindowFeatures& window_features);
+  void OnSetWindowFeatures(const blink::mojom::WindowFeatures& window_features);
 
   // Determines if a host is in the strict security host set.
   bool IsStrictSecurityHost(const std::string& host);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 21f00ab4..6c8d1ad 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2347,6 +2347,7 @@
         "../browser/extensions/api/vpn_provider/vpn_provider_apitest.cc",
         "../browser/ui/ash/launcher/arc_app_launcher_browsertest.cc",
         "../browser/ui/views/arc_app_dialog_view_browsertest.cc",
+        "../browser/ui/views/frame/browser_frame_ash_browsertest.cc",
         "../browser/ui/webui/options/chromeos/accounts_options_browsertest.cc",
         "../browser/ui/webui/options/chromeos/guest_mode_options_browsertest.cc",
         "../browser/ui/webui/options/chromeos/guest_mode_options_ui_browsertest.cc",
@@ -3241,6 +3242,7 @@
     "../browser/page_load_metrics/observers/protocol_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/resource_prefetch_predictor_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/service_worker_page_load_metrics_observer_unittest.cc",
+    "../browser/page_load_metrics/observers/subresource_filter_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc",
     "../browser/page_load_metrics/user_input_tracker_unittest.cc",
     "../browser/password_manager/chrome_password_manager_client_unittest.cc",
@@ -3775,7 +3777,6 @@
       "../browser/ui/autofill/country_combobox_model_unittest.cc",
       "../browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc",
       "../browser/ui/bluetooth/bluetooth_chooser_controller_unittest.cc",
-      "../browser/ui/desktop_ios_promotion/sms_service_unittest.cc",
       "../browser/ui/passwords/manage_passwords_ui_controller_unittest.cc",
     ]
     deps += [
@@ -3876,9 +3877,6 @@
       "../browser/extensions/api/experience_sampling_private/experience_sampling_private_api_unittest.cc",
       "../browser/extensions/api/extension_action/browser_action_unittest.cc",
       "../browser/extensions/api/extension_action/extension_action_prefs_unittest.cc",
-      "../browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc",
-      "../browser/extensions/api/file_handlers/directory_util_unittest.cc",
-      "../browser/extensions/api/file_handlers/mime_util_unittest.cc",
       "../browser/extensions/api/file_system/file_system_api_unittest.cc",
       "../browser/extensions/api/identity/extension_token_key_unittest.cc",
       "../browser/extensions/api/identity/gaia_web_auth_flow_unittest.cc",
@@ -4741,6 +4739,7 @@
     }
 
     sources += [
+      "../browser/ui/desktop_ios_promotion/sms_service_unittest.cc",
       "../browser/ui/input_method/input_method_engine_unittest.cc",
       "../test/data/resource.rc",
     ]
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index b66294a5..224d609 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -62,32 +62,29 @@
 namespace {
 
 const char* const kCommonSwitches[] = {
-  "disable-infobars",
-  "disable-popup-blocking",
-  "ignore-certificate-errors",
-  "metrics-recording-only",
+    "disable-popup-blocking", "enable-automation", "ignore-certificate-errors",
+    "metrics-recording-only",
 };
 
 const char* const kDesktopSwitches[] = {
-  "disable-hang-monitor",
-  "disable-prompt-on-repost",
-  "disable-sync",
-  "no-first-run",
-  "disable-background-networking",
-  "disable-web-resources",
-  "safebrowsing-disable-auto-update",
-  "disable-client-side-phishing-detection",
-  "disable-default-apps",
-  "enable-logging",
-  "log-level=0",
-  "password-store=basic",
-  "use-mock-keychain",
-  "test-type=webdriver",
+    "disable-hang-monitor",
+    "disable-prompt-on-repost",
+    "disable-sync",
+    "no-first-run",
+    "disable-background-networking",
+    "disable-web-resources",
+    "safebrowsing-disable-auto-update",
+    "disable-client-side-phishing-detection",
+    "disable-default-apps",
+    "enable-logging",
+    "log-level=0",
+    "password-store=basic",
+    "use-mock-keychain",
+    "test-type=webdriver",
 };
 
 const char* const kAndroidSwitches[] = {
-  "disable-fre",
-  "enable-remote-debugging",
+    "disable-fre", "enable-remote-debugging",
 };
 
 #if defined(OS_LINUX)
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 7622bb3..27c492c6 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -63,16 +63,16 @@
     'ChromeDriverAndroidTest.testMultipleScreenOrientationChanges',
     'ChromeDriverAndroidTest.testDeleteScreenOrientationManual',
     'ChromeDriverAndroidTest.testScreenOrientationAcrossMultipleTabs',
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1503
+    'ChromeDriverTest.testShadowDomHover',
+    'ChromeDriverTest.testMouseMoveTo',
+    'ChromeDriverTest.testHoverOverElement',
 ]
 
 _VERSION_SPECIFIC_FILTER = {}
 _VERSION_SPECIFIC_FILTER['HEAD'] = [
     # https://code.google.com/p/chromedriver/issues/detail?id=992
     'ChromeDownloadDirTest.testDownloadDirectoryOverridesExistingPreferences',
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1503
-    'ChromeDriverTest.testShadowDomHover',
-    'ChromeDriverTest.testMouseMoveTo',
-    'ChromeDriverTest.testHoverOverElement',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1625
     'ChromeDriverTest.testWindowMaximize',
     'ChromeDriverTest.testWindowPosition',
@@ -84,19 +84,9 @@
     'ChromeDownloadDirTest.testFileDownloadWithGet',
     'ChromeDriverPageLoadTimeoutTest.*',
 ]
-_VERSION_SPECIFIC_FILTER['55'] = [
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1503
-    'ChromeDriverTest.testShadowDomHover',
-    'ChromeDriverTest.testMouseMoveTo',
-    'ChromeDriverTest.testHoverOverElement',
-]
-_VERSION_SPECIFIC_FILTER['56'] = [
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1503
-    'ChromeDriverTest.testShadowDomHover',
-    'ChromeDriverTest.testMouseMoveTo',
-    'ChromeDriverTest.testHoverOverElement',
-]
 _VERSION_SPECIFIC_FILTER['57'] = [
+    # https://code.google.com/p/chromedriver/issues/detail?id=992
+    'ChromeDownloadDirTest.testDownloadDirectoryOverridesExistingPreferences',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1625
     'ChromeDriverTest.testWindowMaximize',
     'ChromeDriverTest.testWindowPosition',
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 4a23cbf7..1e15157a 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -106,11 +106,13 @@
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1674
     'WindowSwitchingTest.testShouldBeAbleToIterateOverAllOpenWindows',
 ]
-_REVISION_NEGATIVE_FILTER['57'] = [
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1625
-    'TakesScreenshotTest.*',
-    'WindowTest.*',
-]
+_REVISION_NEGATIVE_FILTER['57'] = (
+    _REVISION_NEGATIVE_FILTER['HEAD'] + [
+        # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1625
+        'TakesScreenshotTest.*',
+        'WindowTest.*',
+    ]
+)
 
 _OS_NEGATIVE_FILTER = {}
 _OS_NEGATIVE_FILTER['win'] = [
diff --git a/chrome/test/data/extensions/api_test/cast_channel/api/test_authority_keys.html b/chrome/test/data/extensions/api_test/cast_channel/api/test_authority_keys.html
deleted file mode 100644
index 27b59d83..0000000
--- a/chrome/test/data/extensions/api_test/cast_channel/api/test_authority_keys.html
+++ /dev/null
@@ -1 +0,0 @@
-<script src="test_authority_keys.js"></script>
diff --git a/chrome/test/data/extensions/api_test/cast_channel/api/test_authority_keys.js b/chrome/test/data/extensions/api_test/cast_channel/api/test_authority_keys.js
deleted file mode 100644
index 07f9a7f4..0000000
--- a/chrome/test/data/extensions/api_test/cast_channel/api/test_authority_keys.js
+++ /dev/null
@@ -1,170 +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.
-
-var VALID_SIGNATURE = [
-    0xA3, 0xCD, 0xE8, 0x92, 0xED, 0xE3, 0x3F, 0xEC, 0x63, 0x4F, 0x2B, 0x0D,
-    0x05, 0xA9, 0x6A, 0xA7, 0xF6, 0x5F, 0x25, 0x13, 0xCB, 0xB7, 0xC4, 0x7E,
-    0x21, 0x48, 0x59, 0x31, 0xEA, 0x5B, 0x01, 0x11, 0x52, 0x45, 0x58, 0xB3,
-    0x2E, 0x87, 0x85, 0x5B, 0x95, 0xF2, 0x53, 0x07, 0xBA, 0x95, 0x06, 0x82,
-    0xF8, 0xF1, 0x45, 0x40, 0x74, 0x99, 0x78, 0x66, 0x72, 0x79, 0xE1, 0x91,
-    0xA7, 0x00, 0x89, 0xFE, 0x57, 0x9F, 0xD3, 0x18, 0x7A, 0x49, 0x62, 0x65,
-    0x54, 0xC5, 0x8D, 0x4E, 0x4E, 0x7E, 0xCF, 0x45, 0x3C, 0xE0, 0x64, 0x1D,
-    0x8B, 0x32, 0x4F, 0xFC, 0x24, 0xC2, 0x78, 0x7A, 0x48, 0xC0, 0xCA, 0x1B,
-    0x37, 0xE9, 0x32, 0x0D, 0xA8, 0xE0, 0x3B, 0x27, 0xC3, 0x0C, 0xB8, 0x64,
-    0xB5, 0xCE, 0x8B, 0x1E, 0x64, 0xA5, 0x14, 0x61, 0xBA, 0x27, 0xB0, 0x7C,
-    0x5B, 0xAE, 0xE8, 0xCE, 0x24, 0xBC, 0x64, 0x51, 0x1D, 0xAD, 0xC4, 0xFD,
-    0x59, 0x25, 0xC5, 0xAE, 0x32, 0xD5, 0xC9, 0x44, 0x47, 0x8E, 0xF8, 0x9D,
-    0x64, 0x3E, 0x62, 0x16, 0xDB, 0x88, 0x98, 0x8E, 0xA4, 0xF5, 0x1F, 0x4E,
-    0xA1, 0x72, 0xD1, 0xE9, 0x2C, 0x80, 0xC2, 0x98, 0xDD, 0xAC, 0xBF, 0xAF,
-    0x94, 0x73, 0x24, 0xDC, 0x6A, 0x25, 0xE8, 0xA4, 0x3D, 0xF1, 0x8A, 0x45,
-    0xD2, 0x08, 0x47, 0x9C, 0xDD, 0xFF, 0x14, 0x55, 0xB8, 0x89, 0xBB, 0xC8,
-    0xC2, 0x39, 0x91, 0x6E, 0x9F, 0xAD, 0x51, 0x5D, 0xE1, 0xF1, 0x34, 0x5C,
-    0x08, 0xE8, 0xE5, 0x5D, 0x51, 0xA9, 0x6F, 0x33, 0xED, 0x35, 0x14, 0x65,
-    0x4E, 0xA7, 0xEF, 0xED, 0x1C, 0x66, 0xE5, 0x85, 0xE4, 0x64, 0xC2, 0xE6,
-    0x24, 0x93, 0x19, 0x89, 0x3B, 0x39, 0xFA, 0x8F, 0x05, 0x31, 0x13, 0x13,
-    0x41, 0x94, 0xF8, 0x85, 0x14, 0x77, 0x0D, 0x0F, 0x80, 0xFE, 0x3A, 0x1F,
-    0x56, 0x2C, 0x93, 0x18
-];
-
-var VALID_AUTHORITY_KEYS = [
-    0x0A, 0xB3, 0x02, 0x0A, 0x20, 0x52, 0x9D, 0x9C, 0xD6, 0x7F, 0xE5, 0xEB,
-    0x69, 0x8E, 0x70, 0xDD, 0x26, 0xD7, 0xD8, 0xF1, 0x26, 0x59, 0xF1, 0xE6,
-    0xE5, 0x23, 0x48, 0xBF, 0x6A, 0x5C, 0xF7, 0x16, 0xE1, 0x3F, 0x41, 0x0E,
-    0x73, 0x12, 0x8E, 0x02, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01,
-    0x00, 0xBC, 0x22, 0x80, 0xBD, 0x80, 0xF6, 0x3A, 0x21, 0x00, 0x3B, 0xAE,
-    0x76, 0x5E, 0x35, 0x7F, 0x3D, 0xC3, 0x64, 0x5C, 0x55, 0x94, 0x86, 0x34,
-    0x2F, 0x05, 0x87, 0x28, 0xCD, 0xF7, 0x69, 0x8C, 0x17, 0xB3, 0x50, 0xA7,
-    0xB8, 0x82, 0xFA, 0xDF, 0xC7, 0x43, 0x2D, 0xD6, 0x7E, 0xAB, 0xA0, 0x6F,
-    0xB7, 0x13, 0x72, 0x80, 0xA4, 0x47, 0x15, 0xC1, 0x20, 0x99, 0x50, 0xCD,
-    0xEC, 0x14, 0x62, 0x09, 0x5B, 0xA4, 0x98, 0xCD, 0xD2, 0x41, 0xB6, 0x36,
-    0x4E, 0xFF, 0xE8, 0x2E, 0x32, 0x30, 0x4A, 0x81, 0xA8, 0x42, 0xA3, 0x6C,
-    0x9B, 0x33, 0x6E, 0xCA, 0xB2, 0xF5, 0x53, 0x66, 0xE0, 0x27, 0x53, 0x86,
-    0x1A, 0x85, 0x1E, 0xA7, 0x39, 0x3F, 0x4A, 0x77, 0x8E, 0xFB, 0x54, 0x66,
-    0x66, 0xFB, 0x58, 0x54, 0xC0, 0x5E, 0x39, 0xC7, 0xF5, 0x50, 0x06, 0x0B,
-    0xE0, 0x8A, 0xD4, 0xCE, 0xE1, 0x6A, 0x55, 0x1F, 0x8B, 0x17, 0x00, 0xE6,
-    0x69, 0xA3, 0x27, 0xE6, 0x08, 0x25, 0x69, 0x3C, 0x12, 0x9D, 0x8D, 0x05,
-    0x2C, 0xD6, 0x2E, 0xA2, 0x31, 0xDE, 0xB4, 0x52, 0x50, 0xD6, 0x20, 0x49,
-    0xDE, 0x71, 0xA0, 0xF9, 0xAD, 0x20, 0x40, 0x12, 0xF1, 0xDD, 0x25, 0xEB,
-    0xD5, 0xE6, 0xB8, 0x36, 0xF4, 0xD6, 0x8F, 0x7F, 0xCA, 0x43, 0xDC, 0xD7,
-    0x10, 0x5B, 0xE6, 0x3F, 0x51, 0x8A, 0x85, 0xB3, 0xF3, 0xFF, 0xF6, 0x03,
-    0x2D, 0xCB, 0x23, 0x4F, 0x9C, 0xAD, 0x18, 0xE7, 0x93, 0x05, 0x8C, 0xAC,
-    0x52, 0x9A, 0xF7, 0x4C, 0xE9, 0x99, 0x7A, 0xBE, 0x6E, 0x7E, 0x4D, 0x0A,
-    0xE3, 0xC6, 0x1C, 0xA9, 0x93, 0xFA, 0x3A, 0xA5, 0x91, 0x5D, 0x1C, 0xBD,
-    0x66, 0xEB, 0xCC, 0x60, 0xDC, 0x86, 0x74, 0xCA, 0xCF, 0xF8, 0x92, 0x1C,
-    0x98, 0x7D, 0x57, 0xFA, 0x61, 0x47, 0x9E, 0xAB, 0x80, 0xB7, 0xE4, 0x48,
-    0x80, 0x2A, 0x92, 0xC5, 0x1B, 0x02, 0x03, 0x01, 0x00, 0x01, 0x0A, 0xB3,
-    0x02, 0x0A, 0x20, 0xA2, 0x48, 0xC2, 0xE8, 0x54, 0xE6, 0x56, 0xA5, 0x6D,
-    0xE8, 0x23, 0x1F, 0x1E, 0xE1, 0x75, 0x6F, 0xDB, 0xE4, 0x07, 0xF9, 0xFE,
-    0xD4, 0x65, 0x0D, 0x60, 0xCC, 0x5A, 0xCB, 0x65, 0x11, 0xC7, 0x20, 0x12,
-    0x8E, 0x02, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB0,
-    0x0E, 0x5E, 0x07, 0x3A, 0xDF, 0xA4, 0x5F, 0x68, 0xF7, 0x21, 0xC7, 0x64,
-    0xDB, 0xB6, 0x76, 0xEF, 0xEE, 0x8B, 0x93, 0xF8, 0xF6, 0x1B, 0x88, 0xE1,
-    0x93, 0xB7, 0x17, 0xF0, 0x15, 0x1E, 0x7E, 0x52, 0x55, 0x77, 0x3C, 0x02,
-    0x8D, 0x7B, 0x4A, 0x6C, 0xD3, 0xBD, 0xD6, 0xC1, 0x9C, 0x72, 0xC8, 0xB3,
-    0x15, 0xCF, 0x11, 0xC1, 0xF5, 0x46, 0xC4, 0xD5, 0x20, 0x47, 0xFB, 0x30,
-    0xF4, 0xE4, 0x61, 0x0C, 0x68, 0xF0, 0x5E, 0xAB, 0x37, 0x8E, 0x9B, 0xE1,
-    0xBC, 0x81, 0xC3, 0x70, 0x8A, 0x78, 0xD6, 0x83, 0x34, 0x32, 0x9C, 0x19,
-    0x62, 0xEB, 0xE4, 0x9C, 0xED, 0xE3, 0x64, 0x6C, 0x41, 0x1D, 0x9C, 0xD2,
-    0x8B, 0x48, 0x4C, 0x23, 0x90, 0x95, 0xB3, 0xE7, 0x52, 0xEA, 0x05, 0x57,
-    0xCC, 0x60, 0xB3, 0xBA, 0x14, 0xE4, 0xBA, 0x00, 0x39, 0xE4, 0x46, 0x55,
-    0x74, 0xCE, 0x5A, 0x8E, 0x7A, 0x67, 0x23, 0xDA, 0x68, 0x0A, 0xFA, 0xC4,
-    0x84, 0x1E, 0xB4, 0xC5, 0xA1, 0xA2, 0x6A, 0x73, 0x1F, 0x6E, 0xC8, 0x2E,
-    0x2F, 0x9A, 0x9E, 0xA8, 0xB1, 0x0E, 0xFD, 0x87, 0xA6, 0x8F, 0x4D, 0x3D,
-    0x4B, 0x05, 0xD5, 0x35, 0x5A, 0x74, 0x4D, 0xBC, 0x8E, 0x82, 0x44, 0x96,
-    0xF4, 0xB5, 0x95, 0x60, 0x4E, 0xA5, 0xDF, 0x27, 0x3D, 0x41, 0x5C, 0x07,
-    0xA3, 0xB4, 0x35, 0x5A, 0xB3, 0x9E, 0xF2, 0x05, 0x24, 0xCA, 0xCD, 0x31,
-    0x5A, 0x0D, 0x26, 0x4C, 0xD4, 0xD3, 0xFD, 0x50, 0xE1, 0x34, 0xE9, 0x4C,
-    0x81, 0x58, 0x30, 0xB2, 0xC7, 0x7A, 0xDD, 0x81, 0x89, 0xA6, 0xD4, 0x3A,
-    0x38, 0x84, 0x03, 0xB7, 0x34, 0x9E, 0x77, 0x3F, 0xFF, 0x78, 0x07, 0x5B,
-    0x99, 0xC1, 0xB2, 0x1F, 0x35, 0x56, 0x6E, 0x3A, 0x3C, 0x0C, 0x25, 0xE1,
-    0x57, 0xF6, 0x8A, 0x7E, 0x49, 0xC0, 0xCC, 0x83, 0x11, 0x35, 0xE7, 0x91,
-    0x6D, 0x2E, 0x65, 0x02, 0x03, 0x01, 0x00, 0x01
-];
-
-var INVALID_AUTHORITY_KEYS = [
-    0x10, 0xB3, 0x02, 0x0A, 0x20, 0x52, 0x9D, 0x9C, 0xD6, 0x7F, 0xE5, 0xEB,
-    0x69, 0x8E, 0x70, 0xDD, 0x26, 0xD7, 0xD8, 0xF1, 0x26, 0x59, 0xF1, 0xE6,
-    0xE5, 0x23, 0x48, 0xBF, 0x6A, 0x5C, 0xF7, 0x16, 0xE1, 0x3F, 0x41, 0x0E,
-    0x73, 0x12, 0x8E, 0x02, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01,
-    0x00, 0xBC, 0x22, 0x80, 0xBD, 0x80, 0xF6, 0x3A, 0x21, 0x00, 0x3B, 0xAE,
-    0x76, 0x5E, 0x35, 0x7F, 0x3D, 0xC3, 0x64, 0x5C, 0x55, 0x94, 0x86, 0x34,
-    0x2F, 0x05, 0x87, 0x28, 0xCD, 0xF7, 0x69, 0x8C, 0x17, 0xB3, 0x50, 0xA7,
-    0xB8, 0x82, 0xFA, 0xDF, 0xC7, 0x43, 0x2D, 0xD6, 0x7E, 0xAB, 0xA0, 0x6F,
-    0xB7, 0x13, 0x72, 0x80, 0xA4, 0x47, 0x15, 0xC1, 0x20, 0x99, 0x50, 0xCD,
-    0xEC, 0x14, 0x62, 0x09, 0x5B, 0xA4, 0x98, 0xCD, 0xD2, 0x41, 0xB6, 0x36,
-    0x4E, 0xFF, 0xE8, 0x2E, 0x32, 0x30, 0x4A, 0x81, 0xA8, 0x42, 0xA3, 0x6C,
-    0x9B, 0x33, 0x6E, 0xCA, 0xB2, 0xF5, 0x53, 0x66, 0xE0, 0x27, 0x53, 0x86,
-    0x1A, 0x85, 0x1E, 0xA7, 0x39, 0x3F, 0x4A, 0x77, 0x8E, 0xFB, 0x54, 0x66,
-    0x66, 0xFB, 0x58, 0x54, 0xC0, 0x5E, 0x39, 0xC7, 0xF5, 0x50, 0x06, 0x0B,
-    0xE0, 0x8A, 0xD4, 0xCE, 0xE1, 0x6A, 0x55, 0x1F, 0x8B, 0x17, 0x00, 0xE6,
-    0x69, 0xA3, 0x27, 0xE6, 0x08, 0x25, 0x69, 0x3C, 0x12, 0x9D, 0x8D, 0x05,
-    0x2C, 0xD6, 0x2E, 0xA2, 0x31, 0xDE, 0xB4, 0x52, 0x50, 0xD6, 0x20, 0x49,
-    0xDE, 0x71, 0xA0, 0xF9, 0xAD, 0x20, 0x40, 0x12, 0xF1, 0xDD, 0x25, 0xEB,
-    0xD5, 0xE6, 0xB8, 0x36, 0xF4, 0xD6, 0x8F, 0x7F, 0xCA, 0x43, 0xDC, 0xD7,
-    0x10, 0x5B, 0xE6, 0x3F, 0x51, 0x8A, 0x85, 0xB3, 0xF3, 0xFF, 0xF6, 0x03,
-    0x2D, 0xCB, 0x23, 0x4F, 0x9C, 0xAD, 0x18, 0xE7, 0x93, 0x05, 0x8C, 0xAC,
-    0x52, 0x9A, 0xF7, 0x4C, 0xE9, 0x99, 0x7A, 0xBE, 0x6E, 0x7E, 0x4D, 0x0A,
-    0xE3, 0xC6, 0x1C, 0xA9, 0x93, 0xFA, 0x3A, 0xA5, 0x91, 0x5D, 0x1C, 0xBD,
-    0x66, 0xEB, 0xCC, 0x60, 0xDC, 0x86, 0x74, 0xCA, 0xCF, 0xF8, 0x92, 0x1C,
-    0x98, 0x7D, 0x57, 0xFA, 0x61, 0x47, 0x9E, 0xAB, 0x80, 0xB7, 0xE4, 0x48,
-    0x80, 0x2A, 0x92, 0xC5, 0x1B, 0x02, 0x03, 0x01, 0x00, 0x01, 0x0A, 0xB3,
-    0x02, 0x0A, 0x20, 0xA2, 0x48, 0xC2, 0xE8, 0x54, 0xE6, 0x56, 0xA5, 0x6D,
-    0xE8, 0x23, 0x1F, 0x1E, 0xE1, 0x75, 0x6F, 0xDB, 0xE4, 0x07, 0xF9, 0xFE,
-    0xD4, 0x65, 0x0D, 0x60, 0xCC, 0x5A, 0xCB, 0x65, 0x11, 0xC7, 0x20, 0x12,
-    0x8E, 0x02, 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 0x00, 0xB0,
-    0x0E, 0x5E, 0x07, 0x3A, 0xDF, 0xA4, 0x5F, 0x68, 0xF7, 0x21, 0xC7, 0x64,
-    0xDB, 0xB6, 0x76, 0xEF, 0xEE, 0x8B, 0x93, 0xF8, 0xF6, 0x1B, 0x88, 0xE1,
-    0x93, 0xB7, 0x17, 0xF0, 0x15, 0x1E, 0x7E, 0x52, 0x55, 0x77, 0x3C, 0x02,
-    0x8D, 0x7B, 0x4A, 0x6C, 0xD3, 0xBD, 0xD6, 0xC1, 0x9C, 0x72, 0xC8, 0xB3,
-    0x15, 0xCF, 0x11, 0xC1, 0xF5, 0x46, 0xC4, 0xD5, 0x20, 0x47, 0xFB, 0x30,
-    0xF4, 0xE4, 0x61, 0x0C, 0x68, 0xF0, 0x5E, 0xAB, 0x37, 0x8E, 0x9B, 0xE1,
-    0xBC, 0x81, 0xC3, 0x70, 0x8A, 0x78, 0xD6, 0x83, 0x34, 0x32, 0x9C, 0x19,
-    0x62, 0xEB, 0xE4, 0x9C, 0xED, 0xE3, 0x64, 0x6C, 0x41, 0x1D, 0x9C, 0xD2,
-    0x8B, 0x48, 0x4C, 0x23, 0x90, 0x95, 0xB3, 0xE7, 0x52, 0xEA, 0x05, 0x57,
-    0xCC, 0x60, 0xB3, 0xBA, 0x14, 0xE4, 0xBA, 0x00, 0x39, 0xE4, 0x46, 0x55,
-    0x74, 0xCE, 0x5A, 0x8E, 0x7A, 0x67, 0x23, 0xDA, 0x68, 0x0A, 0xFA, 0xC4,
-    0x84, 0x1E, 0xB4, 0xC5, 0xA1, 0xA2, 0x6A, 0x73, 0x1F, 0x6E, 0xC8, 0x2E,
-    0x2F, 0x9A, 0x9E, 0xA8, 0xB1, 0x0E, 0xFD, 0x87, 0xA6, 0x8F, 0x4D, 0x3D,
-    0x4B, 0x05, 0xD5, 0x35, 0x5A, 0x74, 0x4D, 0xBC, 0x8E, 0x82, 0x44, 0x96,
-    0xF4, 0xB5, 0x95, 0x60, 0x4E, 0xA5, 0xDF, 0x27, 0x3D, 0x41, 0x5C, 0x07,
-    0xA3, 0xB4, 0x35, 0x5A, 0xB3, 0x9E, 0xF2, 0x05, 0x24, 0xCA, 0xCD, 0x31,
-    0x5A, 0x0D, 0x26, 0x4C, 0xD4, 0xD3, 0xFD, 0x50, 0xE1, 0x34, 0xE9, 0x4C,
-    0x81, 0x58, 0x30, 0xB2, 0xC7, 0x7A, 0xDD, 0x81, 0x89, 0xA6, 0xD4, 0x3A,
-    0x38, 0x84, 0x03, 0xB7, 0x34, 0x9E, 0x77, 0x3F, 0xFF, 0x78, 0x07, 0x5B,
-    0x99, 0xC1, 0xB2, 0x1F, 0x35, 0x56, 0x6E, 0x3A, 0x3C, 0x0C, 0x25, 0xE1,
-    0x57, 0xF6, 0x8A, 0x7E, 0x49, 0xC0, 0xCC, 0x83, 0x11, 0x35, 0xE7, 0x91,
-    0x6D, 0x2E, 0x65, 0x02, 0x03, 0x01, 0x00, 0x01
-];
-
-var generateBase64Data = function(s) {
-  return window.btoa(String.fromCharCode.apply(null, s));
-};
-
-var onInvalidAuthorityKeys = function() {
-  chrome.test.assertLastError('Unable to set authority keys.');
-  chrome.test.succeed();
-};
-
-var onValidAuthorityKeys = function() {
-  chrome.test.assertNoLastError();
-  chrome.test.succeed();
-};
-
-chrome.test.runTests([
-  function testValid() {
-    chrome.cast.channel.setAuthorityKeys(
-        generateBase64Data(VALID_AUTHORITY_KEYS),
-        generateBase64Data(VALID_SIGNATURE), onValidAuthorityKeys);
-  },
-  function testInvalid() {
-    chrome.cast.channel.setAuthorityKeys(
-        generateBase64Data(INVALID_AUTHORITY_KEYS),
-        // TODO(eroman): crbug.com/601171: Remove this entire test once
-        // chrome.cast.channel.setAuthorityKeys() is removed.
-        //
-        // For now the test has been modified so that even passing
-        // invalid keys is successful, as the API is deprecated.
-        generateBase64Data(VALID_SIGNATURE), onValidAuthorityKeys);
-  }
-]);
diff --git a/chrome/test/data/extensions/api_test/cast_channel/api/test_get_logs.html b/chrome/test/data/extensions/api_test/cast_channel/api/test_get_logs.html
deleted file mode 100644
index f7e005f1..0000000
--- a/chrome/test/data/extensions/api_test/cast_channel/api/test_get_logs.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<script src="common.js"></script>
-<script src="test_get_logs.js"></script>
diff --git a/chrome/test/data/extensions/api_test/cast_channel/api/test_get_logs.js b/chrome/test/data/extensions/api_test/cast_channel/api/test_get_logs.js
deleted file mode 100644
index 315029b..0000000
--- a/chrome/test/data/extensions/api_test/cast_channel/api/test_get_logs.js
+++ /dev/null
@@ -1,36 +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.
-
-var message = {
-  'namespace_': 'foo',
-  'sourceId': 'src',
-  'destinationId': 'dest',
-  'data': 'some-string'
-};
-
-var onGetLogs = function(blob) {
-  chrome.test.assertTrue(blob.byteLength > 0);
-  chrome.test.succeed();
-}
-
-var onClose = function(channel) {
-  assertClosedChannel(channel);
-  chrome.cast.channel.getLogs(onGetLogs);
-};
-
-var onSend = function(channel) {
-  assertOpenChannel(channel);
-  chrome.cast.channel.close(channel, onClose);
-};
-
-var onOpen = function(channel) {
-  assertOpenChannel(channel);
-  chrome.cast.channel.send(channel, message, onSend);
-};
-
-chrome.cast.channel.open({
-  ipAddress: '192.168.1.1',
-  port: 8009,
-  auth: 'ssl_verified'
-}, onOpen);
diff --git a/chrome/test/data/extensions/api_test/native_bindings/extension/background.js b/chrome/test/data/extensions/api_test/native_bindings/extension/background.js
index 7cfaa0fc..e1375f0 100644
--- a/chrome/test/data/extensions/api_test/native_bindings/extension/background.js
+++ b/chrome/test/data/extensions/api_test/native_bindings/extension/background.js
@@ -115,6 +115,12 @@
       });
     });
   },
+  function testLastError() {
+    chrome.runtime.setUninstallURL('chrome://newtab', function() {
+      chrome.test.assertLastError('Invalid URL: "chrome://newtab".');
+      chrome.test.succeed();
+    });
+  },
 ];
 
 chrome.test.getConfig(config => {
diff --git a/chrome/test/data/gpu/feature_compositing_static.html b/chrome/test/data/gpu/feature_compositing_static.html
index cb02f887..260fd6d8 100644
--- a/chrome/test/data/gpu/feature_compositing_static.html
+++ b/chrome/test/data/gpu/feature_compositing_static.html
@@ -5,7 +5,7 @@
 <title>GPU Feature Testing: Accelerated Compositing</title>
 <style>
 body {
-  -webkit-transform: translateZ(0);
+  transform: translateZ(0);
 }
 </style>
 </head>
diff --git a/chrome/test/data/gpu/feature_raf_no_damage.html b/chrome/test/data/gpu/feature_raf_no_damage.html
index 496ac10..02dbcc9e 100644
--- a/chrome/test/data/gpu/feature_raf_no_damage.html
+++ b/chrome/test/data/gpu/feature_raf_no_damage.html
@@ -5,7 +5,7 @@
 <title>GPU Feature Testing: Accelerated Compositing No Damage</title>
 <style>
 body {
-  -webkit-transform: translateZ(0);
+  transform: translateZ(0);
 }
 </style>
 <script>
diff --git a/chrome/test/data/navigation_interception/navigation_from_image_onload.html b/chrome/test/data/navigation_interception/navigation_from_image_onload.html
index 90c78b0..bbf3e12 100644
--- a/chrome/test/data/navigation_interception/navigation_from_image_onload.html
+++ b/chrome/test/data/navigation_interception/navigation_from_image_onload.html
@@ -17,7 +17,7 @@
       top: 0px;
       left: 0px;
       background-color: green;
-      -webkit-transform: translate3d(0, 0, 0);
+      transform: translate3d(0, 0, 0);
     }
   </style>
   <script>
diff --git a/chrome/test/data/navigation_interception/navigation_from_user_gesture.html b/chrome/test/data/navigation_interception/navigation_from_user_gesture.html
index 4d5a44d3..0170559 100644
--- a/chrome/test/data/navigation_interception/navigation_from_user_gesture.html
+++ b/chrome/test/data/navigation_interception/navigation_from_user_gesture.html
@@ -17,7 +17,7 @@
       top: 0px;
       left: 0px;
       background-color: green;
-      -webkit-transform: translate3d(0, 0, 0);
+      transform: translate3d(0, 0, 0);
     }
   </style>
   <script>
diff --git a/chrome/test/data/navigation_interception/navigation_from_user_gesture_to_iframe_page.html b/chrome/test/data/navigation_interception/navigation_from_user_gesture_to_iframe_page.html
index 02fefae..3414caf 100644
--- a/chrome/test/data/navigation_interception/navigation_from_user_gesture_to_iframe_page.html
+++ b/chrome/test/data/navigation_interception/navigation_from_user_gesture_to_iframe_page.html
@@ -17,7 +17,7 @@
       top: 0px;
       left: 0px;
       background-color: green;
-      -webkit-transform: translate3d(0, 0, 0);
+      transform: translate3d(0, 0, 0);
     }
   </style>
   <script>
diff --git a/chrome/test/data/navigation_interception/navigation_from_xhr_callback.html b/chrome/test/data/navigation_interception/navigation_from_xhr_callback.html
index a40cab8f..afbba53e 100644
--- a/chrome/test/data/navigation_interception/navigation_from_xhr_callback.html
+++ b/chrome/test/data/navigation_interception/navigation_from_xhr_callback.html
@@ -17,7 +17,7 @@
       top: 0px;
       left: 0px;
       background-color: green;
-      -webkit-transform: translate3d(0, 0, 0);
+      transform: translate3d(0, 0, 0);
     }
   </style>
   <script>
diff --git a/chrome/test/data/navigation_interception/navigation_from_xhr_callback_and_long_timeout.html b/chrome/test/data/navigation_interception/navigation_from_xhr_callback_and_long_timeout.html
index a1196aa..2aacd116 100644
--- a/chrome/test/data/navigation_interception/navigation_from_xhr_callback_and_long_timeout.html
+++ b/chrome/test/data/navigation_interception/navigation_from_xhr_callback_and_long_timeout.html
@@ -17,7 +17,7 @@
       top: 0px;
       left: 0px;
       background-color: green;
-      -webkit-transform: translate3d(0, 0, 0);
+      transform: translate3d(0, 0, 0);
     }
   </style>
   <script>
diff --git a/chrome/test/data/navigation_interception/navigation_from_xhr_callback_and_short_timeout.html b/chrome/test/data/navigation_interception/navigation_from_xhr_callback_and_short_timeout.html
index c3aacfc..1e90e23 100644
--- a/chrome/test/data/navigation_interception/navigation_from_xhr_callback_and_short_timeout.html
+++ b/chrome/test/data/navigation_interception/navigation_from_xhr_callback_and_short_timeout.html
@@ -17,7 +17,7 @@
       top: 0px;
       left: 0px;
       background-color: green;
-      -webkit-transform: translate3d(0, 0, 0);
+      transform: translate3d(0, 0, 0);
     }
   </style>
   <script>
diff --git a/chrome/test/data/perf/frame_rate/head.js b/chrome/test/data/perf/frame_rate/head.js
index 9c22c7a..cde54ec 100644
--- a/chrome/test/data/perf/frame_rate/head.js
+++ b/chrome/test/data/perf/frame_rate/head.js
@@ -414,7 +414,7 @@
 }
 
 function __make_body_composited() {
-  document.body.style.webkitTransform = "translateZ(0)";
+  document.body.style.transform = "translateZ(0)";
 }
 
 function __start(gesture_function) {
@@ -491,5 +491,5 @@
 }
 
 function __force_compositor() {
-  document.body.style.webkitTransform = "translateZ(0)";
+  document.body.style.transform = "translateZ(0)";
 }
diff --git a/chrome/test/data/webui/md_history/history_grouped_list_test.js b/chrome/test/data/webui/md_history/history_grouped_list_test.js
deleted file mode 100644
index 94db8c2..0000000
--- a/chrome/test/data/webui/md_history/history_grouped_list_test.js
+++ /dev/null
@@ -1,313 +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.
-
-suite('history-grouped-list', function() {
-  var app;
-  var toolbar;
-  var groupedList;
-  var sidebar;
-  var listContainer;
-
-  var SIMPLE_RESULTS;
-  var PER_DAY_RESULTS;
-  var PER_MONTH_RESULTS;
-
-  suiteSetup(function() {
-    SIMPLE_RESULTS = [
-      createHistoryEntry('2016-03-16', 'https://www.google.com/'),
-      createHistoryEntry('2016-03-16', 'https://en.wikipedia.org/DankMeme'),
-      createHistoryEntry('2016-03-16 10:00', 'https://www.example.com'),
-      createHistoryEntry(
-          '2016-03-16', 'https://www.google.com/?q=yoloswaggins'),
-    ];
-
-    PER_DAY_RESULTS = [
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org'),
-      createHistoryEntry('2016-03-13', 'https://www.youtube.com'),
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org'),
-      createHistoryEntry('2016-03-11', 'https://en.wikipedia.org'),
-      createHistoryEntry('2016-03-10', 'https://en.wikipedia.org')
-    ];
-
-    PER_MONTH_RESULTS = [
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org'),
-      createHistoryEntry('2016-03-13', 'https://www.youtube.com'),
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org'),
-      createHistoryEntry('2016-03-1', 'https://en.wikipedia.org'),
-      createHistoryEntry('2016-03-1', 'https://en.wikipedia.org')
-    ];
-  });
-
-  setup(function() {
-    app = replaceApp();
-    app.grouped_ = true;
-
-    listContainer = app.$['history'];
-    toolbar = app.$['toolbar'];
-    sidebar = app.$['content-side-bar'];
-    return PolymerTest.flushTasks().then(function() {
-      groupedList = app.$.history.$$('#grouped-list');
-      assertTrue(!!groupedList);
-    });
-  });
-
-  test('grouped ui is shown', function() {
-    assertEquals('history', sidebar.$.menu.selected);
-    assertTrue(!!toolbar.$$('#grouped-buttons-container'));
-
-    var content = app.$['history'].$['content'];
-
-    // History list is shown at first.
-    assertEquals('infinite-list', content.selected);
-
-    // Switching to week or month causes grouped history list to be shown.
-    app.fire('change-query', {range: HistoryRange.WEEK});
-    assertEquals('grouped-list', content.selected);
-    assertEquals('history', sidebar.$.menu.selected);
-
-    app.fire('change-query', {range: HistoryRange.ALL_TIME});
-    assertEquals('infinite-list', content.selected);
-    assertEquals('history', sidebar.$.menu.selected);
-
-    app.fire('change-query', {range: HistoryRange.MONTH});
-    assertEquals('grouped-list', content.selected);
-    assertEquals('history', sidebar.$.menu.selected);
-  });
-
-  test('items grouped by domain', function() {
-    app.fire('change-query', {range: HistoryRange.WEEK});
-    var info = createHistoryInfo();
-    app.historyResult(info, SIMPLE_RESULTS);
-    return PolymerTest.flushTasks().then(function() {
-      var data = groupedList.groupedHistoryData_;
-      // 1 card for the day with 3 domains.
-      assertEquals(1, data.length);
-      assertEquals(3, data[0].domains.length);
-
-      // Most visits at the top.
-      assertEquals(2, data[0].domains[0].visits.length);
-      assertEquals(1, data[0].domains[1].visits.length);
-      assertEquals(1, data[0].domains[2].visits.length);
-    });
-  });
-
-  test('toolbar dates appear in grouped mode', function() {
-    var getInfo = function() {
-      var info = createHistoryInfo();
-      info.queryStartMonth = 'Dec 2016';
-      info.queryInterval = 'Yesterday - Now';
-      return info;
-    };
-    app.set('queryState_.range', HistoryRange.MONTH);
-    app.historyResult(getInfo(), SIMPLE_RESULTS);
-    assertEquals(
-        'Dec 2016', toolbar.$$('#grouped-date').textContent.trim());
-
-    app.set('queryState_.range', HistoryRange.WEEK);
-    app.historyResult(getInfo(), SIMPLE_RESULTS);
-    assertEquals(
-        'Yesterday - Now', toolbar.$$('#grouped-date').textContent.trim());
-  });
-
-  test('items grouped by day in week view', function() {
-    app.fire('change-query', {range: HistoryRange.WEEK});
-    app.historyResult(createHistoryInfo(), PER_DAY_RESULTS);
-    return PolymerTest.flushTasks().then(function() {
-      var data = groupedList.groupedHistoryData_;
-
-      // 3 cards.
-      assertEquals(3, data.length);
-
-      assertEquals(2, data[0].domains.length);
-      assertEquals(2, data[0].domains[0].visits.length);
-      assertEquals(1, data[0].domains[1].visits.length);
-
-      assertEquals(1, data[1].domains.length);
-      assertEquals(1, data[1].domains[0].visits.length);
-
-      assertEquals(1, data[2].domains.length);
-      assertEquals(1, data[2].domains[0].visits.length);
-    });
-  });
-
-  test('items grouped by month in month view', function() {
-    app.fire('change-query', {range: HistoryRange.MONTH});
-    app.historyResult(createHistoryInfo(), PER_MONTH_RESULTS);
-    return PolymerTest.flushTasks().then(function() {
-      var data = groupedList.groupedHistoryData_;
-
-      // 1 card.
-      assertEquals(1, data.length);
-
-      assertEquals(2, data[0].domains.length);
-      assertEquals(4, data[0].domains[0].visits.length);
-      assertEquals(1, data[0].domains[1].visits.length);
-    });
-  });
-
-  test('items rendered when expanded', function() {
-    app.fire('change-query', {range: HistoryRange.WEEK});
-    app.historyResult(createHistoryInfo(), SIMPLE_RESULTS);
-
-    return PolymerTest.flushTasks().then(function() {
-      assertEquals(0, polymerSelectAll(groupedList, 'history-item').length);
-      MockInteractions.tap(groupedList.$$('.domain-heading'));
-      return PolymerTest.flushTasks();
-    }).then(function() {
-      assertEquals(2, polymerSelectAll(groupedList, 'history-item').length);
-    });
-  });
-
-  test('shift selection in week view', function() {
-    var results = [
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org/a'),
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org/b'),
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org/c'),
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org/d'),
-      createHistoryEntry('2016-03-13', 'https://www.youtube.com/a'),
-      createHistoryEntry('2016-03-13', 'https://www.youtube.com/b'),
-      createHistoryEntry('2016-03-11', 'https://en.wikipedia.org'),
-      createHistoryEntry('2016-03-10', 'https://www.youtube.com')
-    ];
-    app.fire('change-query', {range: HistoryRange.WEEK});
-    app.historyResult(createHistoryInfo(), results);
-
-    return waitForEvent(groupedList, 'dom-change', function() {
-      return polymerSelectAll(groupedList, '.dropdown-indicator').length == 4;
-    }).then(function() {
-      polymerSelectAll(groupedList, '.dropdown-indicator').
-          forEach(MockInteractions.tap);
-
-      return PolymerTest.flushTasks();
-    }).then(function() {
-      var items = polymerSelectAll(groupedList, 'history-item');
-
-      MockInteractions.tap(items[0].$.checkbox);
-      assertDeepEquals(
-          [true, false, false, false],
-          groupedList.groupedHistoryData_[0].domains[0].visits.map(
-              i => i.selected));
-
-      // Shift-select to the third item.
-      shiftClick(items[2].$.checkbox);
-      assertDeepEquals(
-          [true, true, true, false],
-          groupedList.groupedHistoryData_[0].domains[0].visits.map(
-              i => i.selected));
-
-      // Shift-selecting to another domain selects as per usual.
-      shiftClick(items[5].$.checkbox);
-      assertDeepEquals(
-          [true, true, true, false],
-          groupedList.groupedHistoryData_[0].domains[0].visits.map(
-              i => i.selected));
-      assertDeepEquals(
-          [false, true],
-          groupedList.groupedHistoryData_[0].domains[1].visits.map(
-              i => i.selected));
-    });
-  });
-
-  test('items deletion in week view', function(done) {
-    var results = [
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org/a'),
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org/b'),
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org/c'),
-      createHistoryEntry('2016-03-13', 'https://en.wikipedia.org/d'),
-      createHistoryEntry('2016-03-13', 'https://www.youtube.com/a'),
-      createHistoryEntry('2016-03-13', 'https://www.youtube.com/b'),
-      createHistoryEntry('2016-03-11', 'https://en.wikipedia.org'),
-      createHistoryEntry('2016-03-10', 'https://www.youtube.com')
-    ];
-    app.fire('change-query', {range: HistoryRange.WEEK});
-    app.historyResult(createHistoryInfo(), results);
-
-    waitForEvent(groupedList, 'dom-change', function() {
-      return polymerSelectAll(groupedList, '.dropdown-indicator').length == 4;
-    }).then(function() {
-      polymerSelectAll(groupedList, '.dropdown-indicator').
-          forEach(MockInteractions.tap);
-
-      return PolymerTest.flushTasks();
-    }).then(function() {
-      var items = polymerSelectAll(groupedList, 'history-item');
-
-      MockInteractions.tap(items[0].$.checkbox);
-      MockInteractions.tap(items[2].$.checkbox);
-      MockInteractions.tap(items[4].$.checkbox);
-      MockInteractions.tap(items[5].$.checkbox);
-      MockInteractions.tap(items[6].$.checkbox);
-      MockInteractions.tap(items[7].$.checkbox);
-
-      // Select and deselect item 1.
-      MockInteractions.tap(items[1].$.checkbox);
-      MockInteractions.tap(items[1].$.checkbox);
-
-      return PolymerTest.flushTasks();
-    }).then(function() {
-      MockInteractions.tap(app.$.toolbar.$$('#delete-button'));
-      var dialog = listContainer.$.dialog.get();
-
-      registerMessageCallback('removeVisits', this, function() {
-        PolymerTest.flushTasks().then(function() {
-          deleteComplete();
-          return waitForEvent(groupedList, 'dom-change', function() {
-            return polymerSelectAll(
-                groupedList, '.dropdown-indicator').length == 1;
-          });
-        }).then(function() {
-          items = polymerSelectAll(groupedList, 'history-item');
-          assertEquals(2, items.length);
-          assertEquals('https://en.wikipedia.org/b', items[0].item.title);
-          assertEquals('https://en.wikipedia.org/d', items[1].item.title);
-          assertEquals(
-              1, polymerSelectAll(groupedList, '.domain-heading').length);
-
-          assertEquals(
-              1, polymerSelectAll(groupedList, '.group-container').length);
-
-          assertFalse(dialog.open);
-          done();
-        });
-      });
-      // Confirmation dialog should appear.
-      assertTrue(dialog.open);
-
-      MockInteractions.tap(listContainer.$$('.action-button'));
-    });
-  });
-
-  test('build removal tree', function() {
-    var paths = [
-      'a.0.b.1',
-      'a.0.b.3',
-      'a.2.b.3',
-    ];
-
-    var expected = {
-      currentPath: 'a',
-      leaf: false,
-      indexes: [0, 2],
-      children: [
-        {
-          currentPath: 'a.0.b',
-          leaf: true,
-          indexes: [1, 3],
-          children: [],
-        },
-        null,
-        {
-          currentPath: 'a.2.b',
-          leaf: true,
-          indexes: [3],
-          children: [],
-        },
-      ],
-    };
-
-    assertEquals(
-        JSON.stringify(expected),
-        JSON.stringify(groupedList.buildRemovalTree_(paths)));
-  });
-});
diff --git a/chrome/test/data/webui/md_history/history_metrics_test.js b/chrome/test/data/webui/md_history/history_metrics_test.js
index c065ac10..4df9393 100644
--- a/chrome/test/data/webui/md_history/history_metrics_test.js
+++ b/chrome/test/data/webui/md_history/history_metrics_test.js
@@ -76,10 +76,6 @@
       assertEquals(1, histogram[HistoryPageViewHistogram.SYNCED_TABS]);
       app.selectedPage_ = 'history';
       assertEquals(2, histogram[HistoryPageViewHistogram.HISTORY]);
-      app.fire('change-query', {range: HistoryRange.WEEK});
-      assertEquals(1, histogram[HistoryPageViewHistogram.GROUPED_WEEK]);
-      app.fire('change-query', {range: HistoryRange.MONTH});
-      assertEquals(1, histogram[HistoryPageViewHistogram.GROUPED_MONTH]);
     });
   });
 
diff --git a/chrome/test/data/webui/md_history/history_routing_test.js b/chrome/test/data/webui/md_history/history_routing_test.js
index 2ebae99..db5c01c9 100644
--- a/chrome/test/data/webui/md_history/history_routing_test.js
+++ b/chrome/test/data/webui/md_history/history_routing_test.js
@@ -80,34 +80,6 @@
         assertEquals(searchTerm, toolbar.searchTerm);
         assertEquals('chrome://history/?q=' + searchTerm, window.location.href);
       });
-
-      test('changing route changes grouped range and offset', function() {
-        app.grouped_ = true;
-        navigateTo('/history/week?offset=1');
-        assertEquals(HistoryRange.WEEK, app.queryState_.range);
-        assertEquals(1, app.queryState_.groupedOffset);
-
-        navigateTo('/history/month');
-        assertEquals(HistoryRange.MONTH, app.queryState_.range);
-        assertEquals(0, app.queryState_.groupedOffset);
-
-        navigateTo('/');
-        assertEquals(HistoryRange.ALL_TIME, app.queryState_.range);
-      });
-
-      test('route updates from grouped range and offset', function() {
-        app.grouped_ = true;
-
-        app.fire('change-query', {range: HistoryRange.WEEK});
-        assertEquals('chrome://history/history/week', window.location.href);
-
-        app.fire('change-query', {range: HistoryRange.MONTH, offset: 5});
-        assertEquals(
-            'chrome://history/history/month?offset=5', window.location.href);
-
-        app.fire('change-query', {range: HistoryRange.ALL_TIME});
-        assertEquals('chrome://history/', window.location.href);
-      });
     });
   }
   return {
@@ -131,8 +103,6 @@
       test('search initiated on load', function(done) {
         var verifyFunction = function(info) {
           assertEquals(expectedQuery, info[0]);
-          assertEquals(5, info[1]);
-          assertEquals(HistoryRange.WEEK, info[2]);
           PolymerTest.flushTasks().then(function() {
             assertEquals(
                 expectedQuery,
diff --git a/chrome/test/data/webui/md_history/history_toolbar_test.js b/chrome/test/data/webui/md_history/history_toolbar_test.js
index aa70bfb..2de74712 100644
--- a/chrome/test/data/webui/md_history/history_toolbar_test.js
+++ b/chrome/test/data/webui/md_history/history_toolbar_test.js
@@ -69,37 +69,6 @@
     toolbar.$$('cr-toolbar').fire('search-changed', 'Test2');
   });
 
-  test('grouped history navigation buttons', function() {
-    var info = createHistoryInfo();
-    info.finished = false;
-    app.historyResult(info, []);
-    app.grouped_ = true;
-    return PolymerTest.flushTasks().then(function() {
-      app.fire('change-query', {range: HistoryRange.MONTH});
-      groupedList = app.$.history.$$('#grouped-list');
-      assertTrue(!!groupedList);
-      var today = toolbar.$$('#today-button');
-      var next = toolbar.$$('#next-button');
-      var prev = toolbar.$$('#prev-button');
-
-      assertEquals(0, toolbar.groupedOffset);
-      assertTrue(today.disabled);
-      assertTrue(next.disabled);
-      assertFalse(prev.disabled);
-
-      MockInteractions.tap(prev);
-      assertEquals(1, toolbar.groupedOffset);
-      assertFalse(today.disabled);
-      assertFalse(next.disabled);
-      assertFalse(prev.disabled);
-
-      app.historyResult(createHistoryInfo(), []);
-      assertFalse(today.disabled);
-      assertFalse(next.disabled);
-      assertTrue(prev.disabled);
-    });
-  });
-
   test('sync notice shows and hides', function() {
     toolbar.showSyncNotice = true;
     Polymer.dom.flush();
diff --git a/chrome/test/data/webui/md_history/md_history_browsertest.js b/chrome/test/data/webui/md_history/md_history_browsertest.js
index a3d9a69..754d587 100644
--- a/chrome/test/data/webui/md_history/md_history_browsertest.js
+++ b/chrome/test/data/webui/md_history/md_history_browsertest.js
@@ -83,20 +83,6 @@
   mocha.run();
 });
 
-function MaterialHistoryGroupedListTest() {}
-
-MaterialHistoryGroupedListTest.prototype = {
-  __proto__: MaterialHistoryBrowserTest.prototype,
-
-  extraLibraries: MaterialHistoryBrowserTest.prototype.extraLibraries.concat([
-    'history_grouped_list_test.js',
-  ]),
-};
-
-TEST_F('MaterialHistoryGroupedListTest', 'All', function() {
-  mocha.run();
-});
-
 function MaterialHistoryItemTest() {}
 
 MaterialHistoryItemTest.prototype = {
@@ -173,12 +159,7 @@
 MaterialHistoryRoutingWithQueryParamTest.prototype = {
   __proto__: MaterialHistoryRoutingTest.prototype,
 
-  browsePreload: 'chrome://history/history/week?q=query&offset=5',
-
-  commandLineSwitches:
-      MaterialHistoryBrowserTest.prototype.commandLineSwitches.concat([
-        {switchName: 'enable-grouped-history'}
-      ]),
+  browsePreload: 'chrome://history/?q=query',
 
   /** @override */
   setUp: function() {
diff --git a/chrome/test/data/webui/print_preview.js b/chrome/test/data/webui/print_preview.js
index 7670823..3282b34 100644
--- a/chrome/test/data/webui/print_preview.js
+++ b/chrome/test/data/webui/print_preview.js
@@ -160,9 +160,9 @@
    */
   waitForAnimationToEnd: function(elementId) {
     // add a listener for the animation end event
-    document.addEventListener('webkitAnimationEnd', function f(e) {
+    document.addEventListener('animationend', function f(e) {
       if (e.target.id == elementId) {
-        document.removeEventListener(f, 'webkitAnimationEnd');
+        document.removeEventListener(f, 'animationend');
         testDone();
       }
     });
diff --git a/chrome/test/data/webui/settings/about_page_tests.js b/chrome/test/data/webui/settings/about_page_tests.js
index b094b63..701bcfc 100644
--- a/chrome/test/data/webui/settings/about_page_tests.js
+++ b/chrome/test/data/webui/settings/about_page_tests.js
@@ -241,7 +241,7 @@
 
         fireStatusChanged(UpdateStatus.DISABLED_BY_ADMIN);
         assertEquals(null, icon.src);
-        assertEquals('cr:domain', icon.icon);
+        assertEquals('cr20:domain', icon.icon);
         assertEquals(0, statusMessageEl.textContent.trim().length);
 
         fireStatusChanged(UpdateStatus.FAILED);
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 674ccbf..5ae0041e 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -271,6 +271,35 @@
 
 /**
  * Test fixture for
+ * chrome/browser/resources/settings/people_page/
+ * fingerprint_dialog_progress_arc.html.
+ *
+ * This is ChromeOS only.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsFingerprintProgressArcTest() {}
+
+CrSettingsFingerprintProgressArcTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload:
+      'chrome://md-settings/people_page/fingerprint_progress_arc.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    'fingerprint_progress_arc_browsertest_chromeos.js',
+  ]),
+};
+
+TEST_F('CrSettingsFingerprintProgressArcTest', 'FingerprintProgressArcTest',
+    function() {
+  mocha.run();
+});
+
+/**
+ * Test fixture for
  * chrome/browser/resources/settings/people_page/change_picture.html.
  * This is ChromeOS only.
  * @constructor
diff --git a/chrome/test/data/webui/settings/fingerprint_progress_arc_browsertest_chromeos.js b/chrome/test/data/webui/settings/fingerprint_progress_arc_browsertest_chromeos.js
new file mode 100644
index 0000000..2f880e4
--- /dev/null
+++ b/chrome/test/data/webui/settings/fingerprint_progress_arc_browsertest_chromeos.js
@@ -0,0 +1,201 @@
+// 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.
+
+suite('settings-fingerprint-progress-arc', function() {
+  /**
+   * An object descrbing a 2d point.
+   * @typedef {{
+   *   x: number,
+   *   y: number,
+   * }}
+   */
+  var Point;
+
+  /**
+   * An object descrbing a color with r, g and b values.
+   * @typedef {{
+   *   r: number,
+   *   g: number,
+   *   b: number,
+   * }}
+   */
+  var Color;
+
+  /** @type {?SettingsFingerprintProgressArcElement} */
+  var progressArc = null;
+
+  /** @type {?HTMLCanvasElement} */
+  var canvas = null;
+
+  /** @type {Color} */
+  var black = {r: 0, g: 0, b: 0};
+  /** @type {Color} */
+  var blue = {r: 0, g: 0, b: 255};
+  /** @type {Color} */
+  var white = {r: 255, g: 255, b: 255};
+
+  /**
+   * Helper function which gets the rgb values at |point| on the canvas.
+   * @param {Point} point
+   * @return {Color}
+   */
+  function getRGBData(point) {
+    var ctx = canvas.getContext('2d');
+    var pixel = ctx.getImageData(point.x, point.y, 1, 1).data;
+    return {r: pixel[0], g: pixel[1], b: pixel[2]};
+  }
+
+  /**
+   * Helper function which checks if the given color is white. This is used to
+   * test the shadows, where getting the exact color at a certain point is
+   * difficult, so we just check that it is not white.
+   * @param {Color} actualColor
+   */
+  function checkColorNotWhite(actualColor) {
+    assertNotEquals(white.r, actualColor.r);
+    assertNotEquals(white.g, actualColor.g);
+    assertNotEquals(white.b, actualColor.b);
+  }
+
+  /**
+   * Helper function which checks that a list of points are not white on the
+   * canvas.
+   * @param {!Array<Point>} listOfPoints
+   */
+  function checkListOfNotWhiteData(listOfPoints) {
+    for (var i = 0; i < listOfPoints.length; ++i)
+      checkColorNotWhite(getRGBData(listOfPoints[i]));
+  }
+
+  /**
+   * Helper function which checks if the given color is matches the expected
+   * color.
+   * @param {Color} expectedColor
+   * @param {Color} actualColor
+   */
+  function checkRGBData(expectedColor, actualColor) {
+    assertEquals(expectedColor.r, actualColor.r);
+    assertEquals(expectedColor.g, actualColor.g);
+    assertEquals(expectedColor.b, actualColor.b);
+  }
+
+  /**
+   * Helper function which checks that a list of points match the color the are
+   * expected to have on the canvas.
+   * @param {Color} expectedColor
+   * @param {!Array<Point>} listOfPoints
+   */
+  function checkListOfRGBData(expectedColor, listOfPoints) {
+    for (var i = 0; i < listOfPoints.length; ++i)
+      checkRGBData(expectedColor, getRGBData(listOfPoints[i]));
+  }
+
+  setup(function() {
+    PolymerTest.clearBody();
+    progressArc = document.createElement('settings-fingerprint-progress-arc');
+    canvas = progressArc.$.canvas;
+
+    // Override some parameters and function for testing purposes.
+    progressArc.canvasCircleRadius_ = 50;
+    progressArc.canvasCircleStrokeWidth_ = 3;
+    progressArc.canvasCircleBackgroundColor_ = 'rgba(0,0,0,1.0)';
+    progressArc.canvasCircleProgressColor_ = 'rgba(0,0,255,1.0)';
+    progressArc.canvasCircleShadowColor_= 'rgba(0,0,0,1.0)';
+    progressArc.clearCanvas = function() {
+      var ctx = canvas.getContext('2d');
+      ctx.fillStyle = 'rgba(255,255,255,1.0)';
+      ctx.fillRect(0, 0, canvas.width, canvas.height);
+    };
+    progressArc.clearCanvas();
+
+    document.body.appendChild(progressArc);
+    Polymer.dom.flush();
+  });
+
+  test('TestDrawArc', function() {
+    // Verify that by drawing an arc from 0 to PI/2 with radius 50 and center at
+    // (150, 75), points along that arc should be blue, and points not on that
+    // arc should remain white.
+    progressArc.drawArc(0, Math.PI / 2,
+        progressArc.canvasCircleProgressColor_);
+    /** @type {Array<Point>} */
+    var expectedPointsOnArc = [{x:200, y:75} /* 0rad */,
+        {x:185, y:110} /* PI/4rad */, {x:150, y:125} /* PI/2rad */];
+    /** @type {Array<Point>} */
+    var expectedPointsNotOnArc = [{x:115, y:110} /* 3PI/4rad */,
+        {x:100, y:75} /* PI */];
+    checkListOfRGBData(blue, expectedPointsOnArc);
+    checkListOfRGBData(white, expectedPointsNotOnArc);
+
+    // After clearing, the points that were blue should be white.
+    progressArc.clearCanvas();
+    checkListOfRGBData(white, expectedPointsOnArc);
+
+    // Verify that by drawing an arc from 3PI/2 to 5PI/2 with radius 50 and
+    // center at (150, 75), points along that arc should be blue, and points not
+    // on that arc should remain white.
+    progressArc.drawArc(3 * Math.PI / 2, 5 * Math.PI / 2,
+        progressArc.canvasCircleProgressColor_);
+    expectedPointsOnArc = [{x:150, y:25} /* 3PI/2 */, {x:185, y:40} /* 7PI/4 */,
+        {x:200, y:75} /* 2PI */, {x:185, y:110} /* 9PI/4 */,
+        {x:150, y:125} /* 5PI/2rad */];
+    expectedPointsNotOnArc = [{x:115, y:110} /* 3PI/4rad */,
+        {x:100, y:75} /* PI */, {x:115, y:40} /* 5PI/4 */];
+    checkListOfRGBData(blue, expectedPointsOnArc);
+    checkListOfRGBData(white, expectedPointsNotOnArc);
+  });
+
+  test('TestDrawBackgroundCircle', function() {
+    // Verify that by drawing an circle with radius 50 and center at (150, 75),
+    // points along that arc should be black, and points not on that arc should
+    // remain white.
+    progressArc.drawBackgroundCircle();
+    /** @type {Array<Point>} */
+    var expectedPointsInCircle = [{x:200, y:75} /* 0rad */,
+        {x:150, y:125} /* PI/2rad */, {x:100, y:75} /* PIrad */,
+        {x:150, y:25} /* 3PI/2rad */];
+    /** @type {Array<Point>} */
+    var expectedPointsNotInCircle =
+        [{x:110, y:75} /* Too left, outside of stroke */,
+         {x:90, y:75} /* Too right, inside of stroke */,
+         {x:200, y:100} /* Outside of circle */,
+         {x:150, y:75} /* In the center */];
+    checkListOfRGBData(black, expectedPointsInCircle);
+    checkListOfRGBData(white, expectedPointsNotInCircle);
+
+    // After clearing, the points that were black should be white.
+    progressArc.clearCanvas();
+    checkListOfRGBData(white, expectedPointsInCircle);
+  });
+
+  test('TestDrawShadow', function() {
+    // Verify that by drawing a shadow with radius 50 and center at (150,75)
+    // with blur 20, points that have distance between 50 and 70 from the center
+    // should not be white.
+    progressArc.drawShadow(20, 0, 0);
+    /** @type {Array<Point>} */
+    var expectedPointsInShadowBlur10 = [{x:210, y:75} /* 0rad */,
+        {x:150, y:135} /* PI/2rad */, {x:90, y:75} /* PIrad */,
+        {x:150, y:15} /* 3PI/2rad */];
+    /** @type {Array<Point>} */
+    var expectedPointsInShadowBlur20 = [{x:220, y:75} /* 0rad */,
+        {x:150, y:145} /* PI/2rad */, {x:80, y:75} /* PIrad */,
+        {x:150, y:5} /* 3PI/2rad */];
+
+    checkListOfNotWhiteData(expectedPointsInShadowBlur10);
+    checkListOfNotWhiteData(expectedPointsInShadowBlur20);
+
+    // After clearing, the points that were black should be white.
+    progressArc.clearCanvas();
+    checkListOfRGBData(white, expectedPointsInShadowBlur10);
+    checkListOfRGBData(white, expectedPointsInShadowBlur20);
+
+    // Verify that by drawing a shadow with radius 50 and center at (150,75)
+    // with blur 20, points that have distance between 50 and 60 from the center
+    // should not be white. Points greater than 60 distance should be white.
+    progressArc.drawShadow(10, 0, 0);
+    checkListOfNotWhiteData(expectedPointsInShadowBlur10);
+    checkListOfRGBData(white, expectedPointsInShadowBlur20);
+  });
+});
diff --git a/chrome/test/data/webui/settings/metrics_reporting_tests.js b/chrome/test/data/webui/settings/metrics_reporting_tests.js
index de2f12c..e9ef617d 100644
--- a/chrome/test/data/webui/settings/metrics_reporting_tests.js
+++ b/chrome/test/data/webui/settings/metrics_reporting_tests.js
@@ -24,8 +24,8 @@
 
       var control = page.$.metricsReportingControl;
       assertEquals(testBrowserProxy.metricsReporting.enabled, control.checked);
-      var indicatorVisible = !!page.$$('#indicator');
-      assertEquals(testBrowserProxy.metricsReporting.managed, indicatorVisible);
+      assertEquals(testBrowserProxy.metricsReporting.managed,
+                   !!control.pref.controlledBy);
 
       var changedMetrics = {
         enabled: !testBrowserProxy.metricsReporting.enabled,
@@ -35,13 +35,16 @@
       Polymer.dom.flush();
 
       assertEquals(changedMetrics.enabled, control.checked);
-      indicatorVisible = !!page.$$('#indicator');
-      assertEquals(changedMetrics.managed, indicatorVisible);
+      assertEquals(changedMetrics.managed, !!control.pref.controlledBy);
 
       var toggled = !changedMetrics.enabled;
+      control.checked = toggled;
+      control.notifyChangedByUserInteraction();
 
-      MockInteractions.tap(control);
-      return testBrowserProxy.whenCalled('setMetricsReportingEnabled', toggled);
+      return testBrowserProxy.whenCalled('setMetricsReportingEnabled').then(
+          function(enabled) {
+            assertEquals(toggled, enabled);
+          });
     });
   });
 
diff --git a/chrome/test/data/webui/settings/settings_autofill_section_browsertest.js b/chrome/test/data/webui/settings/settings_autofill_section_browsertest.js
index 7228b71..4af3b28 100644
--- a/chrome/test/data/webui/settings/settings_autofill_section_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_autofill_section_browsertest.js
@@ -217,6 +217,32 @@
                    row.querySelector('#creditCardExpiration').textContent);
     });
 
+    test('verifyCreditCardRowButtonIsDropdownWhenLocal', function() {
+      var creditCard = FakeDataMaker.creditCardEntry();
+      creditCard.metadata.isLocal = true;
+      var section = self.createAutofillSection_([], [creditCard]);
+      var creditCardList = section.$.creditCardList;
+      var row = creditCardList.children[0];
+      assertTrue(!!row);
+      var menuButton = row.querySelector('#creditCardMenu');
+      assertTrue(!!menuButton);
+      var outlinkButton = row.querySelector('[is="paper-icon-button-light"');
+      assertFalse(!!outlinkButton);
+    });
+
+    test('verifyCreditCardRowButtonIsOutlinkWhenRemote', function() {
+      var creditCard = FakeDataMaker.creditCardEntry();
+      creditCard.metadata.isLocal = false;
+      var section = self.createAutofillSection_([], [creditCard]);
+      var creditCardList = section.$.creditCardList;
+      var row = creditCardList.children[0];
+      assertTrue(!!row);
+      var menuButton = row.querySelector('#creditCardMenu');
+      assertFalse(!!menuButton);
+      var outlinkButton = row.querySelector('[is="paper-icon-button-light"');
+      assertTrue(!!outlinkButton);
+    });
+
     test('verifyAddVsEditCreditCardTitle', function() {
       var newCreditCard = FakeDataMaker.emptyCreditCardEntry();
       var newCreditCardDialog = self.createCreditCardDialog_(newCreditCard);
@@ -430,6 +456,32 @@
       assertEquals(addressSummary, actualSummary);
     });
 
+    test('verifyAddressRowButtonIsDropdownWhenLocal', function() {
+      var address = FakeDataMaker.addressEntry();
+      address.metadata.isLocal = true;
+      var section = self.createAutofillSection_([address], []);
+      var addressList = section.$.addressList;
+      var row = addressList.children[0];
+      assertTrue(!!row);
+      var menuButton = row.querySelector('#addressMenu')
+      assertTrue(!!menuButton);
+      var outlinkButton = row.querySelector('[is="paper-icon-button-light"]');
+      assertFalse(!!outlinkButton);
+    });
+
+    test('verifyAddressRowButtonIsOutlinkWhenRemote', function() {
+      var address = FakeDataMaker.addressEntry();
+      address.metadata.isLocal = false;
+      var section = self.createAutofillSection_([address], []);
+      var addressList = section.$.addressList;
+      var row = addressList.children[0];
+      assertTrue(!!row);
+      var menuButton = row.querySelector('#addressMenu')
+      assertFalse(!!menuButton);
+      var outlinkButton = row.querySelector('[is="paper-icon-button-light"]');
+      assertTrue(!!outlinkButton);
+    });
+
     test('verifyAddAddressDialog', function() {
       return self.createAddressDialog_(
           FakeDataMaker.emptyAddressEntry()).then(function(dialog) {
diff --git a/chrome/test/data/webui/test_api.js b/chrome/test/data/webui/test_api.js
index 1a4841f7..a58c731 100644
--- a/chrome/test/data/webui/test_api.js
+++ b/chrome/test/data/webui/test_api.js
@@ -50,7 +50,7 @@
   /**
    * Make all transitions and animations take 0ms. NOTE: this will completely
    * disable webkitTransitionEnd events. If your code relies on them firing, it
-   * will break. webkitAnimationEnd events should still work.
+   * will break. animationend events should still work.
    */
   Test.disableAnimationsAndTransitions = function() {
     var noAnimationStyle = document.createElement('style');
@@ -59,8 +59,8 @@
       '*, * /deep/ * {' +
       '  -webkit-transition-duration: 0ms !important;' +
       '  -webkit-transition-delay: 0ms !important;' +
-      '  -webkit-animation-duration: 0ms !important;' +
-      '  -webkit-animation-delay: 0ms !important;' +
+      '  animation-duration: 0ms !important;' +
+      '  animation-delay: 0ms !important;' +
       '}';
     document.querySelector('head').appendChild(noAnimationStyle);
 
diff --git a/chrome/tools/build/mac/copy_keystone_framework.py b/chrome/tools/build/mac/copy_keystone_framework.py
index 513fdc91..19b8f2f 100644
--- a/chrome/tools/build/mac/copy_keystone_framework.py
+++ b/chrome/tools/build/mac/copy_keystone_framework.py
@@ -31,7 +31,10 @@
   # dotfiles and the Headers directories.
   subprocess.check_call(
       ['rsync', '-acC', '--delete',
-       '--exclude', 'Headers', '--exclude', 'PrivateHeaders',
+       # TODO(rsesek): Exclude these directories again after they are marked as
+       # optional in the code signing resource rules, otherwise the code
+       # signature is invalidated. https://crbug.com/688076
+       #'--exclude', 'Headers', '--exclude', 'PrivateHeaders',
        '--include', '*.so',
        os.path.join(args[1], 'Versions/Current/'),
        output_path])
diff --git a/chrome_elf/blacklist/test/blacklist_test.cc b/chrome_elf/blacklist/test/blacklist_test.cc
index 16ce917..a85f27ef 100644
--- a/chrome_elf/blacklist/test/blacklist_test.cc
+++ b/chrome_elf/blacklist/test/blacklist_test.cc
@@ -143,7 +143,8 @@
 
   void SetUp() override {
     base::string16 temp;
-    override_manager_.OverrideRegistry(HKEY_CURRENT_USER, &temp);
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER, &temp));
     ASSERT_TRUE(nt::SetTestingOverride(nt::HKCU, temp));
 
     // Make the override path available to our test DLL.
diff --git a/chrome_elf/chrome_elf_util_unittest.cc b/chrome_elf/chrome_elf_util_unittest.cc
index 3a9f441..db25af0 100644
--- a/chrome_elf/chrome_elf_util_unittest.cc
+++ b/chrome_elf/chrome_elf_util_unittest.cc
@@ -63,10 +63,10 @@
   base::string16 temp;
 
   if (key == nt::HKCU) {
-    rom->OverrideRegistry(HKEY_CURRENT_USER, &temp);
+    ASSERT_NO_FATAL_FAILURE(rom->OverrideRegistry(HKEY_CURRENT_USER, &temp));
     ASSERT_TRUE(nt::SetTestingOverride(nt::HKCU, temp));
   } else {
-    rom->OverrideRegistry(HKEY_LOCAL_MACHINE, &temp);
+    ASSERT_NO_FATAL_FAILURE(rom->OverrideRegistry(HKEY_LOCAL_MACHINE, &temp));
     ASSERT_TRUE(nt::SetTestingOverride(nt::HKLM, temp));
   }
 }
@@ -85,7 +85,7 @@
 
   // Set up registry override for this test.
   registry_util::RegistryOverrideManager override_manager;
-  RegRedirect(nt::HKCU, &override_manager);
+  ASSERT_NO_FATAL_FAILURE(RegRedirect(nt::HKCU, &override_manager));
 
   // First, ensure that the emergency-off finch signal works.
   EXPECT_TRUE(SetSecurityFinchFlag(true));
@@ -97,7 +97,7 @@
   elf_security::EarlyBrowserSecurity();
   EXPECT_TRUE(IsSecuritySet());
 
-  CancelRegRedirect(nt::HKCU);
+  ASSERT_NO_FATAL_FAILURE(CancelRegRedirect(nt::HKCU));
 }
 
 }  // namespace
diff --git a/chrome_elf/nt_registry/nt_registry_unittest.cc b/chrome_elf/nt_registry/nt_registry_unittest.cc
index d202042..0d54cb5 100644
--- a/chrome_elf/nt_registry/nt_registry_unittest.cc
+++ b/chrome_elf/nt_registry/nt_registry_unittest.cc
@@ -294,9 +294,11 @@
  protected:
   void SetUp() override {
     base::string16 temp;
-    override_manager_.OverrideRegistry(HKEY_CURRENT_USER, &temp);
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER, &temp));
     ASSERT_TRUE(nt::SetTestingOverride(nt::HKCU, temp));
-    override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, &temp);
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, &temp));
     ASSERT_TRUE(nt::SetTestingOverride(nt::HKLM, temp));
   }
 
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index d89cf1d..6e0581f8 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -67,7 +67,6 @@
     tests += [
       ":cast_shell_browsertests",
       ":cast_shell_unittests",
-      "//chromecast/media/cma:cast_cma_unittests",
       "//ipc:ipc_tests",
       "//jingle:jingle_unittests",
       "//url:url_unittests",
@@ -137,11 +136,13 @@
       # Disable ProcessUtilTest.* (need to define OS_ANDROID)
       # Disable StackContainer.BufferAlignment (don't support 16-byte alignment)
       # Disable SystemMetrics2Test.GetSystemMemoryInfo (buffers>0 can't be guaranteed)
+      # Disable TimeFormattingTest.TimeFormat* for flakiness on devices (crbug/671429)
       gtest_excludes = [
         "ProcessMetricsTest.GetNumberOfThreads",
         "ProcessUtilTest.*",
         "StackContainer.BufferAlignment",
         "SystemMetrics2Test.GetSystemMemoryInfo",
+        "TimeFormattingTest.TimeFormat*",
       ]
 
       if (is_cast_audio_only) {
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 76ddc3e..ed1dc9e 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -438,7 +438,7 @@
     const content::Referrer& referrer,
     const std::string& frame_name,
     WindowOpenDisposition disposition,
-    const blink::WebWindowFeatures& features,
+    const blink::mojom::WindowFeatures& features,
     bool user_gesture,
     bool opener_suppressed,
     content::ResourceContext* context,
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h
index f73776c3..ddbb6b7 100644
--- a/chromecast/browser/cast_content_browser_client.h
+++ b/chromecast/browser/cast_content_browser_client.h
@@ -159,7 +159,7 @@
                        const content::Referrer& referrer,
                        const std::string& frame_name,
                        WindowOpenDisposition disposition,
-                       const blink::WebWindowFeatures& features,
+                       const blink::mojom::WindowFeatures& features,
                        bool user_gesture,
                        bool opener_suppressed,
                        content::ResourceContext* context,
diff --git a/chromecast/media/BUILD.gn b/chromecast/media/BUILD.gn
index ad6caf6..5f599d9 100644
--- a/chromecast/media/BUILD.gn
+++ b/chromecast/media/BUILD.gn
@@ -20,12 +20,12 @@
     "audio/cast_audio_output_stream_unittest.cc",
     "base/media_resource_tracker_unittest.cc",
     "base/supported_codec_profile_levels_memo_unittest.cc",
+    "test/run_all_unittests.cc",
   ]
 
   deps = [
     ":media",
     "//base",
-    "//base/test:run_all_unittests",
     "//base/test:test_support",
     "//chromecast/base",
     "//chromecast/base/metrics:test_support",
@@ -35,4 +35,8 @@
     "//testing/gmock",
     "//testing/gtest",
   ]
+
+  if (!is_android) {
+    deps += [ "//chromecast/media/cma:unittests" ]
+  }
 }
diff --git a/chromecast/media/cma/BUILD.gn b/chromecast/media/cma/BUILD.gn
index 3afa9f1..03b6384e 100644
--- a/chromecast/media/cma/BUILD.gn
+++ b/chromecast/media/cma/BUILD.gn
@@ -14,7 +14,8 @@
   ]
 }
 
-test("cast_cma_unittests") {
+source_set("unittests") {
+  testonly = true
   sources = [
     "backend/audio_video_pipeline_device_unittest.cc",
     "base/balanced_media_task_runner_unittest.cc",
@@ -36,7 +37,6 @@
     "test/mock_frame_provider.h",
     "test/mock_media_pipeline_backend.cc",
     "test/mock_media_pipeline_backend.h",
-    "test/run_all_unittests.cc",
   ]
 
   deps = [
@@ -60,6 +60,10 @@
     "//ui/gfx/geometry",
   ]
 
+  data = [
+    "//media/test/data/",
+  ]
+
   # MultizoneBackendTest verifies rendering delay reported by the backend.
   # Since rendering delay is optional on video platforms, enable this test
   # on audio devices only.
diff --git a/chromecast/media/cma/test/run_all_unittests.cc b/chromecast/media/test/run_all_unittests.cc
similarity index 71%
rename from chromecast/media/cma/test/run_all_unittests.cc
rename to chromecast/media/test/run_all_unittests.cc
index 133f8bed..fcb79fb 100644
--- a/chromecast/media/cma/test/run_all_unittests.cc
+++ b/chromecast/media/test/run_all_unittests.cc
@@ -9,21 +9,17 @@
 #include "chromecast/base/metrics/cast_metrics_test_helper.h"
 #include "media/base/media.h"
 
-#if defined(OS_ANDROID)
-#error "CMA not supported on Android"
-#endif
-
-class CmaTestSuite : public base::TestSuite {
+class CastMediaTestSuite : public base::TestSuite {
  public:
   // Note: the base class constructor creates an AtExitManager.
-  CmaTestSuite(int argc, char** argv) : TestSuite(argc, argv) {}
-  ~CmaTestSuite() override {}
+  CastMediaTestSuite(int argc, char** argv) : TestSuite(argc, argv) {}
+  ~CastMediaTestSuite() override {}
 
  protected:
   void Initialize() override;
 };
 
-void CmaTestSuite::Initialize() {
+void CastMediaTestSuite::Initialize() {
   // Run TestSuite::Initialize first so that logging is initialized.
   base::TestSuite::Initialize();
 
@@ -37,9 +33,9 @@
 }
 
 int main(int argc, char** argv) {
-  CmaTestSuite test_suite(argc, argv);
+  CastMediaTestSuite test_suite(argc, argv);
 
   return base::LaunchUnitTests(
-      argc, argv, base::Bind(&CmaTestSuite::Run,
-                             base::Unretained(&test_suite)));
+      argc, argv,
+      base::Bind(&CastMediaTestSuite::Run, base::Unretained(&test_suite)));
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index ebba6cc..8a505d4 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-9276.0.0
\ No newline at end of file
+9282.0.0
\ No newline at end of file
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 0b264cb..c60ef0ad 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -288,6 +288,10 @@
 const char kEnableTouchpadThreeFingerClick[] =
     "enable-touchpad-three-finger-click";
 
+// Enables touch support for screen magnifier.
+const char kEnableTouchSupportForScreenMagnifier[] =
+    "enable-touch-support-for-screen-magnifier";
+
 // Enables the chromecast support for video player app.
 const char kEnableVideoPlayerChromecastSupport[] =
     "enable-video-player-chromecast-support";
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 8b67205..5e7e9fac 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -93,6 +93,7 @@
 CHROMEOS_EXPORT extern const char kEnableScreenshotTestingWithMode[];
 CHROMEOS_EXPORT extern const char kEnableTouchCalibrationSetting[];
 CHROMEOS_EXPORT extern const char kEnableTouchpadThreeFingerClick[];
+CHROMEOS_EXPORT extern const char kEnableTouchSupportForScreenMagnifier[];
 CHROMEOS_EXPORT extern const char kEnableVideoPlayerChromecastSupport[];
 CHROMEOS_EXPORT extern const char kEnterpriseDisableArc[];
 CHROMEOS_EXPORT extern const char kEnterpriseEnableForcedReEnrollment[];
diff --git a/chromeos/geolocation/simple_geolocation_provider.cc b/chromeos/geolocation/simple_geolocation_provider.cc
index 45d6981..06ce1f26 100644
--- a/chromeos/geolocation/simple_geolocation_provider.cc
+++ b/chromeos/geolocation/simple_geolocation_provider.cc
@@ -17,23 +17,10 @@
 namespace chromeos {
 
 namespace {
+
 const char kDefaultGeolocationProviderUrl[] =
     "https://www.googleapis.com/geolocation/v1/geolocate?";
 
-std::unique_ptr<WifiAccessPointVector> GetAccessPointData() {
-  if (!chromeos::NetworkHandler::Get()->geolocation_handler()->wifi_enabled())
-    return nullptr;
-
-  std::unique_ptr<WifiAccessPointVector> result(
-      new chromeos::WifiAccessPointVector);
-  int64_t age_ms = 0;
-  if (!NetworkHandler::Get()->geolocation_handler()->GetWifiAccessPoints(
-          result.get(), &age_ms)) {
-    return nullptr;
-  }
-  return result;
-}
-
 }  // namespace
 
 SimpleGeolocationProvider::SimpleGeolocationProvider(
@@ -49,12 +36,29 @@
 void SimpleGeolocationProvider::RequestGeolocation(
     base::TimeDelta timeout,
     bool send_wifi_access_points,
+    bool send_cell_towers,
     SimpleGeolocationRequest::ResponseCallback callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  auto cell_vector = base::MakeUnique<chromeos::CellTowerVector>();
+  auto wifi_vector = base::MakeUnique<chromeos::WifiAccessPointVector>();
+
+  // Mostly necessary for testing and rare cases where NetworkHandler is not
+  // initialized: in that case, calls to Get() will fail.
+  if (send_wifi_access_points || send_cell_towers) {
+    NetworkHandler::Get()->geolocation_handler()->GetNetworkInformation(
+        wifi_vector.get(), cell_vector.get());
+  }
+
+  if (!send_wifi_access_points || (wifi_vector->size() == 0))
+    wifi_vector = nullptr;
+
+  if (!send_cell_towers || (cell_vector->size() == 0))
+    cell_vector = nullptr;
+
   SimpleGeolocationRequest* request(new SimpleGeolocationRequest(
-      url_context_getter_.get(), url_, timeout,
-      send_wifi_access_points ? GetAccessPointData() : nullptr));
+      url_context_getter_.get(), url_, timeout, std::move(wifi_vector),
+      std::move(cell_vector)));
   requests_.push_back(base::WrapUnique(request));
 
   // SimpleGeolocationProvider owns all requests. It is safe to pass unretained
diff --git a/chromeos/geolocation/simple_geolocation_provider.h b/chromeos/geolocation/simple_geolocation_provider.h
index 2b7ded2..b4fddcc 100644
--- a/chromeos/geolocation/simple_geolocation_provider.h
+++ b/chromeos/geolocation/simple_geolocation_provider.h
@@ -36,10 +36,12 @@
   virtual ~SimpleGeolocationProvider();
 
   // Initiates new request. If |send_wifi_access_points|, WiFi AP information
-  // will be added to the request. See SimpleGeolocationRequest for the
-  // description of the other parameters.
+  // will be added to the request, similarly for |send_cell_towers| and Cell
+  // Tower information. See SimpleGeolocationRequest for the description of
+  // the other parameters.
   void RequestGeolocation(base::TimeDelta timeout,
                           bool send_wifi_access_points,
+                          bool send_cell_towers,
                           SimpleGeolocationRequest::ResponseCallback callback);
 
   // Returns default geolocation service URL.
diff --git a/chromeos/geolocation/simple_geolocation_request.cc b/chromeos/geolocation/simple_geolocation_request.cc
index 1369458..ab15034 100644
--- a/chromeos/geolocation/simple_geolocation_request.cc
+++ b/chromeos/geolocation/simple_geolocation_request.cc
@@ -41,30 +41,38 @@
 
 namespace {
 
-// The full request text. (no parameters are supported by now)
-const char kSimpleGeolocationRequestBody[] = "{\"considerIp\": \"true\"}";
+// Used if sending location signals (WiFi APs, cell towers, etc) is disabled.
+constexpr char kSimpleGeolocationRequestBody[] = "{\"considerIp\": \"true\"}";
 
-// Request data
-const char kConsiderIp[] = "considerIp";
-const char kWifiAccessPoints[] = "wifiAccessPoints";
-
+// Geolocation request field keys:
+// Top-level request data fields.
+constexpr char kConsiderIp[] = "considerIp";
+constexpr char kWifiAccessPoints[] = "wifiAccessPoints";
+constexpr char kCellTowers[] = "cellTowers";
+// Shared Wifi and Cell Tower objects.
+constexpr char kAge[] = "age";
+constexpr char kSignalStrength[] = "signalStrength";
 // WiFi access point objects.
-const char kMacAddress[] = "macAddress";
-const char kSignalStrength[] = "signalStrength";
-const char kAge[] = "age";
-const char kChannel[] = "channel";
-const char kSignalToNoiseRatio[] = "signalToNoiseRatio";
+constexpr char kMacAddress[] = "macAddress";
+constexpr char kChannel[] = "channel";
+constexpr char kSignalToNoiseRatio[] = "signalToNoiseRatio";
+// Cell tower objects.
+constexpr char kCellId[] = "cellId";
+constexpr char kLocationAreaCode[] = "locationAreaCode";
+constexpr char kMobileCountryCode[] = "mobileCountryCode";
+constexpr char kMobileNetworkCode[] = "mobileNetworkCode";
 
-// Response data.
-const char kLocationString[] = "location";
-const char kLatString[] = "lat";
-const char kLngString[] = "lng";
-const char kAccuracyString[] = "accuracy";
+// Geolocation response field keys:
+constexpr char kLocationString[] = "location";
+constexpr char kLatString[] = "lat";
+constexpr char kLngString[] = "lng";
+constexpr char kAccuracyString[] = "accuracy";
+
 // Error object and its contents.
-const char kErrorString[] = "error";
+constexpr char kErrorString[] = "error";
 // "errors" array in "erorr" object is ignored.
-const char kCodeString[] = "code";
-const char kMessageString[] = "message";
+constexpr char kCodeString[] = "code";
+constexpr char kMessageString[] = "message";
 
 // We are using "sparse" histograms for the number of retry attempts,
 // so we need to explicitly limit maximum value (in case something goes wrong).
@@ -291,6 +299,52 @@
 void ReportUmaHasWiFiAccessPoints(bool value) {
   UMA_HISTOGRAM_BOOLEAN("SimpleGeolocation.Request.HasWiFiAccessPoints", value);
 }
+void ReportUmaHasCellTowers(bool value) {
+  UMA_HISTOGRAM_BOOLEAN("SimpleGeolocation.Request.HasCellTowers", value);
+}
+
+// Helpers to reformat data into dictionaries for conversion to request JSON
+std::unique_ptr<base::DictionaryValue> CreateAccessPointDictionary(
+    WifiAccessPoint access_point) {
+  auto access_point_dictionary = base::MakeUnique<base::DictionaryValue>();
+
+  access_point_dictionary->SetStringWithoutPathExpansion(
+      kMacAddress, access_point.mac_address);
+  access_point_dictionary->SetIntegerWithoutPathExpansion(
+      kSignalStrength, access_point.signal_strength);
+  if (!access_point.timestamp.is_null()) {
+    access_point_dictionary->SetStringWithoutPathExpansion(
+        kAge,
+        base::Int64ToString(
+            (base::Time::Now() - access_point.timestamp).InMilliseconds()));
+  }
+
+  access_point_dictionary->SetIntegerWithoutPathExpansion(kChannel,
+                                                          access_point.channel);
+  access_point_dictionary->SetIntegerWithoutPathExpansion(
+      kSignalToNoiseRatio, access_point.signal_to_noise);
+
+  return access_point_dictionary;
+}
+
+std::unique_ptr<base::DictionaryValue> CreateCellTowerDictionary(
+    CellTower cell_tower) {
+  auto cell_tower_dictionary = base::MakeUnique<base::DictionaryValue>();
+  cell_tower_dictionary->SetStringWithoutPathExpansion(kCellId, cell_tower.ci);
+  cell_tower_dictionary->SetStringWithoutPathExpansion(kLocationAreaCode,
+                                                       cell_tower.lac);
+  cell_tower_dictionary->SetStringWithoutPathExpansion(kMobileCountryCode,
+                                                       cell_tower.mcc);
+  cell_tower_dictionary->SetStringWithoutPathExpansion(kMobileNetworkCode,
+                                                       cell_tower.mnc);
+
+  if (!cell_tower.timestamp.is_null()) {
+    cell_tower_dictionary->SetStringWithoutPathExpansion(
+        kAge, base::Int64ToString(
+                  (base::Time::Now() - cell_tower.timestamp).InMilliseconds()));
+  }
+  return cell_tower_dictionary;
+}
 
 }  // namespace
 
@@ -298,7 +352,8 @@
     net::URLRequestContextGetter* url_context_getter,
     const GURL& service_url,
     base::TimeDelta timeout,
-    std::unique_ptr<WifiAccessPointVector> wifi_data)
+    std::unique_ptr<WifiAccessPointVector> wifi_data,
+    std::unique_ptr<CellTowerVector> cell_tower_data)
     : url_context_getter_(url_context_getter),
       service_url_(service_url),
       retry_sleep_on_server_error_(base::TimeDelta::FromSeconds(
@@ -307,7 +362,8 @@
           kResolveGeolocationRetrySleepBadResponseSeconds)),
       timeout_(timeout),
       retries_(0),
-      wifi_data_(wifi_data.release()) {}
+      wifi_data_(wifi_data.release()),
+      cell_tower_data_(cell_tower_data.release()) {}
 
 SimpleGeolocationRequest::~SimpleGeolocationRequest() {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -323,44 +379,51 @@
 }
 
 std::string SimpleGeolocationRequest::FormatRequestBody() const {
-  if (!wifi_data_) {
+  if (!wifi_data_)
     ReportUmaHasWiFiAccessPoints(false);
+
+  if (!cell_tower_data_)
+    ReportUmaHasCellTowers(false);
+
+  if (!cell_tower_data_ && !wifi_data_)
     return std::string(kSimpleGeolocationRequestBody);
-  }
 
   std::unique_ptr<base::DictionaryValue> request(new base::DictionaryValue);
   request->SetBooleanWithoutPathExpansion(kConsiderIp, true);
 
-  base::ListValue* wifi_access_points(new base::ListValue);
-  request->SetWithoutPathExpansion(kWifiAccessPoints, wifi_access_points);
-
-  for (const WifiAccessPoint& access_point : *wifi_data_) {
-    auto access_point_dictionary = base::MakeUnique<base::DictionaryValue>();
-
-    access_point_dictionary->SetStringWithoutPathExpansion(
-        kMacAddress, access_point.mac_address);
-    access_point_dictionary->SetIntegerWithoutPathExpansion(
-        kSignalStrength, access_point.signal_strength);
-    if (!access_point.timestamp.is_null()) {
-      access_point_dictionary->SetStringWithoutPathExpansion(
-          kAge,
-          base::Int64ToString(
-              (base::Time::Now() - access_point.timestamp).InMilliseconds()));
+  if (wifi_data_) {
+    auto wifi_access_points = base::MakeUnique<base::ListValue>();
+    for (const WifiAccessPoint& access_point : *wifi_data_) {
+      wifi_access_points->Append(CreateAccessPointDictionary(access_point));
     }
-
-    access_point_dictionary->SetIntegerWithoutPathExpansion(
-        kChannel, access_point.channel);
-    access_point_dictionary->SetIntegerWithoutPathExpansion(
-        kSignalToNoiseRatio, access_point.signal_to_noise);
-
-    wifi_access_points->Append(std::move(access_point_dictionary));
+    request->SetWithoutPathExpansion(kWifiAccessPoints,
+                                     std::move(wifi_access_points));
   }
+
+  if (cell_tower_data_) {
+    auto cell_towers = base::MakeUnique<base::ListValue>();
+    for (const CellTower& cell_tower : *cell_tower_data_) {
+      cell_towers->Append(CreateCellTowerDictionary(cell_tower));
+    }
+    request->SetWithoutPathExpansion(kCellTowers, std::move(cell_towers));
+  }
+
   std::string result;
   if (!base::JSONWriter::Write(*request, &result)) {
-    ReportUmaHasWiFiAccessPoints(false);
+    // If there's no data for a network type, we will have already reported
+    // false above
+    if (wifi_data_)
+      ReportUmaHasWiFiAccessPoints(false);
+    if (cell_tower_data_)
+      ReportUmaHasCellTowers(false);
+
     return std::string(kSimpleGeolocationRequestBody);
   }
-  ReportUmaHasWiFiAccessPoints(wifi_data_->size());
+
+  if (wifi_data_)
+    ReportUmaHasWiFiAccessPoints(wifi_data_->size());
+  if (cell_tower_data_)
+    ReportUmaHasCellTowers(cell_tower_data_->size());
 
   return result;
 }
diff --git a/chromeos/geolocation/simple_geolocation_request.h b/chromeos/geolocation/simple_geolocation_request.h
index dc72c5c..a172a25a 100644
--- a/chromeos/geolocation/simple_geolocation_request.h
+++ b/chromeos/geolocation/simple_geolocation_request.h
@@ -53,10 +53,12 @@
   // |url| is the server address to which the request wil be sent.
   // |timeout| retry request on error until timeout.
   // If wifi_data is not null, it will be sent to the geolocation server.
+  // If cell_tower_data is not null, it will be sent to the geolocation server.
   SimpleGeolocationRequest(net::URLRequestContextGetter* url_context_getter,
                            const GURL& service_url,
                            base::TimeDelta timeout,
-                           std::unique_ptr<WifiAccessPointVector> wifi_data);
+                           std::unique_ptr<WifiAccessPointVector> wifi_data,
+                           std::unique_ptr<CellTowerVector> cell_tower_data);
 
   ~SimpleGeolocationRequest() override;
 
@@ -133,6 +135,7 @@
   Geoposition position_;
 
   std::unique_ptr<WifiAccessPointVector> wifi_data_;
+  std::unique_ptr<CellTowerVector> cell_tower_data_;
 
   // Creation and destruction should happen on the same thread.
   base::ThreadChecker thread_checker_;
diff --git a/chromeos/geolocation/simple_geolocation_unittest.cc b/chromeos/geolocation/simple_geolocation_unittest.cc
index d18502e..6d1838af7 100644
--- a/chromeos/geolocation/simple_geolocation_unittest.cc
+++ b/chromeos/geolocation/simple_geolocation_unittest.cc
@@ -25,14 +25,14 @@
 
 namespace {
 
-const int kRequestRetryIntervalMilliSeconds = 200;
+constexpr int kRequestRetryIntervalMilliSeconds = 200;
 
 // This should be different from default to prevent SimpleGeolocationRequest
 // from modifying it.
-const char kTestGeolocationProviderUrl[] =
+constexpr char kTestGeolocationProviderUrl[] =
     "https://localhost/geolocation/v1/geolocate?";
 
-const char kSimpleResponseBody[] =
+constexpr char kSimpleResponseBody[] =
     "{\n"
     "  \"location\": {\n"
     "    \"lat\": 51.0,\n"
@@ -40,24 +40,37 @@
     "  },\n"
     "  \"accuracy\": 1200.4\n"
     "}";
-const char kIPOnlyRequestBody[] = "{\"considerIp\": \"true\"}";
-const char kOneWiFiAPRequestBody[] =
+constexpr char kIPOnlyRequestBody[] = "{\"considerIp\": \"true\"}";
+constexpr char kOneWiFiAPRequestBody[] =
     "{"
-      "\"considerIp\":true,"
-      "\"wifiAccessPoints\":["
-        "{"
-          "\"channel\":1,"
-          "\"macAddress\":\"01:00:00:00:00:00\","
-          "\"signalStrength\":10,"
-          "\"signalToNoiseRatio\":0"
-        "}"
-      "]"
+    "\"considerIp\":true,"
+    "\"wifiAccessPoints\":["
+    "{"
+    "\"channel\":1,"
+    "\"macAddress\":\"01:00:00:00:00:00\","
+    "\"signalStrength\":10,"
+    "\"signalToNoiseRatio\":0"
+    "}"
+    "]"
     "}";
-const char kExpectedPosition[] =
+constexpr char kOneCellTowerRequestBody[] =
+    "{"
+    "\"cellTowers\":["
+    "{"
+    "\"cellId\":\"1\","
+    "\"locationAreaCode\":\"10\","
+    "\"mobileCountryCode\":\"100\","
+    "\"mobileNetworkCode\":\"101\""
+    "}"
+    "],"
+    "\"considerIp\":true"
+    "}";
+constexpr char kExpectedPosition[] =
     "latitude=51.000000, longitude=-0.100000, accuracy=1200.400000, "
     "error_code=0, error_message='', status=1 (OK)";
 
-const char kWiFiAP1MacAddress[] = "01:00:00:00:00:00";
+constexpr char kWiFiAP1MacAddress[] = "01:00:00:00:00:00";
+constexpr char kCellTower1MNC[] = "101";
 }  // anonymous namespace
 
 namespace chromeos {
@@ -189,9 +202,9 @@
   std::unique_ptr<base::RunLoop> message_loop_runner_;
 };
 
-class WiFiTestMonitor : public SimpleGeolocationRequestTestMonitor {
+class WirelessTestMonitor : public SimpleGeolocationRequestTestMonitor {
  public:
-  WiFiTestMonitor() {}
+  WirelessTestMonitor() {}
 
   void OnRequestCreated(SimpleGeolocationRequest* request) override {}
   void OnStart(SimpleGeolocationRequest* request) override {
@@ -203,7 +216,7 @@
  private:
   std::string last_request_body_;
 
-  DISALLOW_COPY_AND_ASSIGN(WiFiTestMonitor);
+  DISALLOW_COPY_AND_ASSIGN(WirelessTestMonitor);
 };
 
 class SimpleGeolocationTest : public testing::Test {
@@ -221,7 +234,7 @@
                                            &provider);
 
   GeolocationReceiver receiver;
-  provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), false,
+  provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), false, false,
                               base::Bind(&GeolocationReceiver::OnRequestDone,
                                          base::Unretained(&receiver)));
   receiver.WaitUntilRequestDone();
@@ -241,7 +254,7 @@
                                            &provider);
 
   GeolocationReceiver receiver;
-  provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), false,
+  provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), false, false,
                               base::Bind(&GeolocationReceiver::OnRequestDone,
                                          base::Unretained(&receiver)));
   receiver.WaitUntilRequestDone();
@@ -267,7 +280,7 @@
   ASSERT_GE(expected_retries, 2U);
 
   provider.RequestGeolocation(base::TimeDelta::FromSeconds(timeout_seconds),
-                              false,
+                              false, false,
                               base::Bind(&GeolocationReceiver::OnRequestDone,
                                          base::Unretained(&receiver)));
   receiver.WaitUntilRequestDone();
@@ -299,7 +312,7 @@
   DBusThreadManager::GetSetterForTesting();
   NetworkHandler::Initialize();
 
-  WiFiTestMonitor requests_monitor;
+  WirelessTestMonitor requests_monitor;
   SimpleGeolocationRequest::SetTestMonitor(&requests_monitor);
 
   SimpleGeolocationProvider provider(nullptr,
@@ -310,7 +323,7 @@
                                            0 /* require_retries */, &provider);
 
   GeolocationReceiver receiver;
-  provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), true,
+  provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), true, false,
                               base::Bind(&GeolocationReceiver::OnRequestDone,
                                          base::Unretained(&receiver)));
   receiver.WaitUntilRequestDone();
@@ -324,13 +337,13 @@
   DBusThreadManager::Shutdown();
 }
 
-// Test sending of WiFi Access points.
+// Test sending of WiFi Access points and Cell Towers.
 // (This is mostly derived from GeolocationHandlerTest.)
-class SimpleGeolocationWiFiTest : public ::testing::TestWithParam<bool> {
+class SimpleGeolocationWirelessTest : public ::testing::TestWithParam<bool> {
  public:
-  SimpleGeolocationWiFiTest() : manager_test_(nullptr) {}
+  SimpleGeolocationWirelessTest() : manager_test_(nullptr) {}
 
-  ~SimpleGeolocationWiFiTest() override {}
+  ~SimpleGeolocationWirelessTest() override {}
 
   void SetUp() override {
     // This initializes DBusThreadManager and markes it "for tests only".
@@ -354,6 +367,11 @@
                                                      nullptr);
   }
 
+  bool GetCellTowers() {
+    return geolocation_handler_->GetNetworkInformation(nullptr, &cell_towers_);
+  }
+
+  // This should remain in sync with the format of shill (chromeos) dict entries
   void AddAccessPoint(int idx) {
     base::DictionaryValue properties;
     std::string mac_address =
@@ -366,7 +384,28 @@
                                              channel);
     properties.SetStringWithoutPathExpansion(shill::kGeoSignalStrengthProperty,
                                              strength);
-    manager_test_->AddGeoNetwork(shill::kTypeWifi, properties);
+    manager_test_->AddGeoNetwork(shill::kGeoWifiAccessPointsProperty,
+                                 properties);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // This should remain in sync with the format of shill (chromeos) dict entries
+  void AddCellTower(int idx) {
+    base::DictionaryValue properties;
+    std::string ci = base::IntToString(idx);
+    std::string lac = base::IntToString(idx * 10);
+    std::string mcc = base::IntToString(idx * 100);
+    std::string mnc = base::IntToString(idx * 100 + 1);
+
+    properties.SetStringWithoutPathExpansion(shill::kGeoCellIdProperty, ci);
+    properties.SetStringWithoutPathExpansion(
+        shill::kGeoLocationAreaCodeProperty, lac);
+    properties.SetStringWithoutPathExpansion(
+        shill::kGeoMobileCountryCodeProperty, mcc);
+    properties.SetStringWithoutPathExpansion(
+        shill::kGeoMobileNetworkCodeProperty, mnc);
+
+    manager_test_->AddGeoNetwork(shill::kGeoCellTowersProperty, properties);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -375,16 +414,17 @@
   std::unique_ptr<GeolocationHandler> geolocation_handler_;
   ShillManagerClient::TestInterface* manager_test_;
   WifiAccessPointVector wifi_access_points_;
+  CellTowerVector cell_towers_;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(SimpleGeolocationWiFiTest);
+  DISALLOW_COPY_AND_ASSIGN(SimpleGeolocationWirelessTest);
 };
 
 // Parameter is enable/disable sending of WiFi data.
-TEST_P(SimpleGeolocationWiFiTest, WiFiExists) {
+TEST_P(SimpleGeolocationWirelessTest, WiFiExists) {
   NetworkHandler::Initialize();
 
-  WiFiTestMonitor requests_monitor;
+  WirelessTestMonitor requests_monitor;
   SimpleGeolocationRequest::SetTestMonitor(&requests_monitor);
 
   SimpleGeolocationProvider provider(nullptr,
@@ -396,6 +436,7 @@
   {
     GeolocationReceiver receiver;
     provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), GetParam(),
+                                false,
                                 base::Bind(&GeolocationReceiver::OnRequestDone,
                                            base::Unretained(&receiver)));
     receiver.WaitUntilRequestDone();
@@ -406,10 +447,11 @@
     EXPECT_EQ(1U, url_factory.attempts());
   }
 
-  // Add an acces point.
+  // Add cell and wifi to ensure only wifi is sent when cellular disabled.
   AddAccessPoint(1);
+  AddCellTower(1);
   base::RunLoop().RunUntilIdle();
-  // Inititial call should return false and request access points.
+  // Initial call should return false and request access points.
   EXPECT_FALSE(GetWifiAccessPoints());
   base::RunLoop().RunUntilIdle();
   // Second call should return true since we have an access point.
@@ -421,6 +463,7 @@
   {
     GeolocationReceiver receiver;
     provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), GetParam(),
+                                false,
                                 base::Bind(&GeolocationReceiver::OnRequestDone,
                                            base::Unretained(&receiver)));
     receiver.WaitUntilRequestDone();
@@ -442,7 +485,67 @@
 
 // This test verifies that WiFi data is sent only if sending was requested.
 INSTANTIATE_TEST_CASE_P(EnableDisableSendingWifiData,
-                        SimpleGeolocationWiFiTest,
+                        SimpleGeolocationWirelessTest,
                         testing::Bool());
 
+TEST_P(SimpleGeolocationWirelessTest, CellularExists) {
+  NetworkHandler::Initialize();
+
+  WirelessTestMonitor requests_monitor;
+  SimpleGeolocationRequest::SetTestMonitor(&requests_monitor);
+
+  SimpleGeolocationProvider provider(nullptr,
+                                     GURL(kTestGeolocationProviderUrl));
+
+  GeolocationAPIFetcherFactory url_factory(GURL(kTestGeolocationProviderUrl),
+                                           std::string(kSimpleResponseBody),
+                                           0 /* require_retries */, &provider);
+  {
+    GeolocationReceiver receiver;
+    provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), false,
+                                GetParam(),
+                                base::Bind(&GeolocationReceiver::OnRequestDone,
+                                           base::Unretained(&receiver)));
+    receiver.WaitUntilRequestDone();
+    EXPECT_EQ(kIPOnlyRequestBody, requests_monitor.last_request_body());
+
+    EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
+    EXPECT_FALSE(receiver.server_error());
+    EXPECT_EQ(1U, url_factory.attempts());
+  }
+
+  AddCellTower(1);
+  base::RunLoop().RunUntilIdle();
+  // Initial call should return false and request cell towers.
+  EXPECT_FALSE(GetCellTowers());
+  base::RunLoop().RunUntilIdle();
+  // Second call should return true since we have a tower.
+  EXPECT_TRUE(GetCellTowers());
+  ASSERT_EQ(1u, cell_towers_.size());
+  EXPECT_EQ(kCellTower1MNC, cell_towers_[0].mnc);
+  EXPECT_EQ(base::IntToString(1), cell_towers_[0].ci);
+
+  {
+    GeolocationReceiver receiver;
+    provider.RequestGeolocation(base::TimeDelta::FromSeconds(1), false,
+                                GetParam(),
+                                base::Bind(&GeolocationReceiver::OnRequestDone,
+                                           base::Unretained(&receiver)));
+    receiver.WaitUntilRequestDone();
+    if (GetParam()) {
+      // Sending Cellular data is enabled.
+      EXPECT_EQ(kOneCellTowerRequestBody, requests_monitor.last_request_body());
+    } else {
+      // Sending Cellular data is disabled.
+      EXPECT_EQ(kIPOnlyRequestBody, requests_monitor.last_request_body());
+    }
+
+    EXPECT_EQ(kExpectedPosition, receiver.position().ToString());
+    EXPECT_FALSE(receiver.server_error());
+    // This is total.
+    EXPECT_EQ(2U, url_factory.attempts());
+  }
+  NetworkHandler::Shutdown();
+}
+
 }  // namespace chromeos
diff --git a/chromeos/network/geolocation_handler.cc b/chromeos/network/geolocation_handler.cc
index 0041ccf..fb586417 100644
--- a/chromeos/network/geolocation_handler.cc
+++ b/chromeos/network/geolocation_handler.cc
@@ -16,10 +16,15 @@
 
 namespace chromeos {
 
+namespace {
+
+constexpr const char* kDevicePropertyNames[] = {
+    shill::kGeoWifiAccessPointsProperty, shill::kGeoCellTowersProperty};
+
+}  // namespace
+
 GeolocationHandler::GeolocationHandler()
-    : wifi_enabled_(false),
-      weak_ptr_factory_(this) {
-}
+    : cellular_enabled_(false), wifi_enabled_(false), weak_ptr_factory_(this) {}
 
 GeolocationHandler::~GeolocationHandler() {
   ShillManagerClient* manager_client =
@@ -42,10 +47,10 @@
     int64_t* age_ms) {
   if (!wifi_enabled_)
     return false;
-  // Always request updated access points.
-  RequestWifiAccessPoints();
+  // Always request updated info.
+  RequestGeolocationObjects();
   // If no data has been received, return false.
-  if (geolocation_received_time_.is_null())
+  if (geolocation_received_time_.is_null() || wifi_access_points_.size() == 0)
     return false;
   if (access_points)
     *access_points = wifi_access_points_;
@@ -56,6 +61,27 @@
   return true;
 }
 
+bool GeolocationHandler::GetNetworkInformation(
+    WifiAccessPointVector* access_points,
+    CellTowerVector* cell_towers) {
+  if (!cellular_enabled_ && !wifi_enabled_)
+    return false;
+
+  // Always request updated info.
+  RequestGeolocationObjects();
+
+  // If no data has been received, return false.
+  if (geolocation_received_time_.is_null())
+    return false;
+
+  if (cell_towers)
+    *cell_towers = cell_towers_;
+  if (access_points)
+    *access_points = wifi_access_points_;
+
+  return true;
+}
+
 void GeolocationHandler::OnPropertyChanged(const std::string& key,
                                            const base::Value& value) {
   HandlePropertyChanged(key, value);
@@ -67,7 +93,7 @@
 void GeolocationHandler::ManagerPropertiesCallback(
     DBusMethodCallStatus call_status,
     const base::DictionaryValue& properties) {
-  const base::Value* value = NULL;
+  const base::Value* value = nullptr;
   if (properties.Get(shill::kEnabledTechnologiesProperty, &value) && value)
     HandlePropertyChanged(shill::kEnabledTechnologiesProperty, *value);
 }
@@ -76,10 +102,12 @@
                                                const base::Value& value) {
   if (key != shill::kEnabledTechnologiesProperty)
     return;
-  const base::ListValue* technologies = NULL;
+  const base::ListValue* technologies = nullptr;
   if (!value.GetAsList(&technologies) || !technologies)
     return;
   bool wifi_was_enabled = wifi_enabled_;
+  bool cellular_was_enabled = cellular_enabled_;
+  cellular_enabled_ = false;
   wifi_enabled_ = false;
   for (base::ListValue::const_iterator iter = technologies->begin();
        iter != technologies->end(); ++iter) {
@@ -87,14 +115,21 @@
     (*iter)->GetAsString(&technology);
     if (technology == shill::kTypeWifi) {
       wifi_enabled_ = true;
-      break;
+    } else if (technology == shill::kTypeCellular) {
+      cellular_enabled_ = true;
     }
+    if (wifi_enabled_ && cellular_enabled_)
+      break;
   }
-  if (!wifi_was_enabled && wifi_enabled_)
-    RequestWifiAccessPoints();  // Request initial location data.
+
+  // Request initial location data.
+  if ((!wifi_was_enabled && wifi_enabled_) ||
+      (!cellular_was_enabled && cellular_enabled_)) {
+    RequestGeolocationObjects();
+  }
 }
 
-void GeolocationHandler::RequestWifiAccessPoints() {
+void GeolocationHandler::RequestGeolocationObjects() {
   DBusThreadManager::Get()->GetShillManagerClient()->GetNetworksForGeolocation(
       base::Bind(&GeolocationHandler::GeolocationCallback,
                  weak_ptr_factory_.GetWeakPtr()));
@@ -108,48 +143,97 @@
     return;
   }
   wifi_access_points_.clear();
+  cell_towers_.clear();
   if (properties.empty())
     return;  // No enabled devices, don't update received time.
 
   // Dictionary<device_type, entry_list>
-  for (base::DictionaryValue::Iterator iter(properties);
-       !iter.IsAtEnd(); iter.Advance()) {
-    const base::ListValue* entry_list = NULL;
-    if (!iter.value().GetAsList(&entry_list)) {
-      LOG(WARNING) << "Geolocation dictionary value not a List: " << iter.key();
+  // Example dict returned from shill:
+  // {
+  //   kGeoWifiAccessPointsProperty: [ {kGeoMacAddressProperty: mac_value, ...},
+  //                                   ...
+  //                                 ],
+  //   kGeoCellTowersProperty: [ {kGeoCellIdProperty: cell_id_value, ...}, ... ]
+  // }
+  for (auto device_type : kDevicePropertyNames) {
+    if (!properties.HasKey(device_type)) {
       continue;
     }
+
+    const base::ListValue* entry_list = nullptr;
+    if (!properties.GetList(device_type, &entry_list)) {
+      LOG(WARNING) << "Geolocation dictionary value not a List: "
+                   << device_type;
+      continue;
+    }
+
     // List[Dictionary<key, value_str>]
     for (size_t i = 0; i < entry_list->GetSize(); ++i) {
-      const base::DictionaryValue* entry = NULL;
+      const base::DictionaryValue* entry = nullptr;
       if (!entry_list->GetDictionary(i, &entry) || !entry) {
         LOG(WARNING) << "Geolocation list value not a Dictionary: " << i;
         continue;
       }
-      // Docs: developers.google.com/maps/documentation/business/geolocation
-      WifiAccessPoint wap;
-      entry->GetString(shill::kGeoMacAddressProperty, &wap.mac_address);
-      std::string age_str;
-      if (entry->GetString(shill::kGeoAgeProperty, &age_str)) {
-        int64_t age_ms;
-        if (base::StringToInt64(age_str, &age_ms)) {
-          wap.timestamp =
-              base::Time::Now() - base::TimeDelta::FromMilliseconds(age_ms);
-        }
+      if (device_type == shill::kGeoWifiAccessPointsProperty) {
+        AddAccessPointFromDict(entry);
+      } else if (device_type == shill::kGeoCellTowersProperty) {
+        AddCellTowerFromDict(entry);
       }
-      std::string strength_str;
-      if (entry->GetString(shill::kGeoSignalStrengthProperty, &strength_str))
-        base::StringToInt(strength_str, &wap.signal_strength);
-      std::string signal_str;
-      if (entry->GetString(shill::kGeoSignalToNoiseRatioProperty, &signal_str))
-        base::StringToInt(signal_str, &wap.signal_to_noise);
-      std::string channel_str;
-      if (entry->GetString(shill::kGeoChannelProperty, &channel_str))
-        base::StringToInt(channel_str, &wap.channel);
-      wifi_access_points_.push_back(wap);
     }
   }
   geolocation_received_time_ = base::Time::Now();
 }
 
+void GeolocationHandler::AddAccessPointFromDict(
+    const base::DictionaryValue* entry) {
+  // Docs: developers.google.com/maps/documentation/business/geolocation
+  WifiAccessPoint wap;
+
+  std::string age_str;
+  if (entry->GetString(shill::kGeoAgeProperty, &age_str)) {
+    int64_t age_ms;
+    if (base::StringToInt64(age_str, &age_ms)) {
+      wap.timestamp =
+          base::Time::Now() - base::TimeDelta::FromMilliseconds(age_ms);
+    }
+  }
+  entry->GetString(shill::kGeoMacAddressProperty, &wap.mac_address);
+
+  std::string strength_str;
+  if (entry->GetString(shill::kGeoSignalStrengthProperty, &strength_str))
+    base::StringToInt(strength_str, &wap.signal_strength);
+
+  std::string signal_str;
+  if (entry->GetString(shill::kGeoSignalToNoiseRatioProperty, &signal_str)) {
+    base::StringToInt(signal_str, &wap.signal_to_noise);
+  }
+
+  std::string channel_str;
+  if (entry->GetString(shill::kGeoChannelProperty, &channel_str))
+    base::StringToInt(channel_str, &wap.channel);
+
+  wifi_access_points_.push_back(wap);
+}
+
+void GeolocationHandler::AddCellTowerFromDict(
+    const base::DictionaryValue* entry) {
+  // Docs: developers.google.com/maps/documentation/business/geolocation
+  CellTower ct;
+
+  std::string age_str;
+  if (entry->GetString(shill::kGeoAgeProperty, &age_str)) {
+    int64_t age_ms;
+    if (base::StringToInt64(age_str, &age_ms)) {
+      ct.timestamp =
+          base::Time::Now() - base::TimeDelta::FromMilliseconds(age_ms);
+    }
+  }
+  entry->GetString(shill::kGeoCellIdProperty, &ct.ci);
+  entry->GetString(shill::kGeoLocationAreaCodeProperty, &ct.lac);
+  entry->GetString(shill::kGeoMobileCountryCodeProperty, &ct.mcc);
+  entry->GetString(shill::kGeoMobileNetworkCodeProperty, &ct.mnc);
+
+  cell_towers_.push_back(ct);
+}
+
 }  // namespace chromeos
diff --git a/chromeos/network/geolocation_handler.h b/chromeos/network/geolocation_handler.h
index f9623285..c0e61527 100644
--- a/chromeos/network/geolocation_handler.h
+++ b/chromeos/network/geolocation_handler.h
@@ -21,10 +21,11 @@
 
 namespace chromeos {
 
-// This class provices Shill Wifi Access Point data. It currently relies on
-// polling because that is the usage model in content::WifiDataProvider. This
-// class requests data asynchronously, returning the most recent available data.
-// A typical usage pattern, assuming a wifi device is enabled, is:
+// This class provices Shill Wifi Access Point and Cell Tower data. It
+// currently relies on polling because that is the usage model in
+// content::WifiDataProvider. This class requests data asynchronously,
+// returning the most recent available data. A typical usage pattern,
+// assuming a wifi device is enabled, is:
 //   Initialize();  // Makes an initial request
 //   GetWifiAccessPoints();  // returns true + inital data, requests update
 //   (Delay some amount of time, ~10s)
@@ -37,9 +38,17 @@
  public:
   ~GeolocationHandler() override;
 
-  // This sends a request for wifi access point data. If data is already
-  // available, returns |true|, fills |access_points| with the latest access
-  // point data, and sets |age_ms| to the time since the last update in MS.
+  // This sends a request for geolocation (both wifi AP and cell tower) data.
+  // If AP data is already available, fills |access_points| with the latest
+  // access point data, and similarly for cell tower data and |cell_towers|.
+  // Returns |true| if either type of data is already available upon call.
+  bool GetNetworkInformation(WifiAccessPointVector* access_points,
+                             CellTowerVector* cell_towers);
+
+  // This sends a request for geolocation (both wifi AP and cell tower) data.
+  // If wifi data is already available, returns |true|, fills |access_points|
+  // with the latest access point data, and sets |age_ms| to the time
+  // since the last update in MS.
   bool GetWifiAccessPoints(WifiAccessPointVector* access_points,
                            int64_t* age_ms);
 
@@ -52,7 +61,7 @@
  private:
   friend class NetworkHandler;
   friend class GeolocationHandlerTest;
-  friend class SimpleGeolocationWiFiTest;
+  friend class SimpleGeolocationWirelessTest;
 
   GeolocationHandler();
 
@@ -65,18 +74,23 @@
   // Called from OnPropertyChanged or ManagerPropertiesCallback.
   void HandlePropertyChanged(const std::string& key, const base::Value& value);
 
-  // Asynchronously request wifi access points from Shill.Manager.
-  void RequestWifiAccessPoints();
+  // Asynchronously request geolocation objects (wifi access points and
+  // cell towers) from Shill.Manager.
+  void RequestGeolocationObjects();
 
   // Callback for receiving Geolocation data.
   void GeolocationCallback(DBusMethodCallStatus call_status,
                            const base::DictionaryValue& properties);
 
-  // Wifi enabled state
+  bool cellular_enabled_;
   bool wifi_enabled_;
 
-  // Cached wifi access points and update time
+  void AddCellTowerFromDict(const base::DictionaryValue* entry);
+  void AddAccessPointFromDict(const base::DictionaryValue* entry);
+
+  // Cached netork information and update time
   WifiAccessPointVector wifi_access_points_;
+  CellTowerVector cell_towers_;
   base::Time geolocation_received_time_;
 
   // For Shill client callbacks
diff --git a/chromeos/network/geolocation_handler_unittest.cc b/chromeos/network/geolocation_handler_unittest.cc
index 49a9846..9d5dc9f 100644
--- a/chromeos/network/geolocation_handler_unittest.cc
+++ b/chromeos/network/geolocation_handler_unittest.cc
@@ -44,10 +44,15 @@
   }
 
   bool GetWifiAccessPoints() {
-    return geolocation_handler_->GetWifiAccessPoints(
-        &wifi_access_points_, NULL);
+    return geolocation_handler_->GetWifiAccessPoints(&wifi_access_points_,
+                                                     nullptr);
   }
 
+  bool GetCellTowers() {
+    return geolocation_handler_->GetNetworkInformation(nullptr, &cell_towers_);
+  }
+
+  // This should remain in sync with the format of shill (chromeos) dict entries
   void AddAccessPoint(int idx) {
     base::DictionaryValue properties;
     std::string mac_address =
@@ -55,13 +60,36 @@
                            idx, 0, 0, 0, 0, 0);
     std::string channel = base::IntToString(idx);
     std::string strength = base::IntToString(idx * 10);
+    properties.SetStringWithoutPathExpansion(shill::kGeoMacAddressProperty,
+                                             mac_address);
+    properties.SetStringWithoutPathExpansion(shill::kGeoChannelProperty,
+                                             channel);
+    properties.SetStringWithoutPathExpansion(shill::kGeoSignalStrengthProperty,
+                                             strength);
+    manager_test_->AddGeoNetwork(shill::kGeoWifiAccessPointsProperty,
+                                 properties);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  // This should remain in sync with the format of shill (chromeos) dict entries
+  void AddCellTower(int idx) {
+    base::DictionaryValue properties;
+    // Multiplications are intended solely to differentiate the various fields
+    // in a predictable way, while preserving 3 digits for MCC and MNC.
+    std::string ci = base::IntToString(idx);
+    std::string lac = base::IntToString(idx * 10);
+    std::string mcc = base::IntToString(idx * 100);
+    std::string mnc = base::IntToString(idx * 100 + 1);
+
+    properties.SetStringWithoutPathExpansion(shill::kGeoCellIdProperty, ci);
     properties.SetStringWithoutPathExpansion(
-        shill::kGeoMacAddressProperty, mac_address);
+        shill::kGeoLocationAreaCodeProperty, lac);
     properties.SetStringWithoutPathExpansion(
-        shill::kGeoChannelProperty, channel);
+        shill::kGeoMobileCountryCodeProperty, mcc);
     properties.SetStringWithoutPathExpansion(
-        shill::kGeoSignalStrengthProperty, strength);
-    manager_test_->AddGeoNetwork(shill::kTypeWifi, properties);
+        shill::kGeoMobileNetworkCodeProperty, mnc);
+
+    manager_test_->AddGeoNetwork(shill::kGeoCellTowersProperty, properties);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -70,6 +98,7 @@
   std::unique_ptr<GeolocationHandler> geolocation_handler_;
   ShillManagerClient::TestInterface* manager_test_;
   WifiAccessPointVector wifi_access_points_;
+  CellTowerVector cell_towers_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(GeolocationHandlerTest);
@@ -78,13 +107,15 @@
 TEST_F(GeolocationHandlerTest, NoAccessPoints) {
   // Inititial call should return false.
   EXPECT_FALSE(GetWifiAccessPoints());
+  EXPECT_FALSE(GetCellTowers());
   base::RunLoop().RunUntilIdle();
   // Second call should return false since there are no devices.
   EXPECT_FALSE(GetWifiAccessPoints());
+  EXPECT_FALSE(GetCellTowers());
 }
 
 TEST_F(GeolocationHandlerTest, OneAccessPoint) {
-  // Add an acces point.
+  // Add an access point.
   AddAccessPoint(1);
   base::RunLoop().RunUntilIdle();
   // Inititial call should return false and request access points.
@@ -98,13 +129,14 @@
 }
 
 TEST_F(GeolocationHandlerTest, MultipleAccessPoints) {
-  // Add several acces points.
+  // Add several access points.
   AddAccessPoint(1);
   AddAccessPoint(2);
   AddAccessPoint(3);
   base::RunLoop().RunUntilIdle();
   // Inititial call should return false and request access points.
   EXPECT_FALSE(GetWifiAccessPoints());
+  EXPECT_FALSE(GetCellTowers());
   base::RunLoop().RunUntilIdle();
   // Second call should return true since we have an access point.
   EXPECT_TRUE(GetWifiAccessPoints());
@@ -113,4 +145,65 @@
   EXPECT_EQ(3, wifi_access_points_[2].channel);
 }
 
+TEST_F(GeolocationHandlerTest, OneCellTower) {
+  // Add a cell tower.
+  AddCellTower(1);
+  base::RunLoop().RunUntilIdle();
+  // Inititial call should return false and request towers.
+  EXPECT_FALSE(GetCellTowers());
+  EXPECT_FALSE(GetWifiAccessPoints());
+  base::RunLoop().RunUntilIdle();
+  // Second call should return true since we have a cell tower.
+  EXPECT_TRUE(GetCellTowers());
+  EXPECT_FALSE(GetWifiAccessPoints());
+  ASSERT_EQ(1u, cell_towers_.size());
+  EXPECT_EQ("1", cell_towers_[0].ci);
+  EXPECT_EQ("10", cell_towers_[0].lac);
+  EXPECT_EQ("100", cell_towers_[0].mcc);
+  EXPECT_EQ("101", cell_towers_[0].mnc);
+}
+
+TEST_F(GeolocationHandlerTest, MultipleCellTowers) {
+  // Add several cell towers.
+  AddCellTower(1);
+  AddCellTower(2);
+  AddCellTower(3);
+  base::RunLoop().RunUntilIdle();
+  // Inititial call should return false and request cell towers.
+  EXPECT_FALSE(GetWifiAccessPoints());
+  EXPECT_FALSE(GetCellTowers());
+  base::RunLoop().RunUntilIdle();
+  // Second call should return true since we have a cell tower.
+  EXPECT_FALSE(GetWifiAccessPoints());
+  EXPECT_TRUE(GetCellTowers());
+  ASSERT_EQ(3u, cell_towers_.size());
+  EXPECT_EQ("20", cell_towers_[1].lac);
+  EXPECT_EQ("301", cell_towers_[2].mnc);
+}
+
+TEST_F(GeolocationHandlerTest, MultipleGeolocations) {
+  // Add both a cell tower and wifi AP.
+  AddCellTower(1);
+  AddCellTower(2);
+  AddAccessPoint(1);
+  AddAccessPoint(2);
+  base::RunLoop().RunUntilIdle();
+  // Inititial call should return false and request towers.
+  EXPECT_FALSE(GetCellTowers());
+  EXPECT_FALSE(GetWifiAccessPoints());
+  base::RunLoop().RunUntilIdle();
+  // Second call should return true since we have a cell tower.
+  EXPECT_TRUE(GetCellTowers());
+  EXPECT_TRUE(GetWifiAccessPoints());
+  ASSERT_EQ(2u, wifi_access_points_.size());
+  EXPECT_EQ("02:00:00:00:00:00", wifi_access_points_[1].mac_address);
+  EXPECT_EQ(1, wifi_access_points_[0].channel);
+
+  ASSERT_EQ(2u, cell_towers_.size());
+  EXPECT_EQ("2", cell_towers_[1].ci);
+  EXPECT_EQ("10", cell_towers_[0].lac);
+  EXPECT_EQ("200", cell_towers_[1].mcc);
+  EXPECT_EQ("101", cell_towers_[0].mnc);
+}
+
 }  // namespace chromeos
diff --git a/chromeos/network/network_util.cc b/chromeos/network/network_util.cc
index 8968d84..9d08c59 100644
--- a/chromeos/network/network_util.cc
+++ b/chromeos/network/network_util.cc
@@ -36,6 +36,12 @@
 WifiAccessPoint::~WifiAccessPoint() {
 }
 
+CellTower::CellTower() {}
+
+CellTower::CellTower(const CellTower& other) = default;
+
+CellTower::~CellTower() {}
+
 CellularScanResult::CellularScanResult() {
 }
 
diff --git a/chromeos/network/network_util.h b/chromeos/network/network_util.h
index 37b1302..930f78d 100644
--- a/chromeos/network/network_util.h
+++ b/chromeos/network/network_util.h
@@ -43,6 +43,20 @@
   int channel;  // Wifi channel number.
 };
 
+// Struct for passing cellular location data
+// The age, signalStrength, and timingAdvance fields are currently unused:
+// https://developers.google.com/maps/documentation/geolocation/intro#cell_tower_object
+struct CHROMEOS_EXPORT CellTower {
+  CellTower();
+  CellTower(const CellTower& other);
+  ~CellTower();
+  std::string mcc;       // The mobile country code if available
+  std::string mnc;       // The mobile network code if available
+  std::string lac;       // The location area code if available
+  std::string ci;        // The cell id if availabe
+  base::Time timestamp;  // Timestamp when this location was detected.
+};
+
 // Struct for passing network scan result data.
 struct CHROMEOS_EXPORT CellularScanResult {
   CellularScanResult();
@@ -57,6 +71,7 @@
 };
 
 typedef std::vector<WifiAccessPoint> WifiAccessPointVector;
+typedef std::vector<CellTower> CellTowerVector;
 
 // Describes whether there is an error and whether the error came from
 // the local system or from the server implementing the connect
diff --git a/chromeos/timezone/timezone_resolver.cc b/chromeos/timezone/timezone_resolver.cc
index 28790c30..68795f8 100644
--- a/chromeos/timezone/timezone_resolver.cc
+++ b/chromeos/timezone/timezone_resolver.cc
@@ -119,10 +119,14 @@
   base::WeakPtr<TimeZoneResolver::TimeZoneResolverImpl> AsWeakPtr();
 
   bool ShouldSendWiFiGeolocationData();
+  bool ShouldSendCellularGeolocationData();
 
  private:
   const TimeZoneResolver* resolver_;
 
+  // Helper to check timezone detection policy against expected value
+  bool CheckTimezoneManagementSetting(int expected_policy_value);
+
   // Returns delay to next timezone update request
   base::TimeDelta CalculateNextInterval();
 
@@ -186,6 +190,7 @@
   resolver_->geolocation_provider()->RequestGeolocation(
       base::TimeDelta::FromSeconds(kRefreshTimeZoneTimeoutSeconds),
       resolver_->ShouldSendWiFiGeolocationData(),
+      resolver_->ShouldSendCellularGeolocationData(),
       base::Bind(&TZRequest::OnLocationResolved, AsWeakPtr()));
 }
 
@@ -373,6 +378,11 @@
   return resolver_->ShouldSendWiFiGeolocationData();
 }
 
+bool TimeZoneResolver::TimeZoneResolverImpl::
+    ShouldSendCellularGeolocationData() {
+  return resolver_->ShouldSendCellularGeolocationData();
+}
+
 base::WeakPtr<TimeZoneResolver::TimeZoneResolverImpl>
 TimeZoneResolver::TimeZoneResolverImpl::AsWeakPtr() {
   return weak_ptr_factory_.GetWeakPtr();
@@ -440,4 +450,8 @@
   return delegate_->ShouldSendWiFiGeolocationData();
 }
 
+bool TimeZoneResolver::ShouldSendCellularGeolocationData() const {
+  return delegate_->ShouldSendCellularGeolocationData();
+}
+
 }  // namespace chromeos
diff --git a/chromeos/timezone/timezone_resolver.h b/chromeos/timezone/timezone_resolver.h
index 926179d7..c455f82 100644
--- a/chromeos/timezone/timezone_resolver.h
+++ b/chromeos/timezone/timezone_resolver.h
@@ -42,6 +42,9 @@
     // Returns true if TimeZoneResolver should include WiFi data in request.
     virtual bool ShouldSendWiFiGeolocationData() = 0;
 
+    // Returns true if TimeZoneResolver should include Cellular data in request.
+    virtual bool ShouldSendCellularGeolocationData() = 0;
+
    private:
     DISALLOW_COPY_AND_ASSIGN(Delegate);
   };
@@ -82,6 +85,9 @@
   // Proxy call to Delegate::ShouldSendWiFiGeolocationData().
   bool ShouldSendWiFiGeolocationData() const;
 
+  // Proxy call to Delegate::ShouldSendCellularGeolocationData().
+  bool ShouldSendCellularGeolocationData() const;
+
   // Expose internal fuctions for testing.
   static int MaxRequestsCountForIntervalForTesting(
       const double interval_seconds);
diff --git a/components/autofill/content/common/autofill_driver.mojom b/components/autofill/content/common/autofill_driver.mojom
index 1c951db..ce08780 100644
--- a/components/autofill/content/common/autofill_driver.mojom
+++ b/components/autofill/content/common/autofill_driver.mojom
@@ -61,11 +61,6 @@
 // There is one instance of this interface per render frame host in the browser
 // process.
 interface PasswordManagerDriver {
-  // A ping to the browser that PasswordAutofillAgent was constructed. As a
-  // consequence, the browser sends SetLoggingState with the current
-  // state of the logging activity.
-  PasswordAutofillAgentConstructed();
-
   // Notification that password forms have been seen that are candidates for
   // filling/submitting by the password manager.
   PasswordFormsParsed(array<PasswordForm> forms);
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index c0f4472bf..8eabb52 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -576,7 +576,6 @@
   // PasswordAutofillAgent is guaranteed to outlive |render_frame|.
   render_frame->GetInterfaceRegistry()->AddInterface(
       base::Bind(&PasswordAutofillAgent::BindRequest, base::Unretained(this)));
-  GetPasswordManagerDriver()->PasswordAutofillAgentConstructed();
 }
 
 PasswordAutofillAgent::~PasswordAutofillAgent() {
diff --git a/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
index 0c514e8f..85958d4f 100644
--- a/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
+++ b/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
@@ -64,8 +64,6 @@
   void ShowNotSecureWarning(base::i18n::TextDirection text_direction,
                             const gfx::RectF& bounds) override {}
 
-  void PasswordAutofillAgentConstructed() override {}
-
   void RecordSavePasswordProgress(const std::string& log) override {
     called_record_save_ = true;
     log_ = log;
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 1df2be2..ef832bd9 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -356,6 +356,7 @@
     "//components/sync:test_support_driver",
     "//components/sync:test_support_model",
     "//components/variations",
+    "//components/variations:test_support",
     "//components/webdata/common",
     "//components/webdata_services:test_support",
     "//google_apis",
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc
index 777b963..3b40471 100644
--- a/components/autofill/core/browser/autofill_experiments.cc
+++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -30,16 +30,20 @@
     "AutofillScanCardholderName", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kAutofillCreditCardPopupLayout{
     "AutofillCreditCardPopupLayout", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillCreditCardLastUsedDateDisplay{
+    "AutofillCreditCardLastUsedDateDisplay", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit";
 const char kAutofillCreditCardPopupBackgroundColorKey[] = "background_color";
 const char kAutofillCreditCardPopupDividerColorKey[] = "dropdown_divider_color";
 const char kAutofillCreditCardPopupValueBoldKey[] = "is_value_bold";
 const char kAutofillCreditCardPopupIsValueAndLabelInSingleLineKey[] =
     "is_value_and_label_in_single_line";
-const char kAutofillPopupDropdownItemHeightKey[] =
-    "dropdown_item_height";
+const char kAutofillPopupDropdownItemHeightKey[] = "dropdown_item_height";
 const char kAutofillCreditCardPopupIsIconAtStartKey[] =
     "is_credit_card_icon_at_start";
 const char kAutofillPopupMarginKey[] = "margin";
+const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[] =
+    "show_expiration_date";
 
 namespace {
 
@@ -79,6 +83,10 @@
   return base::FeatureList::IsEnabled(kAutofillCreditCardPopupLayout);
 }
 
+bool IsAutofillCreditCardLastUsedDateDisplayExperimentEnabled() {
+  return base::FeatureList::IsEnabled(kAutofillCreditCardLastUsedDateDisplay);
+}
+
 // |GetCreditCardPopupParameterUintValue| returns 0 if experiment parameter is
 // not specified. 0 == |SK_ColorTRANSPARENT|.
 SkColor GetCreditCardPopupBackgroundColor() {
@@ -108,6 +116,13 @@
   return param_value == "true";
 }
 
+bool ShowExpirationDateInAutofillCreditCardLastUsedDate() {
+  const std::string param_value = variations::GetVariationParamValueByFeature(
+      kAutofillCreditCardLastUsedDateDisplay,
+      kAutofillCreditCardLastUsedDateShowExpirationDateKey);
+  return param_value == "true";
+}
+
 // Modifies |suggestion| as follows if experiment to display value and label in
 // a single line is enabled.
 // Say, |value| is 'Visa ....1111' and |label| is '01/18' (expiration date).
diff --git a/components/autofill/core/browser/autofill_experiments.h b/components/autofill/core/browser/autofill_experiments.h
index c218b742..4f9a86a 100644
--- a/components/autofill/core/browser/autofill_experiments.h
+++ b/components/autofill/core/browser/autofill_experiments.h
@@ -27,8 +27,10 @@
 extern const base::Feature kAutofillCreditCardAssist;
 extern const base::Feature kAutofillScanCardholderName;
 extern const base::Feature kAutofillCreditCardPopupLayout;
+extern const base::Feature kAutofillCreditCardLastUsedDateDisplay;
 extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
 extern const char kAutofillCreditCardPopupSettingsSuggestionValueKey[];
+extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[];
 
 // Returns true if autofill should be enabled. See also
 // IsInAutofillSuggestionsDisabledExperiment below.
@@ -59,6 +61,13 @@
 // enabled.
 bool IsAutofillCreditCardPopupLayoutExperimentEnabled();
 
+// Returns whether Autofill credit card last used date display experiment is
+// enabled.
+bool IsAutofillCreditCardLastUsedDateDisplayExperimentEnabled();
+
+// Returns whether Autofill credit card last used date shows expiration date.
+bool ShowExpirationDateInAutofillCreditCardLastUsedDate();
+
 // Returns the background color for credit card autofill popup, or
 // |SK_ColorTRANSPARENT| if the new credit card autofill popup layout experiment
 // is not enabled.
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index 5b002bc..9bd3ed7 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -12,6 +12,7 @@
 #include <string>
 
 #include "base/guid.h"
+#include "base/i18n/time_formatting.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
@@ -23,6 +24,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/autofill_field.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/validation.h"
@@ -49,6 +51,9 @@
 namespace {
 
 const base::char16 kCreditCardObfuscationSymbol = '*';
+// Time format pattern for short month name (3 digits) and day in month (2
+// digits), e.g. in en-US locale, it can be used to generate "Feb 02".
+const char kTimeFormatPatternNoYearShortMonthDate[] = "MMMdd";
 
 bool ConvertYear(const base::string16& year, int* num) {
   // If the |year| is empty, clear the stored value.
@@ -537,6 +542,55 @@
   set_origin(credit_card.origin());
 }
 
+base::string16 CreditCard::GetLastUsedDateForDisplay(
+    const std::string& app_locale) const {
+  bool show_expiration_date =
+      ShowExpirationDateInAutofillCreditCardLastUsedDate();
+
+  DCHECK(use_count() > 0);
+  // use_count() is initialized as 1 when the card is just added.
+  if (use_count() == 1) {
+    return show_expiration_date
+               ? l10n_util::GetStringFUTF16(
+                     IDS_AUTOFILL_CREDIT_CARD_EXP_AND_ADDED_DATE,
+                     GetInfo(AutofillType(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR),
+                             app_locale),
+                     base::TimeFormatWithPattern(
+                         use_date(), kTimeFormatPatternNoYearShortMonthDate))
+               : l10n_util::GetStringFUTF16(
+                     IDS_AUTOFILL_CREDIT_CARD_ADDED_DATE,
+                     base::TimeFormatWithPattern(
+                         use_date(), kTimeFormatPatternNoYearShortMonthDate));
+  }
+
+  // use_count() > 1 when the card has been used in autofill.
+
+  // If the card was last used in autofill more than a year ago,
+  // display "last used > 1 year ago" without showing date detail.
+  if ((AutofillClock::Now() - use_date()).InDays() > 365) {
+    return show_expiration_date
+               ? l10n_util::GetStringFUTF16(
+                     IDS_AUTOFILL_CREDIT_CARD_EXP_AND_LAST_USED_YEAR_AGO,
+                     GetInfo(AutofillType(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR),
+                             app_locale))
+               : l10n_util::GetStringUTF16(
+                     IDS_AUTOFILL_CREDIT_CARD_LAST_USED_YEAR_AGO);
+  }
+
+  // If the card was last used in autofill within a year, show date information.
+  return show_expiration_date
+             ? l10n_util::GetStringFUTF16(
+                   IDS_AUTOFILL_CREDIT_CARD_EXP_AND_LAST_USED_DATE,
+                   GetInfo(AutofillType(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR),
+                           app_locale),
+                   base::TimeFormatWithPattern(
+                       use_date(), kTimeFormatPatternNoYearShortMonthDate))
+             : l10n_util::GetStringFUTF16(
+                   IDS_AUTOFILL_CREDIT_CARD_LAST_USED_DATE,
+                   base::TimeFormatWithPattern(
+                       use_date(), kTimeFormatPatternNoYearShortMonthDate));
+}
+
 bool CreditCard::UpdateFromImportedCard(const CreditCard& imported_card,
                                         const std::string& app_locale) {
   if (this->GetInfo(AutofillType(CREDIT_CARD_NUMBER), app_locale) !=
diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h
index 47d06f18..0fb251e9 100644
--- a/components/autofill/core/browser/credit_card.h
+++ b/components/autofill/core/browser/credit_card.h
@@ -174,6 +174,9 @@
   // Sets |number_| to |number| and computes the appropriate card |type_|.
   void SetNumber(const base::string16& number);
 
+  // Returns the date when the credit card was last used in autofill.
+  base::string16 GetLastUsedDateForDisplay(const std::string& app_locale) const;
+
   // Logs the number of days since the credit card was last used and records its
   // use.
   void RecordAndLogUse();
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc
index de26d8e5..81f2b88 100644
--- a/components/autofill/core/browser/credit_card_unittest.cc
+++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -10,12 +10,14 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/form_field_data.h"
+#include "components/variations/variations_params_manager.h"
 #include "grit/components_scaled_resources.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -887,4 +889,72 @@
   }
 }
 
+// Test that credit card last used date suggestion can be generated correctly
+// in different variations.
+TEST(CreditCardTest, GetLastUsedDateForDisplay) {
+  const base::Time::Exploded kTestDateTimeExploded = {
+      2016, 12, 6, 10,  // Sat, Dec 10, 2016
+      15,   42, 7, 0    // 15:42:07.000
+  };
+  base::Time kArbitraryTime;
+  EXPECT_TRUE(
+      base::Time::FromLocalExploded(kTestDateTimeExploded, &kArbitraryTime));
+
+  // Test for added to chrome/chromium.
+  CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+  credit_card0.set_use_count(1);
+  credit_card0.set_use_date(kArbitraryTime - base::TimeDelta::FromDays(1));
+  test::SetCreditCardInfo(&credit_card0, "John Dillinger",
+                          "423456789012" /* Visa */, "01", "2021");
+
+  // Test for last used date.
+  CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+  test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
+                          "347666888555" /* American Express */, "04", "2021");
+  credit_card1.set_use_count(10);
+  credit_card1.set_use_date(kArbitraryTime - base::TimeDelta::FromDays(10));
+
+  // Test for last used more than one year ago.
+  CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+  credit_card2.set_use_count(5);
+  credit_card2.set_use_date(kArbitraryTime - base::TimeDelta::FromDays(366));
+  test::SetCreditCardInfo(&credit_card2, "Bonnie Parker",
+                          "518765432109" /* Mastercard */, "12", "2021");
+
+  static const struct {
+    const char* show_expiration_date;
+    const std::string& app_locale;
+    base::string16 added_to_autofill_date;
+    base::string16 last_used_date;
+    base::string16 last_used_year_ago;
+  } kTestCases[] = {
+      // only show last used date.
+      {"false", "en_US", ASCIIToUTF16("Added: Dec 09"),
+       ASCIIToUTF16("Last used: Nov 30"),
+       ASCIIToUTF16("Last used over a year ago")},
+      // show expiration date and last used date.
+      {"true", "en_US", ASCIIToUTF16("Exp: 01/21, added: Dec 09"),
+       ASCIIToUTF16("Exp: 04/21, last used: Nov 30"),
+       ASCIIToUTF16("Exp: 12/21, last used over a year ago")},
+  };
+
+  variations::testing::VariationParamsManager variation_params_;
+
+  for (const auto& test_case : kTestCases) {
+    variation_params_.SetVariationParamsWithFeatureAssociations(
+        kAutofillCreditCardLastUsedDateDisplay.name,
+        {{kAutofillCreditCardLastUsedDateShowExpirationDateKey,
+          test_case.show_expiration_date}},
+        {kAutofillCreditCardLastUsedDateDisplay.name});
+
+    EXPECT_EQ(test_case.added_to_autofill_date,
+              credit_card0.GetLastUsedDateForDisplay(test_case.app_locale));
+    EXPECT_EQ(test_case.last_used_date,
+              credit_card1.GetLastUsedDateForDisplay(test_case.app_locale));
+    EXPECT_EQ(test_case.last_used_year_ago,
+              credit_card2.GetLastUsedDateForDisplay(test_case.app_locale));
+    variation_params_.ClearAllVariationParams();
+  }
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index eff7020b..5cc15a1e 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1607,8 +1607,13 @@
       // cardholder name. The label should never repeat the value.
       if (type.GetStorableType() == CREDIT_CARD_NUMBER) {
         suggestion->value = credit_card->TypeAndLastFourDigits();
-        suggestion->label = credit_card->GetInfo(
-            AutofillType(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR), app_locale_);
+        if (IsAutofillCreditCardLastUsedDateDisplayExperimentEnabled()) {
+          suggestion->label =
+              credit_card->GetLastUsedDateForDisplay(app_locale_);
+        } else {
+          suggestion->label = credit_card->GetInfo(
+              AutofillType(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR), app_locale_);
+        }
         if (IsAutofillCreditCardPopupLayoutExperimentEnabled())
           ModifyAutofillCreditCardSuggestion(suggestion);
       } else if (credit_card->number().empty()) {
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 0ad52758..dc84546 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -17,8 +17,8 @@
 #include "base/command_line.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/guid.h"
+#include "base/i18n/time_formatting.h"
 #include "base/memory/ptr_util.h"
-#include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
@@ -48,8 +48,7 @@
 #include "components/signin/core/browser/fake_signin_manager.h"
 #include "components/signin/core/browser/test_signin_client.h"
 #include "components/signin/core/common/signin_pref_names.h"
-#include "components/variations/entropy_provider.h"
-#include "components/variations/variations_associated_data.h"
+#include "components/variations/variations_params_manager.h"
 #include "components/webdata/common/web_data_service_base.h"
 #include "components/webdata/common/web_database_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -154,9 +153,6 @@
     test::DisableSystemServices(prefs_.get());
     ResetPersonalDataManager(USER_MODE_NORMAL);
 
-    // There are no field trials enabled by default.
-    field_trial_list_.reset();
-
     // Reset the deduping pref to its default value.
     personal_data_->pref_service_->SetInteger(
         prefs::kAutofillLastVersionDeduped, 0);
@@ -313,28 +309,6 @@
                                             imported_credit_card);
   }
 
-  // Sets up the profile order field trial group and parameter. Sets up the
-  // suggestions limit parameter to |limit_param|.
-  void EnableAutofillProfileLimitFieldTrial(const std::string& limit_param) {
-    DCHECK(!limit_param.empty());
-
-    // Clear the existing |field_trial_list_| and variation parameters.
-    field_trial_list_.reset(NULL);
-    field_trial_list_.reset(
-        new base::FieldTrialList(
-            base::MakeUnique<metrics::SHA1EntropyProvider>("foo")));
-    variations::testing::ClearAllVariationParams();
-
-    std::map<std::string, std::string> params;
-    params[kFrecencyFieldTrialLimitParam] = limit_param;
-    variations::AssociateVariationParams(kFrecencyFieldTrialName, "LimitToN",
-                                         params);
-
-    field_trial_ = base::FieldTrialList::CreateFieldTrial(
-        kFrecencyFieldTrialName, "LimitToN");
-    field_trial_->group();
-  }
-
   void SubmitFormAndExpectImportedCardWithData(const FormData& form,
                                                const char* exp_name,
                                                const char* exp_cc_num,
@@ -374,8 +348,7 @@
   PersonalDataLoadedObserverMock personal_data_observer_;
   std::unique_ptr<PersonalDataManager> personal_data_;
 
-  std::unique_ptr<base::FieldTrialList> field_trial_list_;
-  scoped_refptr<base::FieldTrial> field_trial_;
+  variations::testing::VariationParamsManager variation_params_;
 };
 
 TEST_F(PersonalDataManagerTest, AddProfile) {
@@ -3456,7 +3429,8 @@
   EXPECT_EQ(3U, suggestions.size());
 
   // Verify that only two profiles are suggested.
-  EnableAutofillProfileLimitFieldTrial("2");
+  variation_params_.SetVariationParams(kFrecencyFieldTrialName,
+                                       {{kFrecencyFieldTrialLimitParam, "2"}});
 
   suggestions = personal_data_->GetProfileSuggestions(
       AutofillType(NAME_FIRST), base::string16(), false,
@@ -3469,7 +3443,8 @@
 // than three profiles.
 TEST_F(PersonalDataManagerTest,
        GetProfileSuggestions_LimitIsMoreThanProfileSuggestions) {
-  EnableAutofillProfileLimitFieldTrial("3");
+  variation_params_.SetVariationParams(kFrecencyFieldTrialName,
+                                       {{kFrecencyFieldTrialLimitParam, "3"}});
 
   // Set up 2 different profiles.
   AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp
index 018f5cae..9c955dd2 100644
--- a/components/autofill_strings.grdp
+++ b/components/autofill_strings.grdp
@@ -211,14 +211,39 @@
     Pay quickly on sites and apps across devices using cards you have saved with Google.
   </message>
 
+  <!-- Autofill credit card suggestion popup -->
   <message name="IDS_AUTOFILL_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]">
     Exp: <ph name="EXPIRATION_MONTH">$1<ex>06</ex></ph>/<ph name="EXPIRATION_YEAR">$2<ex>17</ex></ph>
   </message>
 
-  <message name="IDS_AUTOFILL_CREDIT_CARD_EXPIRATION_DATE_LABEL_AND_ABBR" desc="text displayed in the Autofill Credit Card popup before the credit card expiration date and the abbreviated expiration date.">
+  <message name="IDS_AUTOFILL_CREDIT_CARD_EXPIRATION_DATE_LABEL_AND_ABBR" desc="Text displayed in the Autofill Credit Card popup before the credit card expiration date and the abbreviated expiration date.">
     , exp <ph name="EXPIRATION_DATE_ABBR">$1<ex>06/17</ex></ph>
   </message>
 
+  <message name="IDS_AUTOFILL_CREDIT_CARD_EXP_AND_LAST_USED_DATE" desc="Text displayed in the Autofill Credit Card popup to indicate the credit card expiration date and the date when this card was last used.">
+    Exp: <ph name="EXPIRATION_DATE_ABBR">$1<ex>06/17</ex></ph>, last used: <ph name="LAST_USED_DATE_NO_DETAIL">$2<ex>Jan 10</ex></ph>
+  </message>
+
+  <message name="IDS_AUTOFILL_CREDIT_CARD_LAST_USED_DATE" desc="Text displayed in the Autofill Credit Card popup to indicate the date when this card was last used.">
+    Last used: <ph name="LAST_USED_MONTH">$1<ex>Jan 10</ex></ph>
+  </message>
+
+  <message name="IDS_AUTOFILL_CREDIT_CARD_EXP_AND_ADDED_DATE" desc="Text displayed in the Autofill Credit Card popup to indicate the credit card expiration date and the date when this card was added to autofill.">
+    Exp: <ph name="EXPIRATION_DATE_ABBR">$1<ex>06/17</ex></ph>, added: <ph name="ADDED_TO_AUTOFILL_MONTH">$2<ex>Jan 10</ex></ph>
+  </message>
+
+  <message name="IDS_AUTOFILL_CREDIT_CARD_ADDED_DATE" desc="Text displayed in the Autofill Credit Card popup to indicate the date when this card was added to autofill.">
+    Added: <ph name="ADDED_TO_AUTOFILL_MONTH">$1<ex>Jan 10</ex></ph>
+  </message>
+
+  <message name="IDS_AUTOFILL_CREDIT_CARD_EXP_AND_LAST_USED_YEAR_AGO" desc="Text displayed in the Autofill Credit Card popup to indicate the credit card expiration date and this card was used in autofill more than a year ago.">
+    Exp: <ph name="EXPIRATION_DATE_ABBR">$1<ex>06/17</ex></ph>, last used over a year ago
+  </message>
+
+  <message name="IDS_AUTOFILL_CREDIT_CARD_LAST_USED_YEAR_AGO" desc="Text displayed in the Autofill Credit Card popup to indicate this card was used in autofill more than a year ago.">
+    Last used over a year ago
+  </message>
+
   <!-- Autofill credit card unmask prompt -->
   <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN_CVC" desc="Error message that encourages the user to try to re-enter their credit card CVC after a previous failed attempt." formatter_data="android_java">
     Check your CVC and try again
diff --git a/components/browser_watcher/exit_code_watcher_win_unittest.cc b/components/browser_watcher/exit_code_watcher_win_unittest.cc
index 4c2c1d9..9c1a074 100644
--- a/components/browser_watcher/exit_code_watcher_win_unittest.cc
+++ b/components/browser_watcher/exit_code_watcher_win_unittest.cc
@@ -85,7 +85,8 @@
   void SetUp() override {
     Super::SetUp();
 
-    override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
   }
 
   base::Process OpenSelfWithAccess(uint32_t access) {
diff --git a/components/browser_watcher/watcher_metrics_provider_win_unittest.cc b/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
index f126bbf..fbce251 100644
--- a/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
+++ b/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
@@ -34,7 +34,8 @@
   void SetUp() override {
     Super::SetUp();
 
-    override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
     test_task_runner_ = new base::TestSimpleTaskRunner();
   }
 
diff --git a/components/cdm/OWNERS b/components/cdm/OWNERS
index 554a4be..5ef846a 100644
--- a/components/cdm/OWNERS
+++ b/components/cdm/OWNERS
@@ -1,2 +1,4 @@
 ddorwin@chromium.org
 xhwang@chromium.org
+
+# COMPONENT: Internals>Media>Encrypted
diff --git a/components/components_chromium_strings.grd b/components/components_chromium_strings.grd
index 7eee274..87be555 100644
--- a/components/components_chromium_strings.grd
+++ b/components/components_chromium_strings.grd
@@ -210,7 +210,7 @@
 
       <!-- Page Info bubble -->
       <message name="IDS_PAGE_INFO_INTERNAL_PAGE" desc="Message to display in the page info bubble when the page you are on is a chrome:// page or about:something.">
-        You are viewing a secure Chromium page.
+        You're viewing a secure Chromium page
       </message>
 
       <message name="IDS_SESSION_CRASHED_VIEW_MESSAGE" desc="Message shown when the last session didn't exit cleanly.">
diff --git a/components/components_google_chrome_strings.grd b/components/components_google_chrome_strings.grd
index 4033f6e..be9a51a7 100644
--- a/components/components_google_chrome_strings.grd
+++ b/components/components_google_chrome_strings.grd
@@ -210,13 +210,13 @@
 
       <!-- Page Info bubble -->
       <message name="IDS_PAGE_INFO_INTERNAL_PAGE" desc="Message to display in the page info bubble when the page you are on is a chrome:// page or about:something.">
-        You are viewing a secure Google Chrome page.
+        You're viewing a secure Google Chrome page
       </message>
 
       <message name="IDS_SESSION_CRASHED_VIEW_MESSAGE" desc="Message shown when the last session didn't exit cleanly.">
         Chrome didn't shut down correctly.
       </message>
-      
+
       <!-- Strings describing Chrome security policy for DevTools security panel -->
       <message name="IDS_PRIVATE_USER_DATA_INPUT_FUTURE_DESCRIPTION" desc="Description of a security problem where the site collects private user data on an insecure page, which will result in an omnibox warning in future versions of Chrome." translateable="false">
         This page includes a password or credit card input over HTTP. A warning will appear in the URL bar starting in Chrome 56 (Jan 2017).
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index d9f1c7b3..91bbf4b2 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -948,6 +948,7 @@
     "//components/metrics",
     "//net",
     "//net:test_support",
+    "//net/android:net_java",
     "//testing/gtest",
   ]
 
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn
index a449ceba..e455f652 100644
--- a/components/cronet/ios/BUILD.gn
+++ b/components/cronet/ios/BUILD.gn
@@ -227,8 +227,41 @@
     ]
   }
 
+  if (enable_dsyms) {
+    action("cronet_dsym_archive") {
+      script = "//chrome/tools/build/mac/archive_symbols.py"
+
+      # These are the dSYMs that will be archived. The sources list must be
+      # the target outputs that correspond to the dSYMs (since a dSYM is a
+      # directory it cannot be listed as a source file). The targets that
+      # generate both the dSYM and binary image are listed in deps.
+      _dsyms = [ "$root_out_dir/Cronet.dSYM" ]
+
+      sources = [
+        "$root_out_dir/Cronet.framework",
+      ]
+
+      _output = "$_package_dir/Cronet.dSYM.tar.bz2"
+
+      outputs = [
+        _output,
+      ]
+
+      args = [ rebase_path(_output, root_out_dir) ] +
+             rebase_path(_dsyms, root_out_dir)
+
+      deps = [
+        ":cronet_framework",
+      ]
+    }
+  } else {
+    group("cronet_dsym_archive") {
+    }
+  }
+
   group("cronet_package") {
     deps = [
+      ":cronet_dsym_archive",
       ":cronet_package_copy",
       ":generate_license",
     ]
diff --git a/components/cronet/stale_host_resolver_unittest.cc b/components/cronet/stale_host_resolver_unittest.cc
index 75b51c4..9c1685e 100644
--- a/components/cronet/stale_host_resolver_unittest.cc
+++ b/components/cronet/stale_host_resolver_unittest.cc
@@ -14,7 +14,9 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
 #include "components/cronet/url_request_context_config.h"
+#include "net/android/network_change_notifier_factory_android.h"
 #include "net/base/net_errors.h"
+#include "net/base/network_change_notifier.h"
 #include "net/cert/cert_verifier.h"
 #include "net/dns/host_resolver_proc.h"
 #include "net/http/http_network_session.h"
@@ -135,6 +137,12 @@
     resolver_ = nullptr;
   }
 
+  void CreateNetworkChangeNotifier() {
+    net::NetworkChangeNotifier::SetFactory(
+        new net::NetworkChangeNotifierFactoryAndroid());
+    net::NetworkChangeNotifier::Create();
+  }
+
   // Creates a cache entry for |kHostname| that is |age_sec| seconds old.
   void CreateCacheEntry(int age_sec) {
     DCHECK(resolver_);
@@ -149,10 +157,8 @@
   }
 
   void OnNetworkChange() {
-    DCHECK(resolver_);
-    DCHECK(resolver_->GetHostCache());
-
-    resolver_->GetHostCache()->OnNetworkChange();
+    net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
+    base::RunLoop().RunUntilIdle();  // Wait for notification.
   }
 
   void LookupStale() {
@@ -400,6 +406,7 @@
   };
 
   SetStaleDelay(kNoStaleDelaySec);
+  CreateNetworkChangeNotifier();
 
   for (size_t i = 0; i < arraysize(kUsabilityTestCases); ++i) {
     const auto& test_case = kUsabilityTestCases[i];
diff --git a/components/google/OWNERS b/components/google/OWNERS
index 2c1c5e2..558e550 100644
--- a/components/google/OWNERS
+++ b/components/google/OWNERS
@@ -1,2 +1,4 @@
 isherman@chromium.org
-pkasting@chromium.org
\ No newline at end of file
+pkasting@chromium.org
+
+# COMPONENT: Internals
diff --git a/components/infobars/OWNERS b/components/infobars/OWNERS
index bf426d6..550d854f 100644
--- a/components/infobars/OWNERS
+++ b/components/infobars/OWNERS
@@ -1 +1,3 @@
 pkasting@chromium.org
+
+# COMPONENT: UI>Browser>Infobars
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 03fdf1e..6b476a64 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -144,6 +144,7 @@
     GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID = 70,
     OFFLINE_PAGE_INFOBAR_DELEGATE = 71,
     SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_DELEGATE = 72,
+    AUTOMATION_INFOBAR_DELEGATE = 73,
   };
 
   // Describes navigation events, used to decide whether infobars should be
diff --git a/components/metrics/proto/omnibox_event.proto b/components/metrics/proto/omnibox_event.proto
index ea002f54..0410d6cc 100644
--- a/components/metrics/proto/omnibox_event.proto
+++ b/components/metrics/proto/omnibox_event.proto
@@ -171,9 +171,9 @@
     // This enum value is currently only used by Android GSA. It represents
     // a suggestion powered by a Chrome content provider.
     ON_DEVICE_CHROME = 13;
-    CLIPBOARD_URL = 14;  // Suggestion coming from clipboard (iOS only).
+    CLIPBOARD_URL = 14;    // Suggestion coming from clipboard (iOS only).
     PHYSICAL_WEB = 15;     // Suggestions triggered by URLs broadcast by nearby
-                           // devices (iOS only).
+                           // devices (iOS and Android).
   }
 
   // The result set displayed on the completion popup
@@ -206,7 +206,8 @@
       EXTENSION_APP = 11;         // DEPRECATED. An Extension App with a
                                   // title/url that contains the input.
       CONTACT = 12;               // One of the user's contacts
-      BOOKMARK_TITLE = 13;        // A bookmark whose title contains the input.
+      BOOKMARK_TITLE = 13;        // A bookmark with a title/url that contains
+                                  // the input.
       SEARCH_SUGGEST_ENTITY = 14; // A suggested search for an entity.
       SEARCH_SUGGEST_TAIL = 15;   // A suggested search to complete the tail
                                   // of the query.
diff --git a/components/metrics/proto/translate_event.proto b/components/metrics/proto/translate_event.proto
index 8bba508a..94ae6ec 100644
--- a/components/metrics/proto/translate_event.proto
+++ b/components/metrics/proto/translate_event.proto
@@ -16,7 +16,7 @@
 // the Translate UI. Contains features used by Translate Ranker for
 // inference, information about the ranker model and its decision, as
 // well as user or automated feedback from the Translate UI.
-// Next tag: 14
+// Next tag: 15
 message TranslateEventProto {
   // Language strings are two or three letter codes, with sometimes an extra
   // suffix (for e.g. chinese zh-TW or zh-CN). See
@@ -27,6 +27,10 @@
   // Target language of the translation.
   optional string target_language = 2;
 
+  // The country where the user is. 2-letter country code. This
+  // corresponds to the stored permanent country in VariationsService.
+  optional string country = 14;
+
   // The following counts are extracted from TranslatePrefs.
   // The number of times the user accepted a translation for the
   // source language.
diff --git a/components/omnibox/OWNERS b/components/omnibox/OWNERS
index a659a21..52130b8 100644
--- a/components/omnibox/OWNERS
+++ b/components/omnibox/OWNERS
@@ -2,3 +2,5 @@
 mpearson@chromium.org
 
 per-file clipboard_url_provider.*=jif@chromium.org
+
+# COMPONENT: UI>Browser>Omnibox
diff --git a/components/omnibox/browser/autocomplete_provider.h b/components/omnibox/browser/autocomplete_provider.h
index 35cc538..370c3b5 100644
--- a/components/omnibox/browser/autocomplete_provider.h
+++ b/components/omnibox/browser/autocomplete_provider.h
@@ -34,6 +34,13 @@
 // below may have some utility, nothing compares with first-hand
 // investigation and experience.
 //
+// ZERO SUGGEST (empty) input type:
+// --------------------------------------------------------------------|-----
+// Clipboard URL                                                       |  800
+// Physical Web (zero suggest)                                         |  700--
+// Zero Suggest (most visited, Android only)                           |  600--
+// Zero Suggest (default, may be overridden by server)                 |  100
+//
 // UNKNOWN input type:
 // --------------------------------------------------------------------|-----
 // Keyword (non-substituting or in keyword UI mode, exact match)       | 1500
@@ -43,15 +50,16 @@
 // Search Primary Provider (what you typed)                            | 1300
 // HistoryURL (what you typed, some inexact matches)                   | 1200++
 // Keyword (substituting, exact match)                                 | 1100
-// Search Primary Provider (past query in history older than 2 days)   | 1050--
+// Search Primary Provider (past query in history older than 2 days)   | 1050*
 // HistoryURL (some inexact matches)                                   |  900++
-// BookmarkProvider (prefix match in bookmark title)                   |  900+-
+// BookmarkProvider (prefix match in bookmark title or URL)            |  900+-
 // Built-in                                                            |  860++
 // Search Primary Provider (navigational suggestion)                   |  800++
+// Physical Web (prefix match in page title or URL)                    |  700--
 // Search Primary Provider (suggestion)                                |  600++
 // Keyword (inexact match)                                             |  450
 // Search Secondary Provider (what you typed)                          |  250
-// Search Secondary Provider (past query in history)                   |  200--
+// Search Secondary Provider (past query in history)                   |  200*
 // Search Secondary Provider (navigational suggestion)                 |  150++
 // Search Secondary Provider (suggestion)                              |  100++
 //
@@ -66,11 +74,11 @@
 // Built-in                                                            |  860++
 // Search Primary Provider (what you typed)                            |  850
 // Search Primary Provider (navigational suggestion)                   |  800++
-// Search Primary Provider (past query in history)                     |  750--
+// Search Primary Provider (past query in history)                     |  750*
 // Keyword (inexact match)                                             |  700
 // Search Primary Provider (suggestion)                                |  300++
 // Search Secondary Provider (what you typed)                          |  250
-// Search Secondary Provider (past query in history)                   |  200--
+// Search Secondary Provider (past query in history)                   |  200*
 // Search Secondary Provider (navigational suggestion)                 |  150++
 // Search Secondary Provider (suggestion)                              |  100++
 //
@@ -81,14 +89,15 @@
 // Keyword (substituting, exact match)                                 | 1450
 // Search Primary Provider (past query in history within 2 days)       | 1399**
 // Search Primary Provider (what you typed)                            | 1300
-// Search Primary Provider (past query in history older than 2 days)   | 1050--
+// Search Primary Provider (past query in history older than 2 days)   | 1050*
 // HistoryURL (inexact match)                                          |  900++
-// BookmarkProvider (prefix match in bookmark title)                   |  900+-
+// BookmarkProvider (prefix match in bookmark title or URL)            |  900+-
 // Search Primary Provider (navigational suggestion)                   |  800++
+// Physical Web (prefix match in page title or URL)                    |  700--
 // Search Primary Provider (suggestion)                                |  600++
 // Keyword (inexact match)                                             |  450
 // Search Secondary Provider (what you typed)                          |  250
-// Search Secondary Provider (past query in history)                   |  200--
+// Search Secondary Provider (past query in history)                   |  200*
 // Search Secondary Provider (navigational suggestion)                 |  150++
 // Search Secondary Provider (suggestion)                              |  100++
 //
@@ -105,7 +114,8 @@
 //
 // The value column gives the ranking returned from the various providers.
 // ++: a series of matches with relevance from n up to (n + max_matches).
-// --: relevance score falls off over time (discounted 50 points @ 15 minutes,
+// --: a series of matches with relevance from n down to (n - max_matches).
+// *:  relevance score falls off over time (discounted 50 points @ 15 minutes,
 //     450 points @ two weeks)
 // **: relevance score falls off over two days (discounted 99 points after two
 //     days).
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc
index bdb9361..ebf591e 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -43,6 +43,19 @@
   // for this WebContents.
   VisiblePasswordObserver::CreateForWebContents(
       content::WebContents::FromRenderFrameHost(render_frame_host_));
+
+  // For some frames |this| may be instantiated before log manager creation, so
+  // here we can not send logging state to renderer process for them. For such
+  // cases, after the log manager got ready later,
+  // ContentPasswordManagerDriverFactory::RequestSendLoggingAvailability() will
+  // call ContentPasswordManagerDriver::SendLoggingAvailability() on |this| to
+  // do it actually.
+  if (client_->GetLogManager()) {
+    // Do not call the virtual method SendLoggingAvailability from a constructor
+    // here, inline its steps instead.
+    GetPasswordAutofillAgent()->SetLoggingState(
+        client_->GetLogManager()->IsLoggingActive());
+  }
 }
 
 ContentPasswordManagerDriver::~ContentPasswordManagerDriver() {
@@ -278,10 +291,6 @@
   password_autofill_manager_.OnShowNotSecureWarning(text_direction, bounds);
 }
 
-void ContentPasswordManagerDriver::PasswordAutofillAgentConstructed() {
-  SendLoggingAvailability();
-}
-
 void ContentPasswordManagerDriver::RecordSavePasswordProgress(
     const std::string& log) {
   client_->GetLogManager()->LogSavePasswordProgress(log);
diff --git a/components/password_manager/content/browser/content_password_manager_driver.h b/components/password_manager/content/browser/content_password_manager_driver.h
index b446835f..d7ddb70c 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/components/password_manager/content/browser/content_password_manager_driver.h
@@ -104,7 +104,6 @@
                                const gfx::RectF& bounds) override;
   void ShowNotSecureWarning(base::i18n::TextDirection text_direction,
                             const gfx::RectF& bounds) override;
-  void PasswordAutofillAgentConstructed() override;
   void RecordSavePasswordProgress(const std::string& log) override;
   void SaveGenerationFieldDetectedByClassifier(
       const autofill::PasswordForm& password_form,
diff --git a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index e26a14a..0606690 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -131,16 +131,14 @@
   FakePasswordAutofillAgent fake_agent_;
 };
 
-TEST_P(ContentPasswordManagerDriverTest,
-       AnswerToNotificationsAboutLoggingState) {
+TEST_P(ContentPasswordManagerDriverTest, SendLoggingStateInCtor) {
   const bool should_allow_logging = GetParam();
+  EXPECT_CALL(log_manager_, IsLoggingActive())
+      .WillRepeatedly(Return(should_allow_logging));
   std::unique_ptr<ContentPasswordManagerDriver> driver(
       new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
                                        &autofill_client_));
 
-  EXPECT_CALL(log_manager_, IsLoggingActive())
-      .WillRepeatedly(Return(should_allow_logging));
-  driver->SendLoggingAvailability();
   if (should_allow_logging) {
     bool logging_activated = false;
     EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_activated));
@@ -152,20 +150,22 @@
   }
 }
 
-TEST_P(ContentPasswordManagerDriverTest, AnswerToIPCPingsAboutLoggingState) {
+TEST_P(ContentPasswordManagerDriverTest, SendLoggingStateAfterLogManagerReady) {
   const bool should_allow_logging = GetParam();
+  EXPECT_CALL(password_manager_client_, GetLogManager())
+      .WillOnce(Return(nullptr));
   std::unique_ptr<ContentPasswordManagerDriver> driver(
       new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
                                        &autofill_client_));
+  // Because log manager is not ready yet, should have no logging state sent.
+  EXPECT_FALSE(WasLoggingActivationMessageSent(nullptr));
 
+  // Log manager is ready, send logging state actually.
+  EXPECT_CALL(password_manager_client_, GetLogManager())
+      .WillOnce(Return(&log_manager_));
   EXPECT_CALL(log_manager_, IsLoggingActive())
       .WillRepeatedly(Return(should_allow_logging));
   driver->SendLoggingAvailability();
-  WasLoggingActivationMessageSent(nullptr);
-
-  // Ping the driver for logging activity update.
-  driver->PasswordAutofillAgentConstructed();
-
   bool logging_activated = false;
   EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_activated));
   EXPECT_EQ(should_allow_logging, logging_activated);
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 134ba1d..4a92871 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -8849,7 +8849,7 @@
       'type': 'int-enum',
       'schema': {
         'type': 'integer',
-        'enum': [ 0, 1, 2, 3 ],
+        'enum': [ 0, 1, 2, 3, 4 ],
       },
       'items': [
         {
@@ -8870,7 +8870,12 @@
         {
           'name': 'TimezoneAutomaticDetectionSendWiFiAccessPoints',
           'value': 3,
-          'caption': '''Always send WiFi acess-points to server while resolving timezone.''',
+          'caption': '''Always send WiFi access-points to server while resolving timezone.''',
+        },
+        {
+          'name': 'TimezoneAutomaticDetectionSendAllLocationInfo',
+          'value': 4,
+          'caption': '''Always send any available location signals to the server while resolving timezone.''',
         },
       ],
       'supported_on': ['chrome_os:53-'],
@@ -8892,6 +8897,8 @@
 
       If set to TimezoneAutomaticDetectionSendWiFiAccessPoints, timezone controls in chrome://settings will be disabled. Automatic timezone detection will be always on. The list of visible WiFi access-points will be always sent to Geolocation API server for fine-grained timezone detection.
 
+      If set to TimezoneAutomaticDetectionSendAllLocationInfo, timezone controls in chrome://settings will be disabled. Automatic timezone detection will be always on. Location information (such as WiFi access-points, reachable Cell Towers, GPS) will be sent to a server for fine-grained timezone detection.
+
       If this policy is not set, it will behave as if TimezoneAutomaticDetectionUsersDecide is set.
 
       If SystemTimezone policy is set, it overrides this policy. In this case automatic timezone detection is completely disabled.''',
diff --git a/components/reading_list/ios/reading_list_model.h b/components/reading_list/ios/reading_list_model.h
index cf7f2bb..e650020 100644
--- a/components/reading_list/ios/reading_list_model.h
+++ b/components/reading_list/ios/reading_list_model.h
@@ -90,7 +90,7 @@
 
   // Adds |url| at the top of the unread entries, and removes entries with the
   // same |url| from everywhere else if they exist. The entry title will be a
-  // trimmed copy of |title.
+  // trimmed copy of |title|.
   // The addition may be asynchronous, and the data will be available only once
   // the observers are notified.
   virtual const ReadingListEntry& AddEntry(
diff --git a/components/safe_browsing_db/v4_database.cc b/components/safe_browsing_db/v4_database.cc
index 8b20a88b..343e85a 100644
--- a/components/safe_browsing_db/v4_database.cc
+++ b/components/safe_browsing_db/v4_database.cc
@@ -25,7 +25,18 @@
 }  // namespace
 
 // static
-V4StoreFactory* V4Database::factory_ = NULL;
+V4DatabaseFactory* V4Database::db_factory_ = NULL;
+
+// static
+V4StoreFactory* V4Database::store_factory_ = NULL;
+
+std::unique_ptr<V4Database> V4DatabaseFactory::Create(
+    const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
+    std::unique_ptr<StoreMap> store_map) {
+  // Not using MakeUnique since the constructor of V4Database is protected.
+  return std::unique_ptr<V4Database>(
+      new V4Database(db_task_runner, std::move(store_map)));
+}
 
 // static
 void V4Database::Create(
@@ -54,9 +65,9 @@
     const TimeTicks create_start_time) {
   DCHECK(db_task_runner->RunsTasksOnCurrentThread());
 
-  if (!factory_) {
-    factory_ = new V4StoreFactory();
-    ANNOTATE_LEAKING_OBJECT_PTR(factory_);
+  if (!store_factory_) {
+    store_factory_ = new V4StoreFactory();
+    ANNOTATE_LEAKING_OBJECT_PTR(store_factory_);
   }
 
   if (!base::CreateDirectory(base_path)) {
@@ -72,10 +83,15 @@
 
     const base::FilePath store_path = base_path.AppendASCII(it.filename());
     (*store_map)[it.list_id()].reset(
-        factory_->CreateV4Store(db_task_runner, store_path));
+        store_factory_->CreateV4Store(db_task_runner, store_path));
+  }
+
+  if (!db_factory_) {
+    db_factory_ = new V4DatabaseFactory();
+    ANNOTATE_LEAKING_OBJECT_PTR(db_factory_);
   }
   std::unique_ptr<V4Database> v4_database(
-      new V4Database(db_task_runner, std::move(store_map)));
+      db_factory_->Create(db_task_runner, std::move(store_map)));
 
   // Database is done loading, pass it to the new_db_callback on the caller's
   // thread. This would unblock resource loads.
@@ -86,11 +102,29 @@
                       TimeTicks::Now() - create_start_time);
 }
 
+// static
+void V4Database::RegisterDatabaseFactoryForTest(
+    std::unique_ptr<V4DatabaseFactory> factory) {
+  if (db_factory_) {
+    delete db_factory_;
+  }
+  db_factory_ = factory.release();
+}
+
+// static
+void V4Database::RegisterStoreFactoryForTest(
+    std::unique_ptr<V4StoreFactory> factory) {
+  if (store_factory_) {
+    delete store_factory_;
+  }
+  store_factory_ = factory.release();
+}
+
 V4Database::V4Database(
     const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
     std::unique_ptr<StoreMap> store_map)
-    : db_task_runner_(db_task_runner),
-      store_map_(std::move(store_map)),
+    : store_map_(std::move(store_map)),
+      db_task_runner_(db_task_runner),
       pending_store_updates_(0),
       weak_factory_on_io_(this) {
   DCHECK(db_task_runner->RunsTasksOnCurrentThread());
@@ -183,10 +217,12 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   for (const ListIdentifier& identifier : stores_to_check) {
     const auto& store_pair = store_map_->find(identifier);
-    if (store_pair == store_map_->end())
+    if (store_pair == store_map_->end()) {
       return false;  // Store not in our list
-    if (!store_pair->second->HasValidData())
+    }
+    if (!store_pair->second->HasValidData()) {
       return false;  // Store never properly populated.
+    }
   }
   return true;
 }
diff --git a/components/safe_browsing_db/v4_database.h b/components/safe_browsing_db/v4_database.h
index cc07d4e30..acb1855 100644
--- a/components/safe_browsing_db/v4_database.h
+++ b/components/safe_browsing_db/v4_database.h
@@ -78,10 +78,9 @@
 class V4DatabaseFactory {
  public:
   virtual ~V4DatabaseFactory() {}
-  virtual V4Database* CreateV4Database(
+  virtual std::unique_ptr<V4Database> Create(
       const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
-      const base::FilePath& base_dir_path,
-      const ListInfos& list_infos) = 0;
+      std::unique_ptr<StoreMap> store_map);
 };
 
 // The on-disk databases are shared among all profiles, as it doesn't contain
@@ -101,7 +100,7 @@
       const scoped_refptr<base::SequencedTaskRunner>& db_task_runner,
       const base::FilePath& base_path,
       const ListInfos& list_infos,
-      NewDatabaseReadyCallback callback);
+      NewDatabaseReadyCallback new_db_callback);
 
   // Destroys the provided v4_database on its task_runner since this may be a
   // long operation.
@@ -153,7 +152,9 @@
              std::unique_ptr<StoreMap> store_map);
 
  private:
+  friend class V4DatabaseFactory;
   friend class V4DatabaseTest;
+  friend class V4SafeBrowsingServiceTest;
   FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest, TestSetupDatabaseWithFakeStores);
   FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest,
                            TestSetupDatabaseWithFakeStoresFailsReset);
@@ -163,12 +164,6 @@
   FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest, TestApplyUpdateWithInvalidUpdate);
   FRIEND_TEST_ALL_PREFIXES(V4DatabaseTest, TestSomeStoresMatchFullHash);
 
-  // Makes the passed |factory| the factory used to instantiate a V4Store. Only
-  // for tests.
-  static void RegisterStoreFactoryForTest(V4StoreFactory* factory) {
-    factory_ = factory;
-  }
-
   // Factory method to create a V4Database. When the database creation is
   // complete, it calls the NewDatabaseReadyCallback on |callback_task_runner|.
   static void CreateOnTaskRunner(
@@ -179,6 +174,16 @@
       NewDatabaseReadyCallback callback,
       const base::TimeTicks create_start_time);
 
+  // Makes the passed |factory| the factory used to instantiate a V4Database.
+  // Only for tests.
+  static void RegisterDatabaseFactoryForTest(
+      std::unique_ptr<V4DatabaseFactory> factory);
+
+  // Makes the passed |factory| the factory used to instantiate a V4Store. Only
+  // for tests.
+  static void RegisterStoreFactoryForTest(
+      std::unique_ptr<V4StoreFactory> factory);
+
   // Callback called when a new store has been created and is ready to be used.
   // This method updates the store_map_ to point to the new store, which causes
   // the old store to get deleted.
@@ -190,15 +195,20 @@
       const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner,
       DatabaseReadyForUpdatesCallback db_ready_for_updates_callback);
 
-  const scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
-
+ protected:
   // Map of ListIdentifier to the V4Store.
   const std::unique_ptr<StoreMap> store_map_;
 
+ private:
+  const scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
+
   DatabaseUpdatedCallback db_updated_callback_;
 
+  // The factory that controls the creation of the V4Database object.
+  static V4DatabaseFactory* db_factory_;
+
   // The factory that controls the creation of V4Store objects.
-  static V4StoreFactory* factory_;
+  static V4StoreFactory* store_factory_;
 
   // The number of stores for which the update request is pending. When this
   // goes down to 0, that indicates that the database has updated all the stores
diff --git a/components/safe_browsing_db/v4_database_unittest.cc b/components/safe_browsing_db/v4_database_unittest.cc
index b8e0786..6b83138 100644
--- a/components/safe_browsing_db/v4_database_unittest.cc
+++ b/components/safe_browsing_db/v4_database_unittest.cc
@@ -91,8 +91,8 @@
   }
 
   void RegisterFactory(bool hash_prefix_matches = true) {
-    factory_.reset(new FakeV4StoreFactory(hash_prefix_matches));
-    V4Database::RegisterStoreFactoryForTest(factory_.get());
+    V4Database::RegisterStoreFactoryForTest(
+        base::MakeUnique<FakeV4StoreFactory>(hash_prefix_matches));
   }
 
   void SetupInfoMapAndExpectedState() {
@@ -206,7 +206,6 @@
   ListInfos list_infos_;
   std::vector<ListIdentifier> expected_identifiers_;
   std::vector<base::FilePath> expected_store_paths_;
-  std::unique_ptr<FakeV4StoreFactory> factory_;
   DatabaseUpdatedCallback callback_db_updated_;
   NewDatabaseReadyCallback callback_db_ready_;
   StoreStateMap expected_store_state_map_;
diff --git a/components/safe_browsing_db/v4_feature_list.cc b/components/safe_browsing_db/v4_feature_list.cc
index 323ad4d..9d166e9 100644
--- a/components/safe_browsing_db/v4_feature_list.cc
+++ b/components/safe_browsing_db/v4_feature_list.cc
@@ -10,31 +10,35 @@
 namespace V4FeatureList {
 
 namespace {
+
 const base::Feature kLocalDatabaseManagerEnabled{
     "SafeBrowsingV4LocalDatabaseManagerEnabled",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kV4HybridEnabled{"SafeBrowsingV4HybridEnabled",
-                                     base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kV4OnlyEnabled{"SafeBrowsingV4OnlyEnabled",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
 
-}  // namespace
+bool IsV4OnlyEnabled() {
+  return base::FeatureList::IsEnabled(kV4OnlyEnabled);
+}
 
 bool IsLocalDatabaseManagerEnabled() {
   return base::FeatureList::IsEnabled(kLocalDatabaseManagerEnabled) ||
-         IsV4HybridEnabled() || IsV4OnlyEnabled();
+         IsV4OnlyEnabled();
 }
 
-bool IsV4HybridEnabled() {
-  return base::FeatureList::IsEnabled(kV4HybridEnabled);
-}
+}  // namespace
 
-bool IsV4OnlyEnabled() {
-  // TODO(vakh): Enable this only when all the lists can be synced from the
-  // server. See http://b/33182208
-  return base::FeatureList::IsEnabled(kV4OnlyEnabled);
+V4UsageStatus GetV4UsageStatus() {
+  V4UsageStatus v4_usage_status;
+  if (safe_browsing::V4FeatureList::IsV4OnlyEnabled()) {
+    v4_usage_status = V4UsageStatus::V4_ONLY;
+  } else if (safe_browsing::V4FeatureList::IsLocalDatabaseManagerEnabled()) {
+    v4_usage_status = V4UsageStatus::V4_INSTANTIATED;
+  } else {
+    v4_usage_status = V4UsageStatus::V4_DISABLED;
+  }
+  return v4_usage_status;
 }
 
 }  // namespace V4FeatureList
diff --git a/components/safe_browsing_db/v4_feature_list.h b/components/safe_browsing_db/v4_feature_list.h
index f549a95..5d7079a 100644
--- a/components/safe_browsing_db/v4_feature_list.h
+++ b/components/safe_browsing_db/v4_feature_list.h
@@ -11,18 +11,21 @@
 // through Finch.
 namespace V4FeatureList {
 
-// Is the PVer4 database manager enabled? Should be true if either of those
-// below are true.
-bool IsLocalDatabaseManagerEnabled();
+enum class V4UsageStatus {
+  // The V4 database manager is not even instantiated i.e. is diabled. All
+  // SafeBrowsing operations use PVer3 code.
+  V4_DISABLED,
 
-// Is the PVer4 database being checked for resource reputation? If this returns
-// true, use PVer4 database for CheckBrowseUrl, otherwise use PVer3.
-bool IsV4HybridEnabled();
+  // The V4 database manager is instantiated, and performs background updates,
+  // but all SafeBrowsing verdicts are returned using the PVer3 database.
+  V4_INSTANTIATED,
 
-// Is only the PVer4 database being checked for resource reputation? If this
-// returns true, use PVer4 database for all SafeBrowsing operations, and don't
-// update the PVer3 database at all.  This is the launch configuration.
-bool IsV4OnlyEnabled();
+  // Only the V4 database manager is instantiated, PVer3 database manager is
+  // not. All SafeBrowsing verdicts are returned using PVer4 database.
+  V4_ONLY
+};
+
+V4UsageStatus GetV4UsageStatus();
 
 }  // namespace V4FeatureList
 
diff --git a/components/safe_browsing_db/v4_get_hash_protocol_manager.h b/components/safe_browsing_db/v4_get_hash_protocol_manager.h
index ffd4ea89..8a0f855 100644
--- a/components/safe_browsing_db/v4_get_hash_protocol_manager.h
+++ b/components/safe_browsing_db/v4_get_hash_protocol_manager.h
@@ -288,6 +288,10 @@
                    const std::vector<FullHashInfo>& full_hash_infos,
                    const base::Time& negative_cache_expire);
 
+ protected:
+  // A cache of full hash results.
+  FullHashCache full_hash_cache_;
+
  private:
   // Map of GetHash requests to parameters which created it.
   using PendingHashRequests =
@@ -329,9 +333,6 @@
   // The clock used to vend times.
   std::unique_ptr<base::Clock> clock_;
 
-  // A cache of full hash results.
-  FullHashCache full_hash_cache_;
-
   // The following sets represent the combination of lists that we would always
   // request from the server, irrespective of which list we found the hash
   // prefix match in.
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc
index 45aad8e..0940f2ef 100644
--- a/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -136,10 +136,6 @@
 scoped_refptr<V4LocalDatabaseManager> V4LocalDatabaseManager::Create(
     const base::FilePath& base_path,
     ExtendedReportingLevelCallback extended_reporting_level_callback) {
-  if (!V4FeatureList::IsLocalDatabaseManagerEnabled()) {
-    return nullptr;
-  }
-
   return make_scoped_refptr(
       new V4LocalDatabaseManager(base_path, extended_reporting_level_callback));
 }
diff --git a/components/safe_browsing_db/v4_store.h b/components/safe_browsing_db/v4_store.h
index 0deb76a2..1a6b14a 100644
--- a/components/safe_browsing_db/v4_store.h
+++ b/components/safe_browsing_db/v4_store.h
@@ -391,6 +391,10 @@
   // |checksum| is used to set the |checksum| field in the final proto.
   StoreWriteResult WriteToDisk(const Checksum& checksum);
 
+ protected:
+  HashPrefixMap hash_prefix_map_;
+
+ private:
   // The checksum value as read from the disk, until it is verified. Once
   // verified, it is cleared.
   std::string expected_checksum_;
@@ -406,7 +410,6 @@
   // update response.
   std::string state_;
   const base::FilePath store_path_;
-  HashPrefixMap hash_prefix_map_;
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
 };
 
diff --git a/components/search_engines/OWNERS b/components/search_engines/OWNERS
index 9608b23..13fa9e4 100644
--- a/components/search_engines/OWNERS
+++ b/components/search_engines/OWNERS
@@ -1,2 +1,4 @@
 pkasting@chromium.org
 vasilii@chromium.org
+
+# COMPONENT: UI>Browser>Search
diff --git a/components/sync/model_impl/processor_entity_tracker.cc b/components/sync/model_impl/processor_entity_tracker.cc
index cae2e88..ec12df8 100644
--- a/components/sync/model_impl/processor_entity_tracker.cc
+++ b/components/sync/model_impl/processor_entity_tracker.cc
@@ -59,11 +59,17 @@
 
 ProcessorEntityTracker::~ProcessorEntityTracker() {}
 
-void ProcessorEntityTracker::CacheCommitData(EntityData* data) {
+void ProcessorEntityTracker::SetCommitData(EntityData* data) {
   DCHECK(data);
-  if (data->client_tag_hash.empty()) {
-    data->client_tag_hash = metadata_.client_tag_hash();
-  }
+  // Update data's fields from metadata.
+  data->client_tag_hash = metadata_.client_tag_hash();
+  if (!metadata_.server_id().empty())
+    data->id = metadata_.server_id();
+  data->creation_time = ProtoTimeToTime(metadata_.creation_time());
+  data->modification_time = ProtoTimeToTime(metadata_.modification_time());
+  DCHECK(MatchesSpecificsHash(data->specifics));
+
+  commit_data_.reset();
   CacheCommitData(data->PassToPtr());
 }
 
@@ -145,21 +151,24 @@
 
 void ProcessorEntityTracker::MakeLocalChange(std::unique_ptr<EntityData> data) {
   DCHECK(!metadata_.client_tag_hash().empty());
-  DCHECK_EQ(metadata_.client_tag_hash(), data->client_tag_hash);
 
-  if (data->modification_time.is_null()) {
-    data->modification_time = base::Time::Now();
-  }
+  // Update metadata fields from updated data.
+  base::Time modification_time = !data->modification_time.is_null()
+                                     ? data->modification_time
+                                     : base::Time::Now();
 
+  // IncrementSequenceNumber should be called before UpdateSpecificHash since
+  // it remembers specifics hash before the modifications.
   IncrementSequenceNumber();
   UpdateSpecificsHash(data->specifics);
-  metadata_.set_modification_time(TimeToProtoTime(data->modification_time));
+  if (!data->creation_time.is_null())
+    metadata_.set_creation_time(TimeToProtoTime(data->creation_time));
+  metadata_.set_modification_time(TimeToProtoTime(modification_time));
   metadata_.set_is_deleted(false);
 
-  data->id = metadata_.server_id();
-  data->creation_time = ProtoTimeToTime(metadata_.creation_time());
-  commit_data_.reset();
-  CacheCommitData(data.get());
+  // SetCommitData will update data's fileds from metadata and wrap it into
+  // immutable EntityDataPtr.
+  SetCommitData(data.get());
 }
 
 void ProcessorEntityTracker::Delete() {
@@ -176,6 +185,7 @@
   if (!metadata_.is_deleted()) {
     DCHECK(HasCommitData());
     DCHECK_EQ(commit_data_->client_tag_hash, metadata_.client_tag_hash());
+    DCHECK_EQ(commit_data_->id, metadata_.server_id());
     request->entity = commit_data_;
   } else {
     // Make an EntityData with empty specifics to indicate deletion. This is
diff --git a/components/sync/model_impl/processor_entity_tracker.h b/components/sync/model_impl/processor_entity_tracker.h
index 718c3c7..9d4ded75 100644
--- a/components/sync/model_impl/processor_entity_tracker.h
+++ b/components/sync/model_impl/processor_entity_tracker.h
@@ -100,9 +100,10 @@
   // Clears any in-memory sync state associated with outstanding commits.
   void ClearTransientSyncState();
 
-  // Takes the passed commit data and caches it in the instance.
-  // The data is swapped from the input struct without copying.
-  void CacheCommitData(EntityData* data);
+  // Takes the passed commit data updates its fields with values from metadata
+  // and caches it in the instance. The data is swapped from the input struct
+  // without copying.
+  void SetCommitData(EntityData* data);
 
   // Caches the a copy of |data_ptr|, which doesn't copy the data itself.
   void CacheCommitData(const EntityDataPtr& data_ptr);
diff --git a/components/sync/model_impl/shared_model_type_processor.cc b/components/sync/model_impl/shared_model_type_processor.cc
index 614321d..108aefc 100644
--- a/components/sync/model_impl/shared_model_type_processor.cc
+++ b/components/sync/model_impl/shared_model_type_processor.cc
@@ -209,19 +209,14 @@
     return;
   }
 
-  // Fill in some data.
-  data->client_tag_hash = GetClientTagHash(storage_key, *data);
-  if (data->modification_time.is_null()) {
-    data->modification_time = base::Time::Now();
-  }
-
-  ProcessorEntityTracker* entity = GetEntityForTagHash(data->client_tag_hash);
-
+  ProcessorEntityTracker* entity = GetEntityForStorageKey(storage_key);
   if (entity == nullptr) {
     // The bridge is creating a new entity.
-    if (data->creation_time.is_null()) {
-      data->creation_time = data->modification_time;
-    }
+    data->client_tag_hash = GetClientTagHash(storage_key, *data);
+    if (data->creation_time.is_null())
+      data->creation_time = base::Time::Now();
+    if (data->modification_time.is_null())
+      data->modification_time = data->creation_time;
     entity = CreateEntity(storage_key, *data);
   } else if (entity->MatchesData(*data)) {
     // Ignore changes that don't actually change anything.
@@ -613,7 +608,9 @@
     ProcessorEntityTracker* entity = GetEntityForStorageKey(data.first);
     // If the entity wasn't deleted or updated with new commit.
     if (entity != nullptr && entity->RequiresCommitData()) {
-      entity->CacheCommitData(data.second.get());
+      // SetCommitData will update EntityData's fields with values from
+      // metadata.
+      entity->SetCommitData(data.second.get());
     }
   }
 }
diff --git a/components/sync/model_impl/shared_model_type_processor_unittest.cc b/components/sync/model_impl/shared_model_type_processor_unittest.cc
index 728758f..5fec577 100644
--- a/components/sync/model_impl/shared_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/shared_model_type_processor_unittest.cc
@@ -1061,17 +1061,21 @@
 
 TEST_F(SharedModelTypeProcessorTest, ConflictResolutionUseLocal) {
   InitializeToReadyState();
-  EntitySpecifics specifics = bridge()->WriteItem(kKey1, kValue1);
+  // WriteAndAck entity to get id from the server.
+  WriteItemAndAck(kKey1, kValue1);
   bridge()->SetConflictResolution(ConflictResolution::UseLocal());
 
-  worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2));
+  // Change value locally and at the same time simulate conflicting update from
+  // server.
+  EntitySpecifics specifics2 = bridge()->WriteItem(kKey1, kValue2);
+  worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue3));
 
   // Updated metadata but not data; new commit request.
-  EXPECT_EQ(1U, db().data_change_count());
-  EXPECT_EQ(2U, db().metadata_change_count());
-  EXPECT_EQ(1, db().GetMetadata(kKey1).server_version());
+  EXPECT_EQ(2U, db().data_change_count());
+  EXPECT_EQ(4U, db().metadata_change_count());
+  EXPECT_EQ(2, db().GetMetadata(kKey1).server_version());
   worker()->ExpectPendingCommits({kHash1, kHash1});
-  worker()->ExpectNthPendingCommit(1, kHash1, specifics);
+  worker()->ExpectNthPendingCommit(1, kHash1, specifics2);
 }
 
 TEST_F(SharedModelTypeProcessorTest, ConflictResolutionUseRemote) {
@@ -1246,18 +1250,20 @@
 // Test that re-encrypting enqueues the right data for USE_LOCAL conflicts.
 TEST_F(SharedModelTypeProcessorTest, ReEncryptConflictResolutionUseLocal) {
   InitializeToReadyState();
+  // WriteAndAck entity to get id from the server.
+  WriteItemAndAck(kKey1, kValue1);
   worker()->UpdateWithEncryptionKey("k1");
-  EntitySpecifics specifics = bridge()->WriteItem(kKey1, kValue1);
+  EntitySpecifics specifics = bridge()->WriteItem(kKey1, kValue2);
   worker()->ExpectPendingCommits({kHash1});
 
   bridge()->SetConflictResolution(ConflictResolution::UseLocal());
   // Unencrypted update needs to be re-commited with key k1.
-  worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue2), 1, "");
+  worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue3), 1, "");
 
   // Ensure the re-commit has the correct value.
   EXPECT_EQ(2U, worker()->GetNumPendingCommits());
   worker()->ExpectNthPendingCommit(1, kHash1, specifics);
-  EXPECT_EQ(kValue1, db().GetValue(kKey1));
+  EXPECT_EQ(kValue2, db().GetValue(kKey1));
 }
 
 // Test that re-encrypting enqueues the right data for USE_REMOTE conflicts.
@@ -1347,10 +1353,12 @@
 // Same as above but with two commit requests before one ack.
 TEST_F(SharedModelTypeProcessorTest, IgnoreRemoteEncryptionInterleaved) {
   InitializeToReadyState();
-  EntitySpecifics specifics1 = bridge()->WriteItem(kKey1, kValue1);
-  EntitySpecifics specifics2 = bridge()->WriteItem(kKey1, kValue2);
+  // WriteAndAck entity to get id from the server.
+  WriteItemAndAck(kKey1, kValue1);
+  EntitySpecifics specifics1 = bridge()->WriteItem(kKey1, kValue2);
+  EntitySpecifics specifics2 = bridge()->WriteItem(kKey1, kValue3);
   worker()->AckOnePendingCommit();
-  // kValue1 is now the base value.
+  // kValue2 is now the base value.
   EXPECT_EQ(1U, worker()->GetNumPendingCommits());
   worker()->ExpectNthPendingCommit(0, kHash1, specifics2);
 
diff --git a/components/sync/test/engine/mock_model_type_worker.cc b/components/sync/test/engine/mock_model_type_worker.cc
index 7247640..2d87fc2 100644
--- a/components/sync/test/engine/mock_model_type_worker.cc
+++ b/components/sync/test/engine/mock_model_type_worker.cc
@@ -25,6 +25,11 @@
 MockModelTypeWorker::~MockModelTypeWorker() {}
 
 void MockModelTypeWorker::EnqueueForCommit(const CommitRequestDataList& list) {
+  // Verify that all request entities have valid id, version combinations.
+  for (const CommitRequestData& commit_request_data : list) {
+    EXPECT_TRUE(commit_request_data.base_version == -1 ||
+                !commit_request_data.entity->id.empty());
+  }
   pending_commits_.push_back(list);
 }
 
@@ -188,13 +193,13 @@
 
   CommitResponseData response_data;
 
-  if (request_data.base_version == 0) {
+  if (request_data.base_version == kUncommittedVersion) {
     // Server assigns new ID to newly committed items.
     DCHECK(entity.id.empty());
-    response_data.id = entity.id;
+    response_data.id = GenerateId(client_tag_hash);
   } else {
     // Otherwise we reuse the ID from the request.
-    response_data.id = GenerateId(client_tag_hash);
+    response_data.id = entity.id;
   }
 
   response_data.client_tag_hash = client_tag_hash;
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index c13df7c..4b0938e 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -7,12 +7,9 @@
 #include <algorithm>
 #include <utility>
 
-#include "base/format_macros.h"
-#include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "components/sync/base/hash_util.h"
 #include "components/sync/device_info/local_device_info_provider.h"
@@ -24,7 +21,6 @@
 #include "components/sync_sessions/synced_tab_delegate.h"
 #include "components/sync_sessions/synced_window_delegate.h"
 #include "components/sync_sessions/synced_window_delegates_getter.h"
-#include "components/sync_sessions/tab_node_pool.h"
 #include "components/variations/variations_associated_data.h"
 
 using sessions::SerializedNavigationEntry;
@@ -66,60 +62,17 @@
   return s1->modified_time > s2->modified_time;
 }
 
-std::string TabNodeIdToTag(const std::string& machine_tag, int tab_node_id) {
-  CHECK_GT(tab_node_id, TabNodePool::kInvalidTabNodeID) << "crbug.com/673618";
-  return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id);
-}
-
 std::string TagFromSpecifics(const sync_pb::SessionSpecifics& specifics) {
   if (specifics.has_header()) {
     return specifics.session_tag();
   } else if (specifics.has_tab()) {
-    return TabNodeIdToTag(specifics.session_tag(), specifics.tab_node_id());
+    return TabNodePool::TabIdToTag(specifics.session_tag(),
+                                   specifics.tab_node_id());
   } else {
     return std::string();
   }
 }
 
-sync_pb::SessionSpecifics SessionTabToSpecifics(
-    const sessions::SessionTab& session_tab,
-    const std::string& local_tag,
-    int tab_node_id) {
-  sync_pb::SessionSpecifics specifics;
-  specifics.mutable_tab()->CopyFrom(session_tab.ToSyncData());
-  specifics.set_session_tag(local_tag);
-  specifics.set_tab_node_id(tab_node_id);
-  return specifics;
-}
-
-void AppendDeletionsForTabNodes(const std::set<int>& tab_node_ids,
-                                const std::string& machine_tag,
-                                syncer::SyncChangeList* change_output) {
-  for (std::set<int>::const_iterator it = tab_node_ids.begin();
-       it != tab_node_ids.end(); ++it) {
-    change_output->push_back(syncer::SyncChange(
-        FROM_HERE, SyncChange::ACTION_DELETE,
-        SyncData::CreateLocalDelete(TabNodeIdToTag(machine_tag, *it),
-                                    syncer::SESSIONS)));
-  }
-}
-
-// Ensure that the tab id is not invalid and is not already synced (which
-// can confuse the logic that tracks whether tabs are mapped or unmapped).
-bool ShouldSyncTabId(
-    SessionID::id_type tab_id,
-    const google::protobuf::RepeatedField<int>& synced_tab_ids) {
-  if (tab_id == TabNodePool::kInvalidTabID)
-    return false;
-
-  for (auto synced_tab_id : synced_tab_ids) {
-    if (tab_id == synced_tab_id)
-      return false;
-  }
-
-  return true;
-}
-
 }  // namespace
 
 // |local_device| is owned by ProfileSyncService, its lifetime exceeds
@@ -164,6 +117,7 @@
     std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
   syncer::SyncMergeResult merge_result(type);
   DCHECK(session_tracker_.Empty());
+  DCHECK_EQ(0U, local_tab_pool_.Capacity());
 
   error_handler_ = std::move(error_handler);
   sync_processor_ = std::move(sync_processor);
@@ -199,12 +153,13 @@
     InitializeCurrentMachineTag(local_device_->GetLocalSyncCacheGUID());
   }
 
-  session_tracker_.SetLocalSessionTag(current_machine_tag());
+  session_tracker_.SetLocalSessionTag(current_machine_tag_);
 
   syncer::SyncChangeList new_changes;
 
   // First, we iterate over sync data to update our session_tracker_.
-  if (!InitFromSyncModel(initial_sync_data, &new_changes)) {
+  syncer::SyncDataList restored_tabs;
+  if (!InitFromSyncModel(initial_sync_data, &restored_tabs, &new_changes)) {
     // The sync db didn't have a header node for us. Create one.
     sync_pb::EntitySpecifics specifics;
     sync_pb::SessionSpecifics* base_specifics = specifics.mutable_session();
@@ -221,12 +176,12 @@
 #if defined(OS_ANDROID)
   std::string sync_machine_tag(
       BuildMachineTag(local_device_->GetLocalSyncCacheGUID()));
-  if (current_machine_tag().compare(sync_machine_tag) != 0)
+  if (current_machine_tag_.compare(sync_machine_tag) != 0)
     DeleteForeignSessionInternal(sync_machine_tag, &new_changes);
 #endif
 
   // Check if anything has changed on the local client side.
-  AssociateWindows(RELOAD_TABS, &new_changes);
+  AssociateWindows(RELOAD_TABS, restored_tabs, &new_changes);
   local_tab_pool_out_of_sync_ = false;
 
   merge_result.set_error(
@@ -238,6 +193,7 @@
 
 void SessionsSyncManager::AssociateWindows(
     ReloadTabsOption option,
+    const syncer::SyncDataList& restored_tabs,
     syncer::SyncChangeList* change_output) {
   const std::string local_tag = current_machine_tag();
   sync_pb::SessionSpecifics specifics;
@@ -305,33 +261,30 @@
         if (!synced_tab)
           continue;
 
-        if (!ShouldSyncTabId(tab_id, window_s.tab())) {
-          LOG(ERROR) << "Not syncing invalid/duplicate tab with id " << tab_id;
-          continue;
-        }
-
-        // Placeholder tabs are those without WebContents, either because they
-        // were never loaded into memory or they were evicted from memory
-        // (typically only on Android devices). They only have a tab id, window
-        // id, and a saved synced id (corresponding to the tab node id). Note
-        // that only placeholders have this sync id, as it's necessary to
-        // properly reassociate the tab with the entity that was backing it.
         if (synced_tab->IsPlaceholderTab()) {
           // For tabs without WebContents update the |tab_id| and |window_id|,
           // as it could have changed after a session restore.
-          if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID) {
+          // Note: We cannot check if a tab is valid if it has no WebContents.
+          // We assume any such tab is valid and leave the contents of
+          // corresponding sync node unchanged.
+          if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID &&
+              tab_id > TabNodePool::kInvalidTabID) {
             AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id,
-                                            change_output);
+                                            restored_tabs, change_output);
+            found_tabs = true;
+            window_s.add_tab(tab_id);
           }
-        } else if (RELOAD_TABS == option) {
-          AssociateTab(synced_tab, change_output);
+          continue;
         }
 
-        // If the tab was syncable, it would have been added to the tracker
-        // either by the above Associate[RestoredPlaceholder]Tab call or by the
-        // OnLocalTabModified method invoking AssociateTab directly. Therefore,
-        // we can key whether this window has valid tabs based on the tab's
-        // presence in the tracker.
+        if (RELOAD_TABS == option)
+          AssociateTab(synced_tab, change_output);
+
+        // If the tab is valid, it would have been added to the tracker either
+        // by the above AssociateTab call (at association time), or by the
+        // change processor calling AssociateTab for all modified tabs.
+        // Therefore, we can key whether this window has valid tabs based on
+        // the tab's presence in the tracker.
         const sessions::SessionTab* tab = nullptr;
         if (session_tracker_.LookupSessionTab(local_tag, tab_id, &tab)) {
           found_tabs = true;
@@ -350,10 +303,8 @@
       }
     }
   }
-  std::set<int> deleted_tab_node_ids;
-  session_tracker_.CleanupLocalTabs(&deleted_tab_node_ids);
-  AppendDeletionsForTabNodes(deleted_tab_node_ids, current_machine_tag(),
-                             change_output);
+  local_tab_pool_.DeleteUnassociatedTabNodes(change_output);
+  session_tracker_.CleanupSession(local_tag);
 
   // Always update the header.  Sync takes care of dropping this update
   // if the entity specifics are identical (i.e windows, client name did
@@ -366,63 +317,73 @@
       syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
 }
 
-void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab_delegate,
+void SessionsSyncManager::AssociateTab(SyncedTabDelegate* const tab,
                                        syncer::SyncChangeList* change_output) {
-  DCHECK(!tab_delegate->IsPlaceholderTab());
+  DCHECK(!tab->IsPlaceholderTab());
+  SessionID::id_type tab_id = tab->GetSessionId();
 
-  if (tab_delegate->IsBeingDestroyed()) {
-    // Do nothing. By not proactively adding the tab to the session, it will be
-    // removed if necessary during subsequent cleanup.
+  if (tab->IsBeingDestroyed()) {
+    // This tab is closing.
+    TabLinksMap::iterator tab_iter = local_tab_map_.find(tab_id);
+    if (tab_iter == local_tab_map_.end()) {
+      // We aren't tracking this tab (for example, sync setting page).
+      return;
+    }
+    local_tab_pool_.FreeTabNode(tab_iter->second->tab_node_id(), change_output);
+    local_tab_map_.erase(tab_iter);
     return;
   }
 
-  if (!tab_delegate->ShouldSync(sessions_client_))
+  if (!tab->ShouldSync(sessions_client_))
     return;
 
-  SessionID::id_type tab_id = tab_delegate->GetSessionId();
-  DVLOG(1) << "Syncing tab " << tab_id << " from window "
-           << tab_delegate->GetWindowId();
+  TabLinksMap::iterator local_tab_map_iter = local_tab_map_.find(tab_id);
+  TabLink* tab_link = nullptr;
 
-  int tab_node_id = TabNodePool::kInvalidTabNodeID;
-  bool existing_tab_node =
-      session_tracker_.GetTabNodeFromLocalTabId(tab_id, &tab_node_id);
-  CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id) << "crbug.com/673618";
-  tab_delegate->SetSyncId(tab_node_id);
-  sessions::SessionTab* session_tab =
-      session_tracker_.GetTab(current_machine_tag(), tab_id);
+  if (local_tab_map_iter == local_tab_map_.end()) {
+    int tab_node_id = tab->GetSyncId();
+    // If there is an old sync node for the tab, reuse it.  If this is a new
+    // tab, get a sync node for it.
+    if (!local_tab_pool_.IsUnassociatedTabNode(tab_node_id)) {
+      tab_node_id = local_tab_pool_.GetFreeTabNode(change_output);
+      tab->SetSyncId(tab_node_id);
+    }
+    local_tab_pool_.AssociateTabNode(tab_node_id, tab_id);
+    tab_link = new TabLink(tab_node_id, tab);
+    local_tab_map_[tab_id] = make_linked_ptr<TabLink>(tab_link);
+  } else {
+    // This tab is already associated with a sync node, reuse it.
+    // Note: on some platforms the tab object may have changed, so we ensure
+    // the tab link is up to date.
+    tab_link = local_tab_map_iter->second.get();
+    local_tab_map_iter->second->set_tab(tab);
+  }
+  DCHECK(tab_link);
+  DCHECK_NE(tab_link->tab_node_id(), TabNodePool::kInvalidTabNodeID);
+  DVLOG(1) << "Reloading tab " << tab_id << " from window "
+           << tab->GetWindowId();
 
-  // Get the previously synced url.
-  int old_index = session_tab->normalized_navigation_index();
-  GURL old_url;
-  if (session_tab->navigations.size() > static_cast<size_t>(old_index))
-    old_url = session_tab->navigations[old_index].virtual_url();
+  // Write to sync model.
+  sync_pb::EntitySpecifics specifics;
+  LocalTabDelegateToSpecifics(*tab, specifics.mutable_session());
+  syncer::SyncData data = syncer::SyncData::CreateLocalData(
+      TabNodePool::TabIdToTag(current_machine_tag_, tab_link->tab_node_id()),
+      current_session_name_, specifics);
+  change_output->push_back(
+      syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
 
-  // Update the tracker's session representation.
-  SetSessionTabFromDelegate(*tab_delegate, base::Time::Now(), session_tab);
-  SetVariationIds(session_tab);
+  int current_index = tab->GetCurrentEntryIndex();
+  const GURL new_url = tab->GetVirtualURLAtIndex(current_index);
+  if (new_url != tab_link->url()) {
+    tab_link->set_url(new_url);
+    favicon_cache_.OnFaviconVisited(new_url,
+                                    tab->GetFaviconURLAtIndex(current_index));
+    page_revisit_broadcaster_.OnPageVisit(
+        new_url, tab->GetTransitionAtIndex(current_index));
+  }
+
   session_tracker_.GetSession(current_machine_tag())->modified_time =
       base::Time::Now();
-
-  // Write to the sync model itself.
-  sync_pb::EntitySpecifics specifics;
-  specifics.mutable_session()->CopyFrom(
-      SessionTabToSpecifics(*session_tab, current_machine_tag(), tab_node_id));
-  syncer::SyncData data = syncer::SyncData::CreateLocalData(
-      TabNodeIdToTag(current_machine_tag(), tab_node_id), current_session_name_,
-      specifics);
-  change_output->push_back(syncer::SyncChange(
-      FROM_HERE, existing_tab_node ? syncer::SyncChange::ACTION_UPDATE
-                                   : syncer::SyncChange::ACTION_ADD,
-      data));
-
-  int current_index = tab_delegate->GetCurrentEntryIndex();
-  const GURL new_url = tab_delegate->GetVirtualURLAtIndex(current_index);
-  if (new_url != old_url) {
-    favicon_cache_.OnFaviconVisited(
-        new_url, tab_delegate->GetFaviconURLAtIndex(current_index));
-    page_revisit_broadcaster_.OnPageVisit(
-        new_url, tab_delegate->GetTransitionAtIndex(current_index));
-  }
 }
 
 bool SessionsSyncManager::RebuildAssociations() {
@@ -482,14 +443,21 @@
   // "interesting" by going to a valid URL, in which case it needs to be added
   // to the window's tab information. Similarly, if a tab became
   // "uninteresting", we remove it from the window's tab information.
-  AssociateWindows(DONT_RELOAD_TABS, &changes);
+  AssociateWindows(DONT_RELOAD_TABS, syncer::SyncDataList(), &changes);
   sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
 }
 
 void SessionsSyncManager::OnFaviconsChanged(const std::set<GURL>& page_urls,
                                             const GURL& /* icon_url */) {
-  for (const GURL& page_url : page_urls)
-    favicon_cache_.OnPageFaviconUpdated(page_url);
+  // TODO(zea): consider a separate container for tabs with outstanding favicon
+  // loads so we don't have to iterate through all tabs comparing urls.
+  for (const GURL& page_url : page_urls) {
+    for (TabLinksMap::iterator tab_iter = local_tab_map_.begin();
+         tab_iter != local_tab_map_.end(); ++tab_iter) {
+      if (tab_iter->second->url() == page_url)
+        favicon_cache_.OnPageFaviconUpdated(page_url);
+    }
+  }
 }
 
 void SessionsSyncManager::StopSyncing(syncer::ModelType type) {
@@ -502,6 +470,8 @@
   sync_processor_.reset(nullptr);
   error_handler_.reset();
   session_tracker_.Clear();
+  local_tab_map_.clear();
+  local_tab_pool_.Clear();
   current_machine_tag_.clear();
   current_session_name_.clear();
   local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID;
@@ -524,17 +494,22 @@
       current_machine_tag(), current_session_name_, header_entity);
   list.push_back(data);
 
-  for (auto& win_iter : session->windows) {
-    for (auto& tab : win_iter.second->tabs) {
-      // TODO(zea): replace with with the correct tab node id once there's a
-      // sync specific wrapper for SessionTab. This method is only used in
-      // tests though, so it's fine for now. crbug.com/662597
-      int tab_node_id = 0;
+  for (auto win_iter = session->windows.begin();
+       win_iter != session->windows.end(); ++win_iter) {
+    for (auto tabs_iter = win_iter->second->tabs.begin();
+         tabs_iter != win_iter->second->tabs.end(); ++tabs_iter) {
       sync_pb::EntitySpecifics entity;
-      entity.mutable_session()->CopyFrom(
-          SessionTabToSpecifics(*tab, current_machine_tag(), tab_node_id));
+      sync_pb::SessionSpecifics* specifics = entity.mutable_session();
+      specifics->mutable_tab()->MergeFrom((*tabs_iter)->ToSyncData());
+      specifics->set_session_tag(current_machine_tag_);
+
+      TabLinksMap::const_iterator tab_map_iter =
+          local_tab_map_.find((*tabs_iter)->tab_id.id());
+      DCHECK(tab_map_iter != local_tab_map_.end());
+      specifics->set_tab_node_id(tab_map_iter->second->tab_node_id());
       syncer::SyncData data = syncer::SyncData::CreateLocalData(
-          TabNodeIdToTag(current_machine_tag(), tab_node_id),
+          TabNodePool::TabIdToTag(current_machine_tag_,
+                                  specifics->tab_node_id()),
           current_session_name_, entity);
       list.push_back(data);
     }
@@ -543,7 +518,7 @@
 }
 
 bool SessionsSyncManager::GetLocalSession(const SyncedSession** local_session) {
-  if (current_machine_tag().empty())
+  if (current_machine_tag_.empty())
     return false;
   *local_session = session_tracker_.GetSession(current_machine_tag());
   return true;
@@ -603,7 +578,7 @@
           LOG(WARNING) << "Dropping modification to local session.";
           return syncer::SyncError();
         }
-        UpdateTrackerWithSpecifics(
+        UpdateTrackerWithForeignSession(
             session, syncer::SyncDataRemote(it->sync_data()).GetModifiedTime());
         break;
       default:
@@ -625,7 +600,7 @@
     return syncer::SyncChange(
         FROM_HERE, SyncChange::ACTION_DELETE,
         SyncData::CreateLocalDelete(
-            TabNodeIdToTag(current_machine_tag(), tab.tab_node_id()),
+            TabNodePool::TabIdToTag(current_machine_tag(), tab.tab_node_id()),
             syncer::SESSIONS));
   }
 }
@@ -641,6 +616,7 @@
 
 bool SessionsSyncManager::InitFromSyncModel(
     const syncer::SyncDataList& sync_data,
+    syncer::SyncDataList* restored_tabs,
     syncer::SyncChangeList* new_changes) {
   bool found_current_header = false;
   int bad_foreign_hash_count = 0;
@@ -658,7 +634,7 @@
         new_changes->push_back(tombstone);
     } else if (specifics.session_tag() != current_machine_tag()) {
       if (TagHashFromSpecifics(specifics) == remote.GetClientTagHash()) {
-        UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime());
+        UpdateTrackerWithForeignSession(specifics, remote.GetModifiedTime());
       } else {
         // In the past, like years ago, we believe that some session data was
         // created with bad tag hashes. This causes any change this client makes
@@ -677,10 +653,6 @@
         found_current_header = true;
         if (specifics.header().has_client_name())
           current_session_name_ = specifics.header().client_name();
-
-        // TODO(zea): crbug.com/639009 update the tracker with the specifics
-        // from the header node as well. This will be necessary to preserve
-        // the set of open tabs when a custom tab is opened.
       } else {
         if (specifics.has_header() || !specifics.has_tab()) {
           LOG(WARNING) << "Found more than one session header node with local "
@@ -688,19 +660,11 @@
           syncer::SyncChange tombstone(TombstoneTab(specifics));
           if (tombstone.IsValid())
             new_changes->push_back(tombstone);
-        } else if (specifics.tab().tab_id() == TabNodePool::kInvalidTabID) {
-          LOG(WARNING) << "Found tab node with invalid tab id.";
-          syncer::SyncChange tombstone(TombstoneTab(specifics));
-          if (tombstone.IsValid())
-            new_changes->push_back(tombstone);
         } else {
-          // This is a valid old tab node, add it to the tracker and associate
-          // it.
-          DVLOG(1) << "Associating local tab " << specifics.tab().tab_id()
-                   << " with node " << specifics.tab_node_id();
-          session_tracker_.ReassociateLocalTab(specifics.tab_node_id(),
-                                               specifics.tab().tab_id());
-          UpdateTrackerWithSpecifics(specifics, remote.GetModifiedTime());
+          // This is a valid old tab node, add it to the pool so it can be
+          // reused for reassociation.
+          local_tab_pool_.AddTabNode(specifics.tab_node_id());
+          restored_tabs->push_back(*it);
         }
       }
     }
@@ -712,7 +676,7 @@
   session_tracker_.LookupAllForeignSessions(&sessions,
                                             SyncedSessionTracker::RAW);
   for (const auto* session : sessions) {
-    session_tracker_.CleanupForeignSession(session->session_tag);
+    session_tracker_.CleanupSession(session->session_tag);
   }
 
   UMA_HISTOGRAM_COUNTS_100("Sync.SessionsBadForeignHashOnMergeCount",
@@ -721,84 +685,70 @@
   return found_current_header;
 }
 
-void SessionsSyncManager::UpdateTrackerWithSpecifics(
+void SessionsSyncManager::UpdateTrackerWithForeignSession(
     const sync_pb::SessionSpecifics& specifics,
     const base::Time& modification_time) {
-  std::string session_tag = specifics.session_tag();
-  SyncedSession* session = session_tracker_.GetSession(session_tag);
+  std::string foreign_session_tag = specifics.session_tag();
+  DCHECK_NE(foreign_session_tag, current_machine_tag());
+
+  SyncedSession* foreign_session =
+      session_tracker_.GetSession(foreign_session_tag);
   if (specifics.has_header()) {
-    // Read in the header data for this session. Header data is
+    // Read in the header data for this foreign session. Header data is
     // essentially a collection of windows, each of which has an ordered id list
     // for their tabs.
 
     if (!IsValidSessionHeader(specifics.header())) {
-      LOG(WARNING) << "Ignoring session node with invalid header "
-                   << "and tag " << session_tag << ".";
+      LOG(WARNING) << "Ignoring foreign session node with invalid header "
+                   << "and tag " << foreign_session_tag << ".";
       return;
     }
 
     // Load (or create) the SyncedSession object for this client.
     const sync_pb::SessionHeader& header = specifics.header();
-    PopulateSessionHeaderFromSpecifics(header, modification_time, session);
+    PopulateSessionHeaderFromSpecifics(header, modification_time,
+                                       foreign_session);
 
     // Reset the tab/window tracking for this session (must do this before
     // we start calling PutWindowInSession and PutTabInWindow so that all
     // unused tabs/windows get cleared by the CleanupSession(...) call).
-    session_tracker_.ResetSessionTracking(session_tag);
+    session_tracker_.ResetSessionTracking(foreign_session_tag);
 
     // Process all the windows and their tab information.
     int num_windows = header.window_size();
-    DVLOG(1) << "Populating " << session_tag << " with " << num_windows
+    DVLOG(1) << "Associating " << foreign_session_tag << " with " << num_windows
              << " windows.";
 
     for (int i = 0; i < num_windows; ++i) {
       const sync_pb::SessionWindow& window_s = header.window(i);
       SessionID::id_type window_id = window_s.window_id();
-      session_tracker_.PutWindowInSession(session_tag, window_id);
-      BuildSyncedSessionFromSpecifics(session_tag, window_s, modification_time,
-                                      session->windows[window_id].get());
+      session_tracker_.PutWindowInSession(foreign_session_tag, window_id);
+      BuildSyncedSessionFromSpecifics(
+          foreign_session_tag, window_s, modification_time,
+          foreign_session->windows[window_id].get());
     }
     // Delete any closed windows and unused tabs as necessary.
-    session_tracker_.CleanupForeignSession(session_tag);
+    session_tracker_.CleanupSession(foreign_session_tag);
   } else if (specifics.has_tab()) {
     const sync_pb::SessionTab& tab_s = specifics.tab();
     SessionID::id_type tab_id = tab_s.tab_id();
-    DVLOG(1) << "Populating " << session_tag << "'s tab id " << tab_id
-             << " from node " << specifics.tab_node_id();
 
-    // Ensure the tracker is aware of the tab node id. Deleting foreign sessions
-    // requires deleting all relevant tab nodes, and it's easier to track the
-    // tab node ids themselves separately from the tab ids.
-    //
-    // Note that TabIDs are not stable across restarts of a client. Consider
-    // this example with two tabs:
-    //
-    // http://a.com  TabID1 --> NodeIDA
-    // http://b.com  TabID2 --> NodeIDB
-    //
-    // After restart, tab ids are reallocated. e.g, one possibility:
-    // http://a.com TabID2 --> NodeIDA
-    // http://b.com TabID1 --> NodeIDB
-    //
-    // If that happened on a remote client, here we will see an update to
-    // TabID1 with tab_node_id changing from NodeIDA to NodeIDB, and TabID2
-    // with tab_node_id changing from NodeIDB to NodeIDA.
-    //
-    // We can also wind up here if we created this tab as an out-of-order
-    // update to the header node for this session before actually associating
-    // the tab itself, so the tab node id wasn't available at the time and
-    // is currently kInvalidTabNodeID.
-    //
-    // In both cases, we can safely throw it into the set of node ids.
-    session_tracker_.OnTabNodeSeen(session_tag, specifics.tab_node_id());
-    sessions::SessionTab* tab = session_tracker_.GetTab(session_tag, tab_id);
-    if (!tab->timestamp.is_null() && tab->timestamp > modification_time) {
-      DVLOG(1) << "Ignoring " << session_tag << "'s session tab " << tab_id
-               << " with earlier modification time: " << tab->timestamp
-               << " vs " << modification_time;
+    const sessions::SessionTab* existing_tab;
+    if (session_tracker_.LookupSessionTab(foreign_session_tag, tab_id,
+                                          &existing_tab) &&
+        existing_tab->timestamp > modification_time) {
+      // Force the tracker to remember this tab node id, even if it isn't
+      // currently being used.
+      session_tracker_.GetTab(foreign_session_tag, tab_id,
+                              specifics.tab_node_id());
+      DVLOG(1) << "Ignoring " << foreign_session_tag << "'s session tab "
+               << tab_id << " with earlier modification time";
       return;
     }
 
+    sessions::SessionTab* tab = session_tracker_.GetTab(
+        foreign_session_tag, tab_id, specifics.tab_node_id());
+
     // Update SessionTab based on protobuf.
     tab->SetFromSyncData(tab_s, modification_time);
 
@@ -807,11 +757,11 @@
     RefreshFaviconVisitTimesFromForeignTab(tab_s, modification_time);
 
     // Update the last modified time.
-    if (session->modified_time < modification_time)
-      session->modified_time = modification_time;
+    if (foreign_session->modified_time < modification_time)
+      foreign_session->modified_time = modification_time;
   } else {
-    LOG(WARNING) << "Ignoring session node with missing header/tab "
-                 << "fields and tag " << session_tag << ".";
+    LOG(WARNING) << "Ignoring foreign session node with missing header/tab "
+                 << "fields and tag " << foreign_session_tag << ".";
   }
 }
 
@@ -829,6 +779,8 @@
     DVLOG(1) << "Creating session sync guid: " << current_machine_tag_;
     sync_prefs_->SetSyncSessionsGUID(current_machine_tag_);
   }
+
+  local_tab_pool_.SetMachineTag(current_machine_tag_);
 }
 
 // static
@@ -892,11 +844,11 @@
     }
   }
   session_window->timestamp = mtime;
-  session_window->tabs.clear();
+  session_window->tabs.resize(specifics.tab_size());
   for (int i = 0; i < specifics.tab_size(); i++) {
     SessionID::id_type tab_id = specifics.tab(i);
     session_tracker_.PutTabInWindow(session_tag, session_window->window_id.id(),
-                                    tab_id);
+                                    tab_id, i);
   }
 }
 
@@ -938,14 +890,20 @@
   }
 
   std::set<int> tab_node_ids_to_delete;
-  session_tracker_.LookupForeignTabNodeIds(tag, &tab_node_ids_to_delete);
+  session_tracker_.LookupTabNodeIds(tag, &tab_node_ids_to_delete);
   if (DisassociateForeignSession(tag)) {
     // Only tell sync to delete the header if there was one.
     change_output->push_back(
         syncer::SyncChange(FROM_HERE, SyncChange::ACTION_DELETE,
                            SyncData::CreateLocalDelete(tag, syncer::SESSIONS)));
   }
-  AppendDeletionsForTabNodes(tab_node_ids_to_delete, tag, change_output);
+  for (std::set<int>::const_iterator it = tab_node_ids_to_delete.begin();
+       it != tab_node_ids_to_delete.end(); ++it) {
+    change_output->push_back(syncer::SyncChange(
+        FROM_HERE, SyncChange::ACTION_DELETE,
+        SyncData::CreateLocalDelete(TabNodePool::TabIdToTag(tag, *it),
+                                    syncer::SESSIONS)));
+  }
   if (!sessions_updated_callback_.is_null())
     sessions_updated_callback_.Run();
 }
@@ -954,7 +912,7 @@
     const std::string& foreign_session_tag) {
   DCHECK_NE(foreign_session_tag, current_machine_tag());
   DVLOG(1) << "Disassociating session " << foreign_session_tag;
-  return session_tracker_.DeleteForeignSession(foreign_session_tag);
+  return session_tracker_.DeleteSession(foreign_session_tag);
 }
 
 bool SessionsSyncManager::GetForeignSession(
@@ -1000,41 +958,66 @@
   return success;
 }
 
+void SessionsSyncManager::LocalTabDelegateToSpecifics(
+    const SyncedTabDelegate& tab_delegate,
+    sync_pb::SessionSpecifics* specifics) {
+  sessions::SessionTab* session_tab = nullptr;
+  session_tab = session_tracker_.GetTab(current_machine_tag(),
+                                        tab_delegate.GetSessionId(),
+                                        tab_delegate.GetSyncId());
+  SetSessionTabFromDelegate(tab_delegate, base::Time::Now(), session_tab);
+  SetVariationIds(session_tab);
+  sync_pb::SessionTab tab_s = session_tab->ToSyncData();
+  specifics->set_session_tag(current_machine_tag_);
+  specifics->set_tab_node_id(tab_delegate.GetSyncId());
+  specifics->mutable_tab()->CopyFrom(tab_s);
+}
+
 void SessionsSyncManager::AssociateRestoredPlaceholderTab(
     const SyncedTabDelegate& tab_delegate,
     SessionID::id_type new_tab_id,
     SessionID::id_type new_window_id,
+    const syncer::SyncDataList& restored_tabs,
     syncer::SyncChangeList* change_output) {
   DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID);
-
-  // It's possible the placeholder tab is associated with a tab node that's
-  // since been deleted. If that's the case, there's no way to reassociate it,
-  // so just return now without adding the tab to the session tracker.
-  if (!session_tracker_.IsLocalTabNodeAssociated(tab_delegate.GetSyncId())) {
-    DVLOG(1) << "Restored placeholder tab's node " << tab_delegate.GetSyncId()
-             << " deleted.";
+  // Rewrite the tab using |restored_tabs| to retrieve the specifics.
+  if (restored_tabs.empty()) {
+    DLOG(WARNING) << "Can't Update tab ID.";
     return;
   }
 
-  // Update tracker with the new association (and inform it of the tab node
-  // in the process).
-  session_tracker_.ReassociateLocalTab(tab_delegate.GetSyncId(), new_tab_id);
+  for (syncer::SyncDataList::const_iterator it = restored_tabs.begin();
+       it != restored_tabs.end(); ++it) {
+    if (it->GetSpecifics().session().tab_node_id() !=
+        tab_delegate.GetSyncId()) {
+      continue;
+    }
 
-  // Update the window id on the SessionTab itself.
-  sessions::SessionTab* local_tab =
-      session_tracker_.GetTab(current_machine_tag(), new_tab_id);
-  local_tab->window_id.set_id(new_window_id);
+    sync_pb::EntitySpecifics entity;
+    sync_pb::SessionSpecifics* specifics = entity.mutable_session();
+    specifics->CopyFrom(it->GetSpecifics().session());
+    DCHECK(specifics->has_tab());
 
-  // Rewrite the specifics based on the reassociated SessionTab to preserve
-  // the new tab and window ids.
-  sync_pb::EntitySpecifics entity;
-  entity.mutable_session()->CopyFrom(SessionTabToSpecifics(
-      *local_tab, current_machine_tag(), tab_delegate.GetSyncId()));
-  syncer::SyncData data = syncer::SyncData::CreateLocalData(
-      TabNodeIdToTag(current_machine_tag(), tab_delegate.GetSyncId()),
-      current_session_name_, entity);
-  change_output->push_back(
-      syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
+    // Update tab node pool with the new association.
+    local_tab_pool_.ReassociateTabNode(tab_delegate.GetSyncId(), new_tab_id);
+    TabLink* tab_link = new TabLink(tab_delegate.GetSyncId(), &tab_delegate);
+    local_tab_map_[new_tab_id] = make_linked_ptr<TabLink>(tab_link);
+
+    if (specifics->tab().tab_id() == new_tab_id &&
+        specifics->tab().window_id() == new_window_id)
+      return;
+
+    // Either the tab_id or window_id changed (e.g due to session restore), so
+    // update the sync node.
+    specifics->mutable_tab()->set_tab_id(new_tab_id);
+    specifics->mutable_tab()->set_window_id(new_window_id);
+    syncer::SyncData data = syncer::SyncData::CreateLocalData(
+        TabNodePool::TabIdToTag(current_machine_tag_, specifics->tab_node_id()),
+        current_session_name_, entity);
+    change_output->push_back(
+        syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE, data));
+    return;
+  }
 }
 
 // static
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index d685c65..66ec40e 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -30,6 +30,7 @@
 #include "components/sync_sessions/revisit/page_revisit_broadcaster.h"
 #include "components/sync_sessions/synced_session.h"
 #include "components/sync_sessions/synced_session_tracker.h"
+#include "components/sync_sessions/tab_node_pool.h"
 
 namespace syncer {
 class LocalDeviceInfoProvider;
@@ -117,6 +118,37 @@
   void DoGarbageCollection();
 
  private:
+  // Keep all the links to local tab data in one place. A tab_node_id and tab
+  // must be passed at creation. The tab_node_id is not mutable, although
+  // all other fields are.
+  class TabLink {
+   public:
+    TabLink(int tab_node_id, const SyncedTabDelegate* tab)
+        : tab_node_id_(tab_node_id), tab_(tab) {}
+
+    void set_tab(const SyncedTabDelegate* tab) { tab_ = tab; }
+    void set_url(const GURL& url) { url_ = url; }
+
+    int tab_node_id() const { return tab_node_id_; }
+    const SyncedTabDelegate* tab() const { return tab_; }
+    const GURL& url() const { return url_; }
+
+   private:
+    // The id for the sync node this tab is stored in.
+    const int tab_node_id_;
+
+    // The tab object itself.
+    const SyncedTabDelegate* tab_;
+
+    // The currently visible url of the tab (used for syncing favicons).
+    GURL url_;
+
+    DISALLOW_COPY_AND_ASSIGN(TabLink);
+  };
+
+  // Container for accessing local tab data by tab id.
+  typedef std::map<SessionID::id_type, linked_ptr<TabLink>> TabLinksMap;
+
   friend class extensions::ExtensionSessionsTest;
   friend class SessionsSyncManagerTest;
   FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, PopulateSessionHeader);
@@ -150,16 +182,20 @@
 
   void InitializeCurrentMachineTag(const std::string& cache_guid);
 
-  // Load and add window or tab data from synced specifics to our internal
+  // Load and add window or tab data for a foreign session to our internal
   // tracking.
-  void UpdateTrackerWithSpecifics(const sync_pb::SessionSpecifics& specifics,
-                                  const base::Time& modification_time);
+  void UpdateTrackerWithForeignSession(
+      const sync_pb::SessionSpecifics& specifics,
+      const base::Time& modification_time);
 
   // Returns true if |sync_data| contained a header node for the current
-  // machine, false otherwise. |new_changes| is a link to the SyncChange
-  // pipeline that exists in the caller's context. This function will append
-  // necessary changes for processing later.
+  // machine, false otherwise. |restored_tabs| is a filtered tab-only
+  // subset of |sync_data| returned by this function for convenience.
+  // |new_changes| is a link to the SyncChange pipeline that exists in the
+  // caller's context. This function will append necessary changes for
+  // processing later.
   bool InitFromSyncModel(const syncer::SyncDataList& sync_data,
+                         syncer::SyncDataList* restored_tabs,
                          syncer::SyncChangeList* new_changes);
 
   // Helper to construct a deletion SyncChange for a *tab node*.
@@ -208,6 +244,11 @@
   // RELOAD_TABS will additionally cause a resync of all tabs (same as calling
   // AssociateTabs with a vector of all tabs).
   //
+  // |restored_tabs| is a filtered tab-only subset of initial sync data, if
+  // available (during MergeDataAndStartSyncing). It can be used to obtain
+  // baseline SessionSpecifics for tabs we can't fully associate any other
+  // way because they don't yet have a WebContents.
+  //
   // Returns: false if the local session's sync nodes were deleted and
   // reassociation is necessary, true otherwise.
   //
@@ -216,6 +257,7 @@
   // changes for processing later.
   enum ReloadTabsOption { RELOAD_TABS, DONT_RELOAD_TABS };
   void AssociateWindows(ReloadTabsOption option,
+                        const syncer::SyncDataList& restored_tabs,
                         syncer::SyncChangeList* change_output);
 
   // Loads and reassociates the local tabs referenced in |tabs|.
@@ -244,10 +286,17 @@
   // as they may have changed after a session was restored.  This method
   // compares new_tab_id and new_window_id against the previously persisted tab
   // ID and window ID (from our TabNodePool) and updates them if either differs.
+  // |restored_tabs| is a filtered tab-only subset of initial sync data, if
+  // available (during MergeDataAndStartSyncing). It can be used to obtain
+  // baseline SessionSpecifics for tabs we can't fully associate any other
+  // way because they don't yet have a WebContents.
+  // TODO(tim): Bug 98892. We should be able to test this for this on android
+  // even though we didn't have tests for old API-based sessions sync.
   void AssociateRestoredPlaceholderTab(
       const SyncedTabDelegate& tab_delegate,
       SessionID::id_type new_tab_id,
       SessionID::id_type new_window_id,
+      const syncer::SyncDataList& restored_tabs,
       syncer::SyncChangeList* change_output);
 
   // Stops and re-starts syncing to rebuild association mappings. Returns true
@@ -274,9 +323,15 @@
   // The client of this sync sessions datatype.
   SyncSessionsClient* const sessions_client_;
 
+  // Mapping of current open (local) tabs to their sync identifiers.
+  TabLinksMap local_tab_map_;
+
   SyncedSessionTracker session_tracker_;
   FaviconCache favicon_cache_;
 
+  // Pool of used/available sync nodes associated with local tabs.
+  TabNodePool local_tab_pool_;
+
   // Tracks whether our local representation of which sync nodes map to what
   // tabs (belonging to the current local session) is inconsistent.  This can
   // happen if a foreign client deems our session as "stale" and decides to
diff --git a/components/sync_sessions/synced_session_tracker.cc b/components/sync_sessions/synced_session_tracker.cc
index 2653b53..a74b877c 100644
--- a/components/sync_sessions/synced_session_tracker.cc
+++ b/components/sync_sessions/synced_session_tracker.cc
@@ -53,8 +53,6 @@
 
 void SyncedSessionTracker::SetLocalSessionTag(
     const std::string& local_session_tag) {
-  DCHECK(local_session_tag_.empty());
-  DCHECK(!local_session_tag.empty());
   local_session_tag_ = local_session_tag;
 }
 
@@ -92,9 +90,6 @@
     const std::string& tag,
     SessionID::id_type tab_id,
     const sessions::SessionTab** tab) const {
-  if (tab_id == TabNodePool::kInvalidTabID)
-    return false;
-
   DCHECK(tab);
   auto tab_map_iter = synced_tab_map_.find(tag);
   if (tab_map_iter == synced_tab_map_.end()) {
@@ -112,9 +107,8 @@
   return true;
 }
 
-void SyncedSessionTracker::LookupForeignTabNodeIds(
-    const std::string& session_tag,
-    std::set<int>* tab_node_ids) const {
+void SyncedSessionTracker::LookupTabNodeIds(const std::string& session_tag,
+                                            std::set<int>* tab_node_ids) {
   tab_node_ids->clear();
   auto session_iter = synced_session_map_.find(session_tag);
   if (session_iter != synced_session_map_.end()) {
@@ -150,9 +144,7 @@
   return synced_session_map_[session_tag].get();
 }
 
-bool SyncedSessionTracker::DeleteForeignSession(
-    const std::string& session_tag) {
-  DCHECK_NE(local_session_tag_, session_tag);
+bool SyncedSessionTracker::DeleteSession(const std::string& session_tag) {
   unmapped_windows_.erase(session_tag);
   unmapped_tabs_.erase(session_tag);
 
@@ -196,14 +188,13 @@
 
 void SyncedSessionTracker::DeleteForeignTab(const std::string& session_tag,
                                             int tab_node_id) {
-  DCHECK_NE(local_session_tag_, session_tag);
   auto session_iter = synced_session_map_.find(session_tag);
   if (session_iter != synced_session_map_.end()) {
     session_iter->second->tab_node_ids.erase(tab_node_id);
   }
 }
 
-void SyncedSessionTracker::CleanupSessionImpl(const std::string& session_tag) {
+void SyncedSessionTracker::CleanupSession(const std::string& session_tag) {
   for (const auto& window_pair : unmapped_windows_[session_tag])
     synced_window_map_[session_tag].erase(window_pair.first);
   unmapped_windows_[session_tag].clear();
@@ -213,11 +204,6 @@
   unmapped_tabs_[session_tag].clear();
 }
 
-bool SyncedSessionTracker::IsTabUnmappedForTesting(SessionID::id_type tab_id) {
-  auto it = unmapped_tabs_[local_session_tag_].find(tab_id);
-  return it != unmapped_tabs_[local_session_tag_].end();
-}
-
 void SyncedSessionTracker::PutWindowInSession(const std::string& session_tag,
                                               SessionID::id_type window_id) {
   std::unique_ptr<sessions::SessionWindow> window;
@@ -247,19 +233,20 @@
 
 void SyncedSessionTracker::PutTabInWindow(const std::string& session_tag,
                                           SessionID::id_type window_id,
-                                          SessionID::id_type tab_id) {
+                                          SessionID::id_type tab_id,
+                                          size_t tab_index) {
   // We're called here for two reasons. 1) We've received an update to the
-  // SessionWindow information of a SessionHeader node for a session,
+  // SessionWindow information of a SessionHeader node for a foreign session,
   // and 2) The SessionHeader node for our local session changed. In both cases
   // we need to update our tracking state to reflect the change.
   //
   // Because the SessionHeader nodes are separate from the individual tab nodes
   // and we don't store tab_node_ids in the header / SessionWindow specifics,
-  // the tab_node_ids are not always available when processing headers. We know
-  // that we will eventually process (via GetTab) every single tab node in the
-  // system, so we permit ourselves to just call GetTab and ignore the result,
-  // creating a placeholder SessionTab in the process.
-  GetTab(session_tag, tab_id);
+  // the tab_node_ids are not always available when processing headers.
+  // We know that we will eventually process (via GetTab) every single tab node
+  // in the system, so we permit ourselves to use kInvalidTabNodeID here and
+  // rely on the later update to build the mapping (or a restart).
+  GetTabImpl(session_tag, tab_id, TabNodePool::kInvalidTabNodeID);
 
   // The tab should be unmapped.
   std::unique_ptr<sessions::SessionTab> tab;
@@ -268,30 +255,60 @@
     tab = std::move(it->second);
     unmapped_tabs_[session_tag].erase(it);
   }
-  CHECK(tab) << "crbug.com/673618 Attempting to map tab " << tab_id
-             << " multiple times!";
+  DCHECK(tab);
 
   tab->window_id.set_id(window_id);
   DVLOG(1) << "  - tab " << tab_id << " added to window " << window_id;
   DCHECK(GetSession(session_tag)->windows.find(window_id) !=
          GetSession(session_tag)->windows.end());
   auto& window_tabs = GetSession(session_tag)->windows[window_id]->tabs;
-  window_tabs.push_back(std::move(tab));
-}
-
-void SyncedSessionTracker::OnTabNodeSeen(const std::string& session_tag,
-                                         int tab_node_id) {
-  GetSession(session_tag)->tab_node_ids.insert(tab_node_id);
+  if (window_tabs.size() <= tab_index) {
+    window_tabs.resize(tab_index + 1);
+  }
+  DCHECK(!window_tabs[tab_index]);
+  window_tabs[tab_index] = std::move(tab);
 }
 
 sessions::SessionTab* SyncedSessionTracker::GetTab(
     const std::string& session_tag,
-    SessionID::id_type tab_id) {
-  CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_id) << "crbug.com/673618";
+    SessionID::id_type tab_id,
+    int tab_node_id) {
+  DCHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id);
+  return GetTabImpl(session_tag, tab_id, tab_node_id);
+}
+
+sessions::SessionTab* SyncedSessionTracker::GetTabImpl(
+    const std::string& session_tag,
+    SessionID::id_type tab_id,
+    int tab_node_id) {
   sessions::SessionTab* tab_ptr = nullptr;
   auto iter = synced_tab_map_[session_tag].find(tab_id);
   if (iter != synced_tab_map_[session_tag].end()) {
     tab_ptr = iter->second;
+    if (tab_node_id != TabNodePool::kInvalidTabNodeID &&
+        tab_id != TabNodePool::kInvalidTabID) {
+      // TabIDs are not stable across restarts of a client. Consider this
+      // example with two tabs:
+      //
+      // http://a.com  TabID1 --> NodeIDA
+      // http://b.com  TabID2 --> NodeIDB
+      //
+      // After restart, tab ids are reallocated. e.g, one possibility:
+      // http://a.com TabID2 --> NodeIDA
+      // http://b.com TabID1 --> NodeIDB
+      //
+      // If that happend on a remote client, here we will see an update to
+      // TabID1 with tab_node_id changing from NodeIDA to NodeIDB, and TabID2
+      // with tab_node_id changing from NodeIDB to NodeIDA.
+      //
+      // We can also wind up here if we created this tab as an out-of-order
+      // update to the header node for this session before actually associating
+      // the tab itself, so the tab node id wasn't available at the time and
+      // is currently kInvalidTabNodeID.
+      //
+      // In both cases, we can safely throw it into the set of node ids.
+      GetSession(session_tag)->tab_node_ids.insert(tab_node_id);
+    }
 
     if (VLOG_IS_ON(1)) {
       std::string title;
@@ -311,6 +328,7 @@
     tab->tab_id.set_id(tab_id);
     synced_tab_map_[session_tag][tab_id] = tab_ptr;
     unmapped_tabs_[session_tag][tab_id] = std::move(tab);
+    GetSession(session_tag)->tab_node_ids.insert(tab_node_id);
     DVLOG(1) << "Getting "
              << (session_tag == local_session_tag_ ? "local session"
                                                    : session_tag)
@@ -321,99 +339,6 @@
   return tab_ptr;
 }
 
-void SyncedSessionTracker::CleanupForeignSession(
-    const std::string& session_tag) {
-  DCHECK_NE(local_session_tag_, session_tag);
-  CleanupSessionImpl(session_tag);
-}
-
-void SyncedSessionTracker::CleanupLocalTabs(std::set<int>* deleted_node_ids) {
-  DCHECK(!local_session_tag_.empty());
-  for (const auto& tab_pair : unmapped_tabs_[local_session_tag_])
-    local_tab_pool_.FreeTab(tab_pair.first);
-  CleanupSessionImpl(local_session_tag_);
-  local_tab_pool_.CleanupTabNodes(deleted_node_ids);
-  for (int tab_node_id : *deleted_node_ids) {
-    GetSession(local_session_tag_)->tab_node_ids.erase(tab_node_id);
-  }
-}
-
-bool SyncedSessionTracker::GetTabNodeFromLocalTabId(SessionID::id_type tab_id,
-                                                    int* tab_node_id) {
-  DCHECK(!local_session_tag_.empty());
-  // Ensure a placeholder SessionTab is in place, if not already.
-  // Although we don't need a SessionTab to fulfill this request, this forces
-  // the
-  // creation of one if it doesn't already exist. This helps to make sure we're
-  // tracking this |tab_id| if |local_tab_pool_| is, and everyone's data
-  // structures
-  // are kept in sync and as consistent as possible.
-  GetTab(local_session_tag_, tab_id);  // Ignore result.
-
-  bool reused_existing_tab =
-      local_tab_pool_.GetTabNodeForTab(tab_id, tab_node_id);
-  DCHECK_NE(TabNodePool::kInvalidTabNodeID, *tab_node_id);
-  GetSession(local_session_tag_)->tab_node_ids.insert(*tab_node_id);
-  return reused_existing_tab;
-}
-
-bool SyncedSessionTracker::IsLocalTabNodeAssociated(int tab_node_id) {
-  if (tab_node_id == TabNodePool::kInvalidTabNodeID)
-    return false;
-  return local_tab_pool_.GetTabIdFromTabNodeId(tab_node_id) !=
-         TabNodePool::kInvalidTabID;
-}
-
-void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
-                                               SessionID::id_type new_tab_id) {
-  DCHECK(!local_session_tag_.empty());
-  DCHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id);
-  DCHECK_NE(TabNodePool::kInvalidTabID, new_tab_id);
-
-  SessionID::id_type old_tab_id =
-      local_tab_pool_.GetTabIdFromTabNodeId(tab_node_id);
-  local_tab_pool_.ReassociateTabNode(tab_node_id, new_tab_id);
-
-  sessions::SessionTab* tab_ptr = nullptr;
-
-  auto old_tab_iter = synced_tab_map_[local_session_tag_].find(old_tab_id);
-  if (old_tab_id != TabNodePool::kInvalidTabID &&
-      old_tab_iter != synced_tab_map_[local_session_tag_].end()) {
-    tab_ptr = old_tab_iter->second;
-    // Remove the tab from the synced tab map under the old id.
-    synced_tab_map_[local_session_tag_].erase(old_tab_iter);
-  } else {
-    // It's possible a placeholder is already in place for the new tab. If so,
-    // reuse it, otherwise create a new one (which will default to unmapped).
-    tab_ptr = GetTab(local_session_tag_, new_tab_id);
-  }
-
-  // If the old tab is unmapped, update the tab id under which it is indexed.
-  auto unmapped_tabs_iter = unmapped_tabs_[local_session_tag_].find(old_tab_id);
-  if (old_tab_id != TabNodePool::kInvalidTabID &&
-      unmapped_tabs_iter != unmapped_tabs_[local_session_tag_].end()) {
-    std::unique_ptr<sessions::SessionTab> tab =
-        std::move(unmapped_tabs_iter->second);
-    DCHECK_EQ(tab_ptr, tab.get());
-    unmapped_tabs_[local_session_tag_].erase(unmapped_tabs_iter);
-    unmapped_tabs_[local_session_tag_][new_tab_id] = std::move(tab);
-  }
-
-  // Update the tab id.
-  if (old_tab_id != TabNodePool::kInvalidTabID) {
-    DVLOG(1) << "Remapped tab " << old_tab_id << " with node " << tab_node_id
-             << " to tab " << new_tab_id;
-  } else {
-    DVLOG(1) << "Mapped new tab node " << tab_node_id << " to tab "
-             << new_tab_id;
-  }
-  tab_ptr->tab_id.set_id(new_tab_id);
-
-  // Add the tab back into the tab map with the new id.
-  synced_tab_map_[local_session_tag_][new_tab_id] = tab_ptr;
-  GetSession(local_session_tag_)->tab_node_ids.insert(tab_node_id);
-}
-
 void SyncedSessionTracker::Clear() {
   // Cleanup unmapped tabs and windows.
   unmapped_windows_.clear();
@@ -427,7 +352,6 @@
   synced_window_map_.clear();
   synced_tab_map_.clear();
 
-  local_tab_pool_.Clear();
   local_session_tag_.clear();
 }
 
diff --git a/components/sync_sessions/synced_session_tracker.h b/components/sync_sessions/synced_session_tracker.h
index ccd47839..35123d7 100644
--- a/components/sync_sessions/synced_session_tracker.h
+++ b/components/sync_sessions/synced_session_tracker.h
@@ -40,7 +40,8 @@
   explicit SyncedSessionTracker(SyncSessionsClient* sessions_client);
   ~SyncedSessionTracker();
 
-  // **** Synced session/tab query methods. ****
+  // We track and distinguish the local session from foreign sessions.
+  void SetLocalSessionTag(const std::string& local_session_tag);
 
   // Fill a preallocated vector with all foreign sessions we're tracking (skips
   // the local session object). SyncedSession ownership remains within the
@@ -50,11 +51,6 @@
   bool LookupAllForeignSessions(std::vector<const SyncedSession*>* sessions,
                                 SessionLookup lookup) const;
 
-  // Fills |tab_node_ids| with the tab node ids (see GetTab) for all the tabs*
-  // associated with the session having tag |session_tag|.
-  void LookupForeignTabNodeIds(const std::string& session_tag,
-                               std::set<int>* tab_node_ids) const;
-
   // Attempts to look up the session windows associatd with the session given
   // by |session_tag|. Ownership of SessionWindows stays within the
   // SyncedSessionTracker.
@@ -80,13 +76,15 @@
   // this won't create-if-not-present.
   bool LookupLocalSession(const SyncedSession** output) const;
 
-  // **** Methods for manipulating synced sessions and tabs. ****
-
   // Returns a pointer to the SyncedSession object associated with
   // |session_tag|. If none exists, creates one. Ownership of the
   // SyncedSession remains within the SyncedSessionTracker.
   SyncedSession* GetSession(const std::string& session_tag);
 
+  // Deletes the session associated with |session_tag| if it exists.
+  // Returns true if the session existed and was deleted, false otherwise.
+  bool DeleteSession(const std::string& session_tag);
+
   // Resets the tracking information for the session specified by |session_tag|.
   // This involves clearing all the windows and tabs from the session, while
   // keeping pointers saved in the synced_window_map_ and synced_tab_map_. Once
@@ -96,6 +94,19 @@
   // tabs not owned.
   void ResetSessionTracking(const std::string& session_tag);
 
+  // Tracks the deletion of a foreign tab by removing the given |tab_node_id|
+  // from the parent session. Doesn't actually remove any tab objects because
+  // the header may have or may not have already been updated to no longer
+  // parent this tab. Regardless, when the header is updated then cleanup will
+  // remove the actual tab data. However, this method always needs to be called
+  // upon foreign tab deletion, otherwise LookupTabNodeIds(...) may return
+  // already deleted tab node ids.
+  void DeleteForeignTab(const std::string& session_tag, int tab_node_id);
+
+  // Deletes those windows and tabs associated with |session_tag| that are no
+  // longer owned. See ResetSessionTracking(...).
+  void CleanupSession(const std::string& session_tag);
+
   // Adds the window with id |window_id| to the session specified by
   // |session_tag|. If none existed for that session, creates one. Similarly, if
   // the session did not exist yet, creates it. Ownership of the SessionWindow
@@ -111,71 +122,21 @@
   // ensure we having mapping information for this session.
   void PutTabInWindow(const std::string& session_tag,
                       SessionID::id_type window_id,
-                      SessionID::id_type tab_id);
+                      SessionID::id_type tab_id,
+                      size_t tab_index);
 
-  // Adds |tab_node_id| to the session specified by |session_tag|, creating that
-  // session if necessary. This is necessary to ensure that each session has an
-  // up to date list of tab nodes linked to it for session deletion purposes.
-  // Note that this won't update the local tab pool, even if the local session
-  // tag is passed. The tab pool is only updated with new tab nodes when they're
-  // associated with a tab id (see ReassociateLocalTabNode or
-  // GetTabNodeFromLocalTabId).
-  void OnTabNodeSeen(const std::string& session_tag, int tab_node_id);
-
-  // Returns a pointer to the SessionTab object associated with
-  // |tab_id| for the session specified with |session_tag|.
-  // Note: Ownership of the SessionTab remains within the SyncedSessionTracker.
-  // TODO(zea): Replace SessionTab with a Sync specific wrapper.
-  // crbug.com/662597
+  // Returns a pointer to the SessionTab object associated with |tab_id| for
+  // the session specified with |session_tag|. If none exists, creates one.
+  // Ownership of the SessionTab remains within the SyncedSessionTracker.
+  // |tab_node_id| must be a valid node id for the node backing this tab.
   sessions::SessionTab* GetTab(const std::string& session_tag,
-                               SessionID::id_type tab_id);
+                               SessionID::id_type tab_id,
+                               int tab_node_id);
 
-  // **** Methods specific to foreign sessions. ****
-
-  // Tracks the deletion of a foreign tab by removing the given |tab_node_id|
-  // from the parent session. Doesn't actually remove any tab objects because
-  // the header may have or may not have already been updated to no longer
-  // parent this tab. Regardless, when the header is updated then cleanup will
-  // remove the actual tab data. However, this method always needs to be called
-  // upon foreign tab deletion, otherwise LookupTabNodeIds(...) may return
-  // already deleted tab node ids.
-  void DeleteForeignTab(const std::string& session_tag, int tab_node_id);
-
-  // Deletes the session associated with |session_tag| if it exists.
-  // Returns true if the session existed and was deleted, false otherwise.
-  bool DeleteForeignSession(const std::string& session_tag);
-
-  // Deletes those windows and tabs associated with |session_tag| that are no
-  // longer owned. See ResetSessionTracking(...)..
-  void CleanupForeignSession(const std::string& session_tag);
-
-  // **** Methods specific to the local session. ****
-
-  // Set the local session tag. Must be called before any other local session
-  // methods are invoked.
-  void SetLocalSessionTag(const std::string& local_session_tag);
-
-  // Similar to CleanupForeignSession, but also marks any unmapped tabs as free
-  // in the tab node pool and fills |deleted_node_ids| with the set of locally
-  // free tab nodes to be deleted.
-  void CleanupLocalTabs(std::set<int>* deleted_node_ids);
-
-  // Fills |tab_node_id| with a tab node for |tab_id|. Returns true if an
-  // existing tab node was found, false if there was none and one had to be
-  // created.
-  bool GetTabNodeFromLocalTabId(SessionID::id_type tab_id, int* tab_node_id);
-
-  // Returns whether |tab_node_id| refers to a valid tab node that is associated
-  // with a tab.
-  bool IsLocalTabNodeAssociated(int tab_node_id);
-
-  // Reassociates the tab denoted by |tab_node_id| with a new tab id, preserving
-  // any previous SessionTab object the node was associated with. This is useful
-  // on restart when sync needs to reassociate tabs from a previous session with
-  // newly restored tabs (and can be used in conjunction with PutTabInWindow).
-  void ReassociateLocalTab(int tab_node_id, SessionID::id_type new_tab_id);
-
-  // **** Methods for querying/manipulating overall state ****.
+  // Fills |tab_node_ids| with the tab node ids (see GetTab) for all the tabs*
+  // associated with the session having tag |session_tag|.
+  void LookupTabNodeIds(const std::string& session_tag,
+                        std::set<int>* tab_node_ids);
 
   // Free the memory for all dynamically allocated objects and clear the
   // tracking structures.
@@ -198,25 +159,21 @@
     }
   }
 
-  // Returns whether a tab is unmapped or not.
-  bool IsTabUnmappedForTesting(SessionID::id_type tab_id);
-
  private:
-  friend class SessionsSyncManagerTest;
-  friend class SyncedSessionTrackerTest;
-
-  // Implementation of CleanupForeignSession/CleanupLocalTabs.
-  void CleanupSessionImpl(const std::string& session_tag);
+  // Implementation for GetTab(...) above, permits invalid tab_node_id.
+  sessions::SessionTab* GetTabImpl(const std::string& session_tag,
+                                   SessionID::id_type tab_id,
+                                   int tab_node_id);
 
   // The client of the sync sessions datatype.
   SyncSessionsClient* const sessions_client_;
 
-  // The mapping of tab/window to their SessionTab/SessionWindow objects.
+  // The mapping of tab/window ids to their SessionTab/SessionWindow objects.
   // The SessionTab/SessionWindow objects referred to may be owned either by the
   // session in the |synced_session_map_| or be temporarily unmapped and live in
   // the |unmapped_tabs_|/|unmapped_windows_| collections.
   //
-  // Map: session tag -> (tab/window -> SessionTab*/SessionWindow*)
+  // Map: session tag -> (tab/window id -> SessionTab*/SessionWindow*)
   std::map<std::string, std::map<SessionID::id_type, sessions::SessionTab*>>
       synced_tab_map_;
   std::map<std::string, std::map<SessionID::id_type, sessions::SessionWindow*>>
@@ -246,9 +203,6 @@
   // sessions.
   std::string local_session_tag_;
 
-  // Pool of used/available sync nodes associated with local tabs.
-  TabNodePool local_tab_pool_;
-
   DISALLOW_COPY_AND_ASSIGN(SyncedSessionTracker);
 };
 
diff --git a/components/sync_sessions/synced_session_tracker_unittest.cc b/components/sync_sessions/synced_session_tracker_unittest.cc
index 366c9cb..68c1f471 100644
--- a/components/sync_sessions/synced_session_tracker_unittest.cc
+++ b/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -17,15 +17,6 @@
 
 const char kValidUrl[] = "http://www.example.com";
 const char kInvalidUrl[] = "invalid.url";
-const char kTag[] = "tag";
-const char kTag2[] = "tag2";
-const char kTag3[] = "tag3";
-const char kTitle[] = "title";
-const int kWindow1 = 1;
-const int kTabNode = 0;
-const int kTab1 = 15;
-const int kTab2 = 25;
-const int kTab3 = 35;
 
 }  // namespace
 
@@ -35,7 +26,6 @@
   ~SyncedSessionTrackerTest() override {}
 
   SyncedSessionTracker* GetTracker() { return &tracker_; }
-  TabNodePool* GetTabNodePool() { return &tracker_.local_tab_pool_; }
 
  private:
   FakeSyncSessionsClient sessions_client_;
@@ -43,33 +33,34 @@
 };
 
 TEST_F(SyncedSessionTrackerTest, GetSession) {
-  SyncedSession* session1 = GetTracker()->GetSession(kTag);
-  SyncedSession* session2 = GetTracker()->GetSession(kTag2);
-  ASSERT_EQ(session1, GetTracker()->GetSession(kTag));
+  SyncedSession* session1 = GetTracker()->GetSession("tag");
+  SyncedSession* session2 = GetTracker()->GetSession("tag2");
+  ASSERT_EQ(session1, GetTracker()->GetSession("tag"));
   ASSERT_NE(session1, session2);
   // Should clean up memory on its own.
 }
 
 TEST_F(SyncedSessionTrackerTest, GetTabUnmapped) {
-  sessions::SessionTab* tab = GetTracker()->GetTab(kTag, 0);
-  ASSERT_EQ(tab, GetTracker()->GetTab(kTag, 0));
+  sessions::SessionTab* tab = GetTracker()->GetTab("tag", 0, 0);
+  ASSERT_EQ(tab, GetTracker()->GetTab("tag", 0, 0));
   // Should clean up memory on its own.
 }
 
 TEST_F(SyncedSessionTrackerTest, PutWindowInSession) {
-  GetTracker()->PutWindowInSession(kTag, 0);
-  SyncedSession* session = GetTracker()->GetSession(kTag);
+  GetTracker()->PutWindowInSession("tag", 0);
+  SyncedSession* session = GetTracker()->GetSession("tag");
   ASSERT_EQ(1U, session->windows.size());
   // Should clean up memory on its own.
 }
 
 TEST_F(SyncedSessionTrackerTest, PutTabInWindow) {
-  GetTracker()->PutWindowInSession(kTag, 10);
-  GetTracker()->PutTabInWindow(kTag, 10, 15);  // win id 10, tab id 15
-  SyncedSession* session = GetTracker()->GetSession(kTag);
+  GetTracker()->PutWindowInSession("tag", 10);
+  GetTracker()->PutTabInWindow("tag", 10, 15,
+                               0);  // win id 10, tab id 15, tab ind 0.
+  SyncedSession* session = GetTracker()->GetSession("tag");
   ASSERT_EQ(1U, session->windows.size());
   ASSERT_EQ(1U, session->windows[10]->tabs.size());
-  ASSERT_EQ(GetTracker()->GetTab(kTag, 15),
+  ASSERT_EQ(GetTracker()->GetTab("tag", 15, 1),
             session->windows[10]->tabs[0].get());
   // Should clean up memory on its own.
 }
@@ -78,28 +69,28 @@
   std::vector<const SyncedSession*> sessions;
   ASSERT_FALSE(GetTracker()->LookupAllForeignSessions(
       &sessions, SyncedSessionTracker::PRESENTABLE));
-  GetTracker()->GetSession(kTag);
-  GetTracker()->PutWindowInSession(kTag, 0);
-  GetTracker()->PutTabInWindow(kTag, 0, 15);
-  sessions::SessionTab* tab = GetTracker()->GetTab(kTag, 15);
+  GetTracker()->GetSession("tag1");
+  GetTracker()->PutWindowInSession("tag1", 0);
+  GetTracker()->PutTabInWindow("tag1", 0, 15, 0);
+  sessions::SessionTab* tab = GetTracker()->GetTab("tag1", 15, 1);
   ASSERT_TRUE(tab);
   tab->navigations.push_back(
       sessions::SerializedNavigationEntryTestHelper::CreateNavigation(kValidUrl,
-                                                                      kTitle));
-  GetTracker()->GetSession(kTag2);
-  GetTracker()->GetSession(kTag3);
-  GetTracker()->PutWindowInSession(kTag3, 0);
-  GetTracker()->PutTabInWindow(kTag3, 0, 15);
-  tab = GetTracker()->GetTab(kTag3, 15);
+                                                                      "title"));
+  GetTracker()->GetSession("tag2");
+  GetTracker()->GetSession("tag3");
+  GetTracker()->PutWindowInSession("tag3", 0);
+  GetTracker()->PutTabInWindow("tag3", 0, 15, 0);
+  tab = GetTracker()->GetTab("tag3", 15, 1);
   ASSERT_TRUE(tab);
   tab->navigations.push_back(
       sessions::SerializedNavigationEntryTestHelper::CreateNavigation(
-          kInvalidUrl, kTitle));
+          kInvalidUrl, "title"));
   ASSERT_TRUE(GetTracker()->LookupAllForeignSessions(
       &sessions, SyncedSessionTracker::PRESENTABLE));
   // Only the session with a valid window and tab gets returned.
   ASSERT_EQ(1U, sessions.size());
-  ASSERT_EQ(kTag, sessions[0]->session_tag);
+  ASSERT_EQ("tag1", sessions[0]->session_tag);
 
   ASSERT_TRUE(GetTracker()->LookupAllForeignSessions(
       &sessions, SyncedSessionTracker::RAW));
@@ -108,15 +99,15 @@
 
 TEST_F(SyncedSessionTrackerTest, LookupSessionWindows) {
   std::vector<const sessions::SessionWindow*> windows;
-  ASSERT_FALSE(GetTracker()->LookupSessionWindows(kTag, &windows));
-  GetTracker()->GetSession(kTag);
-  GetTracker()->PutWindowInSession(kTag, 0);
-  GetTracker()->PutWindowInSession(kTag, 2);
-  GetTracker()->GetSession(kTag2);
-  GetTracker()->PutWindowInSession(kTag2, 0);
-  GetTracker()->PutWindowInSession(kTag2, 2);
-  ASSERT_TRUE(GetTracker()->LookupSessionWindows(kTag, &windows));
-  ASSERT_EQ(2U, windows.size());  // Only windows from kTag session.
+  ASSERT_FALSE(GetTracker()->LookupSessionWindows("tag1", &windows));
+  GetTracker()->GetSession("tag1");
+  GetTracker()->PutWindowInSession("tag1", 0);
+  GetTracker()->PutWindowInSession("tag1", 2);
+  GetTracker()->GetSession("tag2");
+  GetTracker()->PutWindowInSession("tag2", 0);
+  GetTracker()->PutWindowInSession("tag2", 2);
+  ASSERT_TRUE(GetTracker()->LookupSessionWindows("tag1", &windows));
+  ASSERT_EQ(2U, windows.size());  // Only windows from tag1 session.
   ASSERT_NE((sessions::SessionWindow*)nullptr, windows[0]);
   ASSERT_NE((sessions::SessionWindow*)nullptr, windows[1]);
   ASSERT_NE(windows[1], windows[0]);
@@ -124,39 +115,40 @@
 
 TEST_F(SyncedSessionTrackerTest, LookupSessionTab) {
   const sessions::SessionTab* tab;
-  ASSERT_FALSE(
-      GetTracker()->LookupSessionTab(kTag, TabNodePool::kInvalidTabID, &tab));
-  ASSERT_FALSE(GetTracker()->LookupSessionTab(kTag, 5, &tab));
-  GetTracker()->GetSession(kTag);
-  GetTracker()->PutWindowInSession(kTag, 0);
-  GetTracker()->PutTabInWindow(kTag, 0, 5);
-  ASSERT_TRUE(GetTracker()->LookupSessionTab(kTag, 5, &tab));
+  ASSERT_FALSE(GetTracker()->LookupSessionTab("tag1", 5, &tab));
+  GetTracker()->GetSession("tag1");
+  GetTracker()->PutWindowInSession("tag1", 0);
+  GetTracker()->PutTabInWindow("tag1", 0, 5, 0);
+  ASSERT_TRUE(GetTracker()->LookupSessionTab("tag1", 5, &tab));
   ASSERT_NE((sessions::SessionTab*)nullptr, tab);
 }
 
 TEST_F(SyncedSessionTrackerTest, Complex) {
+  const std::string tag1 = "tag";
+  const std::string tag2 = "tag2";
+  const std::string tag3 = "tag3";
   std::vector<sessions::SessionTab *> tabs1, tabs2;
   sessions::SessionTab* temp_tab;
   ASSERT_TRUE(GetTracker()->Empty());
   ASSERT_EQ(0U, GetTracker()->num_synced_sessions());
-  ASSERT_EQ(0U, GetTracker()->num_synced_tabs(kTag));
-  tabs1.push_back(GetTracker()->GetTab(kTag, 0));
-  tabs1.push_back(GetTracker()->GetTab(kTag, 1));
-  tabs1.push_back(GetTracker()->GetTab(kTag, 2));
-  ASSERT_EQ(3U, GetTracker()->num_synced_tabs(kTag));
-  ASSERT_EQ(0U, GetTracker()->num_synced_sessions());
-  temp_tab = GetTracker()->GetTab(kTag, 0);  // Already created.
-  ASSERT_EQ(3U, GetTracker()->num_synced_tabs(kTag));
-  ASSERT_EQ(0U, GetTracker()->num_synced_sessions());
+  ASSERT_EQ(0U, GetTracker()->num_synced_tabs(tag1));
+  tabs1.push_back(GetTracker()->GetTab(tag1, 0, 0));
+  tabs1.push_back(GetTracker()->GetTab(tag1, 1, 1));
+  tabs1.push_back(GetTracker()->GetTab(tag1, 2, 2));
+  ASSERT_EQ(3U, GetTracker()->num_synced_tabs(tag1));
+  ASSERT_EQ(1U, GetTracker()->num_synced_sessions());
+  temp_tab = GetTracker()->GetTab(tag1, 0, 0);  // Already created.
+  ASSERT_EQ(3U, GetTracker()->num_synced_tabs(tag1));
+  ASSERT_EQ(1U, GetTracker()->num_synced_sessions());
   ASSERT_EQ(tabs1[0], temp_tab);
-  tabs2.push_back(GetTracker()->GetTab(kTag2, 0));
-  ASSERT_EQ(1U, GetTracker()->num_synced_tabs(kTag2));
-  ASSERT_EQ(0U, GetTracker()->num_synced_sessions());
-  ASSERT_FALSE(GetTracker()->DeleteForeignSession(kTag3));
+  tabs2.push_back(GetTracker()->GetTab(tag2, 0, 0));
+  ASSERT_EQ(1U, GetTracker()->num_synced_tabs(tag2));
+  ASSERT_EQ(2U, GetTracker()->num_synced_sessions());
+  ASSERT_FALSE(GetTracker()->DeleteSession(tag3));
 
-  SyncedSession* session = GetTracker()->GetSession(kTag);
-  SyncedSession* session2 = GetTracker()->GetSession(kTag2);
-  SyncedSession* session3 = GetTracker()->GetSession(kTag3);
+  SyncedSession* session = GetTracker()->GetSession(tag1);
+  SyncedSession* session2 = GetTracker()->GetSession(tag2);
+  SyncedSession* session3 = GetTracker()->GetSession(tag3);
   session3->device_type = SyncedSession::TYPE_OTHER;
   ASSERT_EQ(3U, GetTracker()->num_synced_sessions());
 
@@ -165,25 +157,25 @@
   ASSERT_TRUE(session3);
   ASSERT_NE(session, session2);
   ASSERT_NE(session2, session3);
-  ASSERT_TRUE(GetTracker()->DeleteForeignSession(kTag3));
+  ASSERT_TRUE(GetTracker()->DeleteSession(tag3));
   ASSERT_EQ(2U, GetTracker()->num_synced_sessions());
 
-  GetTracker()->PutWindowInSession(kTag, 0);           // Create a window.
-  GetTracker()->PutTabInWindow(kTag, 0, 2);            // No longer unmapped.
-  ASSERT_EQ(3U, GetTracker()->num_synced_tabs(kTag));  // Has not changed.
+  GetTracker()->PutWindowInSession(tag1, 0);           // Create a window.
+  GetTracker()->PutTabInWindow(tag1, 0, 2, 0);         // No longer unmapped.
+  ASSERT_EQ(3U, GetTracker()->num_synced_tabs(tag1));  // Has not changed.
 
   const sessions::SessionTab* tab_ptr;
-  ASSERT_TRUE(GetTracker()->LookupSessionTab(kTag, 0, &tab_ptr));
+  ASSERT_TRUE(GetTracker()->LookupSessionTab(tag1, 0, &tab_ptr));
   ASSERT_EQ(tab_ptr, tabs1[0]);
-  ASSERT_TRUE(GetTracker()->LookupSessionTab(kTag, 2, &tab_ptr));
+  ASSERT_TRUE(GetTracker()->LookupSessionTab(tag1, 2, &tab_ptr));
   ASSERT_EQ(tab_ptr, tabs1[2]);
-  ASSERT_FALSE(GetTracker()->LookupSessionTab(kTag, 3, &tab_ptr));
+  ASSERT_FALSE(GetTracker()->LookupSessionTab(tag1, 3, &tab_ptr));
   ASSERT_FALSE(tab_ptr);
 
   std::vector<const sessions::SessionWindow*> windows;
-  ASSERT_TRUE(GetTracker()->LookupSessionWindows(kTag, &windows));
+  ASSERT_TRUE(GetTracker()->LookupSessionWindows(tag1, &windows));
   ASSERT_EQ(1U, windows.size());
-  ASSERT_TRUE(GetTracker()->LookupSessionWindows(kTag2, &windows));
+  ASSERT_TRUE(GetTracker()->LookupSessionWindows(tag2, &windows));
   ASSERT_EQ(0U, windows.size());
 
   // The sessions don't have valid tabs, lookup should not succeed.
@@ -195,8 +187,8 @@
   ASSERT_EQ(2U, sessions.size());
 
   GetTracker()->Clear();
-  ASSERT_EQ(0U, GetTracker()->num_synced_tabs(kTag));
-  ASSERT_EQ(0U, GetTracker()->num_synced_tabs(kTag2));
+  ASSERT_EQ(0U, GetTracker()->num_synced_tabs(tag1));
+  ASSERT_EQ(0U, GetTracker()->num_synced_tabs(tag2));
   ASSERT_EQ(0U, GetTracker()->num_synced_sessions());
 }
 
@@ -211,101 +203,107 @@
       // More attempts than tabs means we'll sometimes get the same tabs,
       // sometimes have to allocate new tabs.
       int rand_tab_num = base::RandInt(0, kMaxTabs);
-      sessions::SessionTab* tab = GetTracker()->GetTab(tag, rand_tab_num + 1);
+      sessions::SessionTab* tab =
+          GetTracker()->GetTab(tag, rand_tab_num, rand_tab_num + 1);
       ASSERT_TRUE(tab);
     }
   }
 }
 
-TEST_F(SyncedSessionTrackerTest, LookupForeignTabNodeIds) {
+TEST_F(SyncedSessionTrackerTest, LookupTabNodeIds) {
   std::set<int> result;
+  std::string tag1 = "session1";
+  std::string tag2 = "session2";
+  std::string tag3 = "session3";
 
-  GetTracker()->OnTabNodeSeen(kTag, 1);
-  GetTracker()->OnTabNodeSeen(kTag, 2);
-  GetTracker()->LookupForeignTabNodeIds(kTag, &result);
+  GetTracker()->GetTab(tag1, 1, 1);
+  GetTracker()->GetTab(tag1, 2, 2);
+  GetTracker()->LookupTabNodeIds(tag1, &result);
   EXPECT_EQ(2U, result.size());
   EXPECT_FALSE(result.end() == result.find(1));
   EXPECT_FALSE(result.end() == result.find(2));
-  GetTracker()->LookupForeignTabNodeIds(kTag2, &result);
+  GetTracker()->LookupTabNodeIds(tag2, &result);
   EXPECT_TRUE(result.empty());
 
-  GetTracker()->PutWindowInSession(kTag, 0);
-  GetTracker()->PutTabInWindow(kTag, 0, 3);
-  GetTracker()->LookupForeignTabNodeIds(kTag, &result);
+  GetTracker()->PutWindowInSession(tag1, 0);
+  GetTracker()->PutTabInWindow(tag1, 0, 3, 0);
+  GetTracker()->LookupTabNodeIds(tag1, &result);
   EXPECT_EQ(2U, result.size());
 
-  GetTracker()->OnTabNodeSeen(kTag, 3);
-  GetTracker()->LookupForeignTabNodeIds(kTag, &result);
+  GetTracker()->GetTab(tag1, 3, 3);
+  GetTracker()->LookupTabNodeIds(tag1, &result);
   EXPECT_EQ(3U, result.size());
   EXPECT_FALSE(result.end() == result.find(3));
 
-  GetTracker()->OnTabNodeSeen(kTag2, 21);
-  GetTracker()->OnTabNodeSeen(kTag2, 22);
-  GetTracker()->LookupForeignTabNodeIds(kTag2, &result);
+  GetTracker()->GetTab(tag2, 1, 21);
+  GetTracker()->GetTab(tag2, 2, 22);
+  GetTracker()->LookupTabNodeIds(tag2, &result);
   EXPECT_EQ(2U, result.size());
   EXPECT_FALSE(result.end() == result.find(21));
   EXPECT_FALSE(result.end() == result.find(22));
-  GetTracker()->LookupForeignTabNodeIds(kTag, &result);
+  GetTracker()->LookupTabNodeIds(tag1, &result);
   EXPECT_EQ(3U, result.size());
   EXPECT_FALSE(result.end() == result.find(1));
   EXPECT_FALSE(result.end() == result.find(2));
 
-  GetTracker()->LookupForeignTabNodeIds(kTag3, &result);
+  GetTracker()->LookupTabNodeIds(tag3, &result);
   EXPECT_TRUE(result.empty());
-  GetTracker()->PutWindowInSession(kTag3, 1);
-  GetTracker()->PutTabInWindow(kTag3, 1, 5);
-  GetTracker()->LookupForeignTabNodeIds(kTag3, &result);
+  GetTracker()->PutWindowInSession(tag3, 1);
+  GetTracker()->PutTabInWindow(tag3, 1, 5, 0);
+  GetTracker()->LookupTabNodeIds(tag3, &result);
   EXPECT_TRUE(result.empty());
-  EXPECT_FALSE(GetTracker()->DeleteForeignSession(kTag3));
-  GetTracker()->LookupForeignTabNodeIds(kTag3, &result);
+  EXPECT_FALSE(GetTracker()->DeleteSession(tag3));
+  GetTracker()->LookupTabNodeIds(tag3, &result);
   EXPECT_TRUE(result.empty());
 
-  EXPECT_FALSE(GetTracker()->DeleteForeignSession(kTag));
-  GetTracker()->LookupForeignTabNodeIds(kTag, &result);
+  EXPECT_FALSE(GetTracker()->DeleteSession(tag1));
+  GetTracker()->LookupTabNodeIds(tag1, &result);
   EXPECT_TRUE(result.empty());
-  GetTracker()->LookupForeignTabNodeIds(kTag2, &result);
+  GetTracker()->LookupTabNodeIds(tag2, &result);
   EXPECT_EQ(2U, result.size());
   EXPECT_FALSE(result.end() == result.find(21));
   EXPECT_FALSE(result.end() == result.find(22));
 
-  GetTracker()->OnTabNodeSeen(kTag2, 21);
-  GetTracker()->OnTabNodeSeen(kTag2, 23);
-  GetTracker()->LookupForeignTabNodeIds(kTag2, &result);
+  GetTracker()->GetTab(tag2, 1, 21);
+  GetTracker()->GetTab(tag2, 2, 23);
+  GetTracker()->LookupTabNodeIds(tag2, &result);
   EXPECT_EQ(3U, result.size());
   EXPECT_FALSE(result.end() == result.find(21));
   EXPECT_FALSE(result.end() == result.find(22));
   EXPECT_FALSE(result.end() == result.find(23));
 
-  EXPECT_FALSE(GetTracker()->DeleteForeignSession(kTag2));
-  GetTracker()->LookupForeignTabNodeIds(kTag2, &result);
+  EXPECT_FALSE(GetTracker()->DeleteSession(tag2));
+  GetTracker()->LookupTabNodeIds(tag2, &result);
   EXPECT_TRUE(result.empty());
 }
 
 TEST_F(SyncedSessionTrackerTest, SessionTracking) {
   ASSERT_TRUE(GetTracker()->Empty());
+  std::string tag1 = "tag1";
+  std::string tag2 = "tag2";
 
   // Create some session information that is stale.
-  SyncedSession* session1 = GetTracker()->GetSession(kTag);
-  GetTracker()->PutWindowInSession(kTag, 0);
-  GetTracker()->PutTabInWindow(kTag, 0, 0);
-  GetTracker()->PutTabInWindow(kTag, 0, 1);
-  GetTracker()->GetTab(kTag, 2)->window_id.set_id(0);  // Will be unmapped.
-  GetTracker()->GetTab(kTag, 3)->window_id.set_id(0);  // Will be unmapped.
-  GetTracker()->PutWindowInSession(kTag, 1);
-  GetTracker()->PutTabInWindow(kTag, 1, 4);
-  GetTracker()->PutTabInWindow(kTag, 1, 5);
+  SyncedSession* session1 = GetTracker()->GetSession(tag1);
+  GetTracker()->PutWindowInSession(tag1, 0);
+  GetTracker()->PutTabInWindow(tag1, 0, 0, 0);
+  GetTracker()->PutTabInWindow(tag1, 0, 1, 1);
+  GetTracker()->GetTab(tag1, 2, 3U)->window_id.set_id(0);  // Will be unmapped.
+  GetTracker()->GetTab(tag1, 3, 4U)->window_id.set_id(0);  // Will be unmapped.
+  GetTracker()->PutWindowInSession(tag1, 1);
+  GetTracker()->PutTabInWindow(tag1, 1, 4, 0);
+  GetTracker()->PutTabInWindow(tag1, 1, 5, 1);
   ASSERT_EQ(2U, session1->windows.size());
   ASSERT_EQ(2U, session1->windows[0]->tabs.size());
   ASSERT_EQ(2U, session1->windows[1]->tabs.size());
-  ASSERT_EQ(6U, GetTracker()->num_synced_tabs(kTag));
+  ASSERT_EQ(6U, GetTracker()->num_synced_tabs(tag1));
 
   // Create a session that should not be affected.
-  SyncedSession* session2 = GetTracker()->GetSession(kTag2);
-  GetTracker()->PutWindowInSession(kTag2, 2);
-  GetTracker()->PutTabInWindow(kTag2, 2, 1);
+  SyncedSession* session2 = GetTracker()->GetSession(tag2);
+  GetTracker()->PutWindowInSession(tag2, 2);
+  GetTracker()->PutTabInWindow(tag2, 2, 1, 0);
   ASSERT_EQ(1U, session2->windows.size());
   ASSERT_EQ(1U, session2->windows[2]->tabs.size());
-  ASSERT_EQ(1U, GetTracker()->num_synced_tabs(kTag2));
+  ASSERT_EQ(1U, GetTracker()->num_synced_tabs(tag2));
 
   // Reset tracking and get the current windows/tabs.
   // We simulate moving a tab from one window to another, then closing the
@@ -313,18 +311,18 @@
   // on the remaining window.
 
   // New tab, arrived before meta node so unmapped.
-  GetTracker()->GetTab(kTag, 6);
-  GetTracker()->ResetSessionTracking(kTag);
-  GetTracker()->PutWindowInSession(kTag, 0);
-  GetTracker()->PutTabInWindow(kTag, 0, 0);
+  GetTracker()->GetTab(tag1, 6, 7U);
+  GetTracker()->ResetSessionTracking(tag1);
+  GetTracker()->PutWindowInSession(tag1, 0);
+  GetTracker()->PutTabInWindow(tag1, 0, 0, 0);
   // Tab 1 is closed.
-  GetTracker()->PutTabInWindow(kTag, 0, 2);  // No longer unmapped.
+  GetTracker()->PutTabInWindow(tag1, 0, 2, 1);  // No longer unmapped.
   // Tab 3 was unmapped and does not get used.
-  GetTracker()->PutTabInWindow(kTag, 0, 4);  // Moved from window 1.
+  GetTracker()->PutTabInWindow(tag1, 0, 4, 2);  // Moved from window 1.
   // Window 1 was closed, along with tab 5.
-  GetTracker()->PutTabInWindow(kTag, 0, 6);  // No longer unmapped.
+  GetTracker()->PutTabInWindow(tag1, 0, 6, 3);  // No longer unmapped.
   // Session 2 should not be affected.
-  GetTracker()->CleanupForeignSession(kTag);
+  GetTracker()->CleanupSession(tag1);
 
   // Verify that only those parts of the session not owned have been removed.
   ASSERT_EQ(1U, session1->windows.size());
@@ -332,172 +330,39 @@
   ASSERT_EQ(1U, session2->windows.size());
   ASSERT_EQ(1U, session2->windows[2]->tabs.size());
   ASSERT_EQ(2U, GetTracker()->num_synced_sessions());
-  ASSERT_EQ(4U, GetTracker()->num_synced_tabs(kTag));
-  ASSERT_EQ(1U, GetTracker()->num_synced_tabs(kTag2));
+  ASSERT_EQ(4U, GetTracker()->num_synced_tabs(tag1));
+  ASSERT_EQ(1U, GetTracker()->num_synced_tabs(tag2));
 
   // All memory should be properly deallocated by destructor for the
   // SyncedSessionTracker.
 }
 
 TEST_F(SyncedSessionTrackerTest, DeleteForeignTab) {
-  int tab_node_id_1 = 1;
-  int tab_node_id_2 = 2;
+  std::string session_tag = "session_tag";
+  int tab_id_1 = 1;
+  int tab_id_2 = 2;
+  int tab_node_id_3 = 3;
+  int tab_node_id_4 = 4;
   std::set<int> result;
 
-  GetTracker()->OnTabNodeSeen(kTag, tab_node_id_1);
-  GetTracker()->OnTabNodeSeen(kTag, tab_node_id_2);
+  GetTracker()->GetTab(session_tag, tab_id_1, tab_node_id_3);
+  GetTracker()->GetTab(session_tag, tab_id_1, tab_node_id_4);
+  GetTracker()->GetTab(session_tag, tab_id_2, tab_node_id_3);
+  GetTracker()->GetTab(session_tag, tab_id_2, tab_node_id_4);
 
-  GetTracker()->LookupForeignTabNodeIds(kTag, &result);
+  GetTracker()->LookupTabNodeIds(session_tag, &result);
   EXPECT_EQ(2U, result.size());
-  EXPECT_TRUE(result.find(tab_node_id_1) != result.end());
-  EXPECT_TRUE(result.find(tab_node_id_2) != result.end());
+  EXPECT_TRUE(result.find(tab_node_id_3) != result.end());
+  EXPECT_TRUE(result.find(tab_node_id_4) != result.end());
 
-  GetTracker()->DeleteForeignTab(kTag, tab_node_id_1);
-  GetTracker()->LookupForeignTabNodeIds(kTag, &result);
+  GetTracker()->DeleteForeignTab(session_tag, tab_node_id_3);
+  GetTracker()->LookupTabNodeIds(session_tag, &result);
   EXPECT_EQ(1U, result.size());
-  EXPECT_TRUE(result.find(tab_node_id_2) != result.end());
+  EXPECT_TRUE(result.find(tab_node_id_4) != result.end());
 
-  GetTracker()->DeleteForeignTab(kTag, tab_node_id_2);
-  GetTracker()->LookupForeignTabNodeIds(kTag, &result);
+  GetTracker()->DeleteForeignTab(session_tag, tab_node_id_4);
+  GetTracker()->LookupTabNodeIds(session_tag, &result);
   EXPECT_TRUE(result.empty());
 }
 
-TEST_F(SyncedSessionTrackerTest, CleanupLocalTabs) {
-  std::set<int> free_node_ids;
-  int tab_node_id = TabNodePool::kInvalidTabNodeID;
-  const int kTabNode1 = 1;
-  const int kTabNode2 = 2;
-  const int kTabNode3 = 3;
-
-  GetTracker()->SetLocalSessionTag(kTag);
-
-  // Start with two restored tab nodes.
-  GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
-  GetTracker()->ReassociateLocalTab(kTabNode2, kTab2);
-  EXPECT_TRUE(GetTabNodePool()->Empty());
-  EXPECT_FALSE(GetTabNodePool()->Full());
-  EXPECT_EQ(2U, GetTabNodePool()->Capacity());
-
-  // Associate with no tabs. The tab pool should now be full.
-  GetTracker()->ResetSessionTracking(kTag);
-  GetTracker()->CleanupLocalTabs(&free_node_ids);
-  EXPECT_TRUE(free_node_ids.empty());
-  EXPECT_TRUE(GetTabNodePool()->Full());
-
-  // Associate with only 1 tab open. A tab node should be reused.
-  GetTracker()->ResetSessionTracking(kTag);
-  GetTracker()->PutWindowInSession(kTag, kWindow1);
-  GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1);
-  EXPECT_TRUE(GetTracker()->GetTabNodeFromLocalTabId(kTab1, &tab_node_id));
-  GetTracker()->CleanupLocalTabs(&free_node_ids);
-  EXPECT_TRUE(free_node_ids.empty());
-
-  // TabNodePool should have one free tab node and one used.
-  EXPECT_EQ(2U, GetTabNodePool()->Capacity());
-  EXPECT_FALSE(GetTabNodePool()->Empty());
-  EXPECT_FALSE(GetTabNodePool()->Full());
-
-  // Simulate a tab opening, which should use the last free tab node.
-  EXPECT_TRUE(GetTracker()->GetTabNodeFromLocalTabId(kTab2, &tab_node_id));
-  EXPECT_TRUE(GetTabNodePool()->Empty());
-
-  // Simulate another tab opening, which should create a new associated tab
-  // node.
-  EXPECT_FALSE(GetTracker()->GetTabNodeFromLocalTabId(kTab3, &tab_node_id));
-  EXPECT_EQ(kTabNode3, tab_node_id);
-  EXPECT_EQ(3U, GetTabNodePool()->Capacity());
-  EXPECT_TRUE(GetTabNodePool()->Empty());
-
-  // Fetching the same tab should return the same tab node id.
-  EXPECT_TRUE(GetTracker()->GetTabNodeFromLocalTabId(kTab3, &tab_node_id));
-  EXPECT_EQ(kTabNode3, tab_node_id);
-  EXPECT_TRUE(GetTabNodePool()->Empty());
-
-  // Associate with no tabs. All tabs should be freed again, and the pool
-  // should now be full.
-  GetTracker()->ResetSessionTracking(kTag);
-  GetTracker()->CleanupLocalTabs(&free_node_ids);
-  EXPECT_TRUE(free_node_ids.empty());
-  EXPECT_TRUE(GetTabNodePool()->Full());
-  EXPECT_FALSE(GetTabNodePool()->Empty());
-}
-
-TEST_F(SyncedSessionTrackerTest, ReassociateTabMapped) {
-  std::set<int> free_node_ids;
-
-  // First create the tab normally.
-  GetTracker()->SetLocalSessionTag(kTag);
-  EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode));
-  GetTracker()->ReassociateLocalTab(kTabNode, kTab1);
-  EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode));
-  EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab1));
-
-  // Map it to a window with the same tab id as it was created with.
-  GetTracker()->ResetSessionTracking(kTag);
-  GetTracker()->PutWindowInSession(kTag, kWindow1);
-  GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1);
-  GetTracker()->CleanupLocalTabs(&free_node_ids);
-  EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
-  SyncedSession* session = GetTracker()->GetSession(kTag);
-  ASSERT_EQ(1U, session->windows.size());
-  ASSERT_EQ(1U, session->windows[kWindow1]->tabs.size());
-  ASSERT_EQ(GetTracker()->GetTab(kTag, kTab1),
-            session->windows[kWindow1]->tabs[0].get());
-
-  // Then reassociate with a new tab id.
-  GetTracker()->ReassociateLocalTab(kTabNode, kTab2);
-  EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode));
-  EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab2));
-  EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
-
-  // Reset tracking, and put the new tab id into the window.
-  GetTracker()->ResetSessionTracking(kTag);
-  EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab2));
-  GetTracker()->PutWindowInSession(kTag, kWindow1);
-  GetTracker()->PutTabInWindow(kTag, kWindow1, kTab2);
-  GetTracker()->CleanupLocalTabs(&free_node_ids);
-  EXPECT_TRUE(free_node_ids.empty());
-  EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab2));
-
-  // Now that it's been mapped, it should be accessible both via the
-  // GetSession as well as the GetTab.
-  ASSERT_EQ(GetTracker()->GetTab(kTag, kTab2),
-            session->windows[kWindow1]->tabs[0].get());
-  ASSERT_EQ(session->tab_node_ids.size(),
-            session->tab_node_ids.count(kTabNode));
-  ASSERT_EQ(1U, GetTabNodePool()->Capacity());
-}
-
-TEST_F(SyncedSessionTrackerTest, ReassociateTabUnmapped) {
-  std::set<int> free_node_ids;
-
-  // First create the old tab in an unmapped state.
-  GetTracker()->SetLocalSessionTag(kTag);
-  EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode));
-  GetTracker()->ReassociateLocalTab(kTabNode, kTab1);
-  EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode));
-  EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab1));
-
-  // Map it to a window, but reassociated with a new tab id.
-  GetTracker()->ResetSessionTracking(kTag);
-  GetTracker()->ReassociateLocalTab(kTabNode, kTab2);
-  EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode));
-  EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab2));
-  EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
-  GetTracker()->PutWindowInSession(kTag, kWindow1);
-  GetTracker()->PutTabInWindow(kTag, kWindow1, kTab2);
-  GetTracker()->CleanupLocalTabs(&free_node_ids);
-  EXPECT_TRUE(free_node_ids.empty());
-  EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab2));
-
-  // Now that it's been mapped, it should be accessible both via the
-  // GetSession as well as GetTab.
-  SyncedSession* session = GetTracker()->GetSession(kTag);
-  ASSERT_EQ(GetTracker()->GetTab(kTag, kTab2),
-            session->windows[kWindow1]->tabs[0].get());
-  ASSERT_EQ(session->tab_node_ids.size(),
-            session->tab_node_ids.count(kTabNode));
-  ASSERT_EQ(1U, GetTabNodePool()->Capacity());
-}
-
 }  // namespace sync_sessions
diff --git a/components/sync_sessions/tab_node_pool.cc b/components/sync_sessions/tab_node_pool.cc
index f187d23d..4067b92 100644
--- a/components/sync_sessions/tab_node_pool.cc
+++ b/components/sync_sessions/tab_node_pool.cc
@@ -4,10 +4,12 @@
 
 #include "components/sync_sessions/tab_node_pool.h"
 
-#include <algorithm>
-
+#include "base/format_macros.h"
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/model/sync_change.h"
+#include "components/sync/model/sync_data.h"
 #include "components/sync/protocol/session_specifics.pb.h"
 #include "components/sync/protocol/sync.pb.h"
 
@@ -24,91 +26,114 @@
 
 TabNodePool::~TabNodePool() {}
 
+// Static
+std::string TabNodePool::TabIdToTag(const std::string& machine_tag,
+                                    int tab_node_id) {
+  return base::StringPrintf("%s %d", machine_tag.c_str(), tab_node_id);
+}
+
 void TabNodePool::AddTabNode(int tab_node_id) {
   DCHECK_GT(tab_node_id, kInvalidTabNodeID);
   DCHECK(nodeid_tabid_map_.find(tab_node_id) == nodeid_tabid_map_.end());
-  DVLOG(1) << "Adding tab node " << tab_node_id << " to pool.";
-  max_used_tab_node_id_ = std::max(max_used_tab_node_id_, tab_node_id);
-  free_nodes_pool_.insert(tab_node_id);
+  unassociated_nodes_.insert(tab_node_id);
+  if (max_used_tab_node_id_ < tab_node_id)
+    max_used_tab_node_id_ = tab_node_id;
 }
 
 void TabNodePool::AssociateTabNode(int tab_node_id, SessionID::id_type tab_id) {
   DCHECK_GT(tab_node_id, kInvalidTabNodeID);
-  DCHECK_GT(tab_id, kInvalidTabID);
-
-  // This is a new node association, the sync node should be free.
-  // Remove node from free node pool and then associate it with the tab.
-  std::set<int>::iterator it = free_nodes_pool_.find(tab_node_id);
-  DCHECK(it != free_nodes_pool_.end());
-  free_nodes_pool_.erase(it);
-
+  // Remove sync node if it is in unassociated nodes pool.
+  std::set<int>::iterator u_it = unassociated_nodes_.find(tab_node_id);
+  if (u_it != unassociated_nodes_.end()) {
+    unassociated_nodes_.erase(u_it);
+  } else {
+    // This is a new node association, the sync node should be free.
+    // Remove node from free node pool and then associate it with the tab.
+    std::set<int>::iterator it = free_nodes_pool_.find(tab_node_id);
+    DCHECK(it != free_nodes_pool_.end());
+    free_nodes_pool_.erase(it);
+  }
   DCHECK(nodeid_tabid_map_.find(tab_node_id) == nodeid_tabid_map_.end());
-  DVLOG(1) << "Associating tab node " << tab_node_id << " with tab " << tab_id;
   nodeid_tabid_map_[tab_node_id] = tab_id;
-  tabid_nodeid_map_[tab_id] = tab_node_id;
 }
 
-bool TabNodePool::GetTabNodeForTab(SessionID::id_type tab_id,
-                                   int* tab_node_id) {
-  if (tabid_nodeid_map_.find(tab_id) != tabid_nodeid_map_.end()) {
-    *tab_node_id = tabid_nodeid_map_[tab_id];
-    return true;
-  }
-
+int TabNodePool::GetFreeTabNode(syncer::SyncChangeList* append_changes) {
+  DCHECK_GT(machine_tag_.length(), 0U);
+  DCHECK(append_changes);
   if (free_nodes_pool_.empty()) {
     // Tab pool has no free nodes, allocate new one.
-    *tab_node_id = ++max_used_tab_node_id_;
-    AddTabNode(*tab_node_id);
+    int tab_node_id = ++max_used_tab_node_id_;
+    std::string tab_node_tag = TabIdToTag(machine_tag_, tab_node_id);
 
-    AssociateTabNode(*tab_node_id, tab_id);
-    return false;
+    // We fill the new node with just enough data so that in case of a crash/bug
+    // we can identify the node as our own on re-association and reuse it.
+    sync_pb::EntitySpecifics entity;
+    sync_pb::SessionSpecifics* specifics = entity.mutable_session();
+    specifics->set_session_tag(machine_tag_);
+    specifics->set_tab_node_id(tab_node_id);
+    append_changes->push_back(syncer::SyncChange(
+        FROM_HERE, syncer::SyncChange::ACTION_ADD,
+        syncer::SyncData::CreateLocalData(tab_node_tag, tab_node_tag, entity)));
+
+    // Grow the pool by 1 since we created a new node.
+    DVLOG(1) << "Adding sync node " << tab_node_id << " to tab node id pool";
+    free_nodes_pool_.insert(tab_node_id);
+    return tab_node_id;
   } else {
     // Return the next free node.
-    *tab_node_id = *free_nodes_pool_.begin();
-    AssociateTabNode(*tab_node_id, tab_id);
-    return true;
+    return *free_nodes_pool_.begin();
   }
 }
 
-void TabNodePool::FreeTab(int tab_id) {
-  DCHECK_GT(tab_id, kInvalidTabID);
-  TabIDToTabNodeIDMap::iterator it = tabid_nodeid_map_.find(tab_id);
-  if (it == tabid_nodeid_map_.end()) {
-    return;  // Already freed.
-  }
+void TabNodePool::FreeTabNode(int tab_node_id,
+                              syncer::SyncChangeList* append_changes) {
+  DCHECK(append_changes);
+  TabNodeIDToTabIDMap::iterator it = nodeid_tabid_map_.find(tab_node_id);
+  DCHECK(it != nodeid_tabid_map_.end());
+  nodeid_tabid_map_.erase(it);
+  FreeTabNodeInternal(tab_node_id, append_changes);
+}
 
-  int tab_node_id = it->second;
-  DVLOG(1) << "Freeing tab " << tab_id << " at node " << tab_node_id;
-  nodeid_tabid_map_.erase(nodeid_tabid_map_.find(tab_node_id));
-  tabid_nodeid_map_.erase(it);
+void TabNodePool::FreeTabNodeInternal(int tab_node_id,
+                                      syncer::SyncChangeList* append_changes) {
+  DCHECK(free_nodes_pool_.find(tab_node_id) == free_nodes_pool_.end());
+  DCHECK(append_changes);
   free_nodes_pool_.insert(tab_node_id);
+
+  // If number of free nodes exceed kFreeNodesHighWatermark,
+  // delete sync nodes till number reaches kFreeNodesLowWatermark.
+  // Note: This logic is to mitigate temporary disassociation issues with old
+  // clients: http://crbug.com/259918. Newer versions do not need this.
+  if (free_nodes_pool_.size() > kFreeNodesHighWatermark) {
+    for (std::set<int>::iterator free_it = free_nodes_pool_.begin();
+         free_it != free_nodes_pool_.end();) {
+      const std::string tab_node_tag = TabIdToTag(machine_tag_, *free_it);
+      append_changes->push_back(syncer::SyncChange(
+          FROM_HERE, syncer::SyncChange::ACTION_DELETE,
+          syncer::SyncData::CreateLocalDelete(tab_node_tag, syncer::SESSIONS)));
+      free_nodes_pool_.erase(free_it++);
+      if (free_nodes_pool_.size() <= kFreeNodesLowWatermark) {
+        return;
+      }
+    }
+  }
+}
+
+bool TabNodePool::IsUnassociatedTabNode(int tab_node_id) {
+  return unassociated_nodes_.find(tab_node_id) != unassociated_nodes_.end();
 }
 
 void TabNodePool::ReassociateTabNode(int tab_node_id,
                                      SessionID::id_type tab_id) {
-  DCHECK_GT(tab_node_id, kInvalidTabNodeID);
-  DCHECK_GT(tab_id, kInvalidTabID);
-
-  auto tabid_it = tabid_nodeid_map_.find(tab_id);
-  if (tabid_it != tabid_nodeid_map_.end()) {
-    if (tabid_it->second == tab_node_id) {
-      return;  // Already associated properly.
-    } else {
-      // Another node is already associated with this tab. Free it.
-      FreeTab(tab_id);
-    }
-  }
-
-  auto nodeid_it = nodeid_tabid_map_.find(tab_node_id);
-  if (nodeid_it != nodeid_tabid_map_.end()) {
-    // This node was already associated with another tab. Free it.
-    FreeTab(nodeid_it->second);
+  // Remove from list of unassociated sync_nodes if present.
+  std::set<int>::iterator it = unassociated_nodes_.find(tab_node_id);
+  if (it != unassociated_nodes_.end()) {
+    unassociated_nodes_.erase(it);
   } else {
-    // This is a new tab node. Add it before association.
-    AddTabNode(tab_node_id);
+    // tab_node_id must be an already associated node.
+    DCHECK(nodeid_tabid_map_.find(tab_node_id) != nodeid_tabid_map_.end());
   }
-
-  AssociateTabNode(tab_node_id, tab_id);
+  nodeid_tabid_map_[tab_node_id] = tab_id;
 }
 
 SessionID::id_type TabNodePool::GetTabIdFromTabNodeId(int tab_node_id) const {
@@ -119,33 +144,27 @@
   return kInvalidTabID;
 }
 
-void TabNodePool::CleanupTabNodes(std::set<int>* deleted_node_ids) {
-  // If number of free nodes exceed kFreeNodesHighWatermark,
-  // delete sync nodes till number reaches kFreeNodesLowWatermark.
-  // Note: This logic is to mitigate temporary disassociation issues with old
-  // clients: http://crbug.com/259918. Newer versions do not need this.
-  if (free_nodes_pool_.size() > kFreeNodesHighWatermark) {
-    for (std::set<int>::iterator free_it = free_nodes_pool_.begin();
-         free_it != free_nodes_pool_.end();) {
-      deleted_node_ids->insert(*free_it);
-      free_nodes_pool_.erase(free_it++);
-      if (free_nodes_pool_.size() <= kFreeNodesLowWatermark) {
-        return;
-      }
-    }
+void TabNodePool::DeleteUnassociatedTabNodes(
+    syncer::SyncChangeList* append_changes) {
+  for (std::set<int>::iterator it = unassociated_nodes_.begin();
+       it != unassociated_nodes_.end();) {
+    FreeTabNodeInternal(*it, append_changes);
+    unassociated_nodes_.erase(it++);
   }
+  DCHECK(unassociated_nodes_.empty());
 }
 
 // Clear tab pool.
 void TabNodePool::Clear() {
+  unassociated_nodes_.clear();
   free_nodes_pool_.clear();
   nodeid_tabid_map_.clear();
-  tabid_nodeid_map_.clear();
   max_used_tab_node_id_ = kInvalidTabNodeID;
 }
 
 size_t TabNodePool::Capacity() const {
-  return nodeid_tabid_map_.size() + free_nodes_pool_.size();
+  return nodeid_tabid_map_.size() + unassociated_nodes_.size() +
+         free_nodes_pool_.size();
 }
 
 bool TabNodePool::Empty() const {
@@ -156,4 +175,8 @@
   return nodeid_tabid_map_.empty();
 }
 
+void TabNodePool::SetMachineTag(const std::string& machine_tag) {
+  machine_tag_ = machine_tag;
+}
+
 }  // namespace sync_sessions
diff --git a/components/sync_sessions/tab_node_pool.h b/components/sync_sessions/tab_node_pool.h
index 833daf7..caadc4e 100644
--- a/components/sync_sessions/tab_node_pool.h
+++ b/components/sync_sessions/tab_node_pool.h
@@ -13,6 +13,11 @@
 
 #include "base/macros.h"
 #include "components/sessions/core/session_id.h"
+#include "components/sync/model/sync_change_processor.h"
+
+namespace syncer {
+class SyncChangeProcessor;
+}  // namespace syncer
 
 namespace sync_sessions {
 
@@ -22,11 +27,17 @@
 // - a tab_id: created by session service, unique to this client
 // - a tab_node_id: the id for a particular sync tab node. This is used
 //   to generate the sync tab node tag through:
-//       tab_tag = StringPrintf("%s %d", local_session_tag, tab_node_id);
+//       tab_tag = StringPrintf("%s_%ui", local_session_tag, tab_node_id);
 //
-// A sync node can be in one of the two states:
+// A sync node can be in one of the three states:
 // 1. Associated   : Sync node is used and associated with a tab.
-// 2. Free         : Sync node is unused.
+// 2. Unassociated : Sync node is used but currently unassociated with any tab.
+//                   This is true for old nodes that remain from a session
+//                   restart. Nodes are only unassociated temporarily while the
+//                   model associator figures out which tabs belong to which
+//                   nodes. Eventually any remaining unassociated nodes are
+//                   freed.
+// 3. Free         : Sync node is unused.
 
 class TabNodePool {
  public:
@@ -43,37 +54,65 @@
 
   static const int kInvalidTabNodeID;
 
-  // Fills |tab_node_id| with a tab node associated with |tab_id|.
-  // If tab_id is already associated with a tab_node_id, reuses the existing
-  // association. Otherwise attempts to get the next free tab node and
-  // associate it with |tab_id|. If none are available, will create a new tab
-  // node.
-  // Returns true if a pre-existing tab node could be reused, false if a new one
-  // had to be created.
-  bool GetTabNodeForTab(SessionID::id_type tab_id, int* tab_node_id);
+  // Build a sync tag from tab_node_id.
+  static std::string TabIdToTag(const std::string& machine_tag,
+                                int tab_node_id);
+
+  // Returns the tab_node_id for the next free tab node. If none are available,
+  // creates a new tab node and adds it to free nodes pool. The free node can
+  // then be used to associate with a tab by calling AssociateTabNode.
+  // Note: The node is considered free until it has been associated. Repeated
+  // calls to GetFreeTabNode will return the same id until node has been
+  // associated.
+  // |change_output| *must* be provided. It is the TabNodePool's link to
+  // the SyncChange pipeline that exists in the caller context. If the need
+  // to create nodes arises in the implementation, associated SyncChanges will
+  // be appended to this list for later application by the caller via the
+  // SyncChangeProcessor.
+  int GetFreeTabNode(syncer::SyncChangeList* change_output);
+
+  // Removes association for |tab_node_id| and returns it to the free node pool.
+  // |change_output| *must* be provided. It is the TabNodePool's link to
+  // the SyncChange pipeline that exists in the caller's context. If the need
+  // to delete sync nodes arises in the implementation, associated SyncChanges
+  // will be appended to this list for later application by the caller via the
+  // SyncChangeProcessor.
+  void FreeTabNode(int tab_node_id, syncer::SyncChangeList* change_output);
+
+  // Associates |tab_node_id| with |tab_id|. |tab_node_id| should either be
+  // unassociated or free. If |tab_node_id| is free, |tab_node_id| is removed
+  // from the free node pool In order to associate a non free sync node,
+  // use ReassociateTabNode.
+  void AssociateTabNode(int tab_node_id, SessionID::id_type tab_id);
+
+  // Adds |tab_node_id| as an unassociated sync node.
+  // Note: this should only be called when we discover tab sync nodes from
+  // previous sessions, not for freeing tab nodes we created through
+  // GetFreeTabNode (use FreeTabNode below for that).
+  void AddTabNode(int tab_node_id);
 
   // Returns the tab_id for |tab_node_id| if it is associated else returns
   // kInvalidTabID.
   SessionID::id_type GetTabIdFromTabNodeId(int tab_node_id) const;
 
-  // Reassociates |tab_node_id| with |tab_id|. If |tab_node_id| is not already
-  // known, it is added to the tab node pool before being associated.
+  // Reassociates |tab_node_id| with |tab_id|. |tab_node_id| must be either
+  // associated with a tab or in the set of unassociated nodes.
   void ReassociateTabNode(int tab_node_id, SessionID::id_type tab_id);
 
-  // Removes association for |tab_id| and returns its tab node to the free node
-  // pool.
-  void FreeTab(int tab_id);
+  // Returns true if |tab_node_id| is an unassociated tab node.
+  bool IsUnassociatedTabNode(int tab_node_id);
 
-  // Fills |deleted_node_ids| with any free nodes to be deleted as proscribed
-  // by the free node low/high watermarks, in order to ensure the free node pool
-  // does not grow too large.
-  void CleanupTabNodes(std::set<int>* deleted_node_ids);
+  // Returns any unassociated nodes to the free node pool.
+  // |change_output| *must* be provided. It is the TabNodePool's link to
+  // the SyncChange pipeline that exists in the caller's context.
+  // See FreeTabNode for more detail.
+  void DeleteUnassociatedTabNodes(syncer::SyncChangeList* change_output);
 
   // Clear tab pool.
   void Clear();
 
   // Return the number of tab nodes this client currently has allocated
-  // (including both free and associated nodes).
+  // (including both free, unassociated and associated nodes)
   size_t Capacity() const;
 
   // Return empty status (all tab nodes are in use).
@@ -82,36 +121,41 @@
   // Return full status (no tab nodes are in use).
   bool Full();
 
+  void SetMachineTag(const std::string& machine_tag);
+
  private:
   friend class SyncTabNodePoolTest;
   typedef std::map<int, SessionID::id_type> TabNodeIDToTabIDMap;
-  typedef std::map<SessionID::id_type, int> TabIDToTabNodeIDMap;
 
-  // Adds |tab_node_id| to the tab node pool.
-  // Note: this should only be called when we discover tab sync nodes from
-  // previous sessions, not for freeing tab nodes we created through
-  // GetTabNodeForTab (use FreeTab for that).
-  void AddTabNode(int tab_node_id);
-
-  // Associates |tab_node_id| with |tab_id|. |tab_node_id| must be free. In
-  // order to associated a non-free tab node, ReassociateTabNode must be
-  // used.
-  void AssociateTabNode(int tab_node_id, SessionID::id_type tab_id);
+  // Adds |tab_node_id| to free node pool.
+  // |change_output| *must* be provided. It is the TabNodePool's link to
+  // the SyncChange pipeline that exists in the caller's context.
+  // See FreeTabNode for more detail.
+  void FreeTabNodeInternal(int tab_node_id,
+                           syncer::SyncChangeList* change_output);
 
   // Stores mapping of node ids associated with tab_ids, these are the used
   // nodes of tab node pool.
   // The nodes in the map can be returned to free tab node pool by calling
-  // FreeTab(..).
+  // FreeTabNode(tab_node_id).
   TabNodeIDToTabIDMap nodeid_tabid_map_;
-  TabIDToTabNodeIDMap tabid_nodeid_map_;
 
   // The node ids for the set of free sync nodes.
   std::set<int> free_nodes_pool_;
 
+  // The node ids that are added to pool using AddTabNode and are currently
+  // not associated with any tab. They can be reassociated using
+  // ReassociateTabNode.
+  std::set<int> unassociated_nodes_;
+
   // The maximum used tab_node id for a sync node. A new sync node will always
   // be created with max_used_tab_node_id_ + 1.
   int max_used_tab_node_id_;
 
+  // The machine tag associated with this tab pool. Used in the title of new
+  // sync nodes.
+  std::string machine_tag_;
+
   DISALLOW_COPY_AND_ASSIGN(TabNodePool);
 };
 
diff --git a/components/sync_sessions/tab_node_pool_unittest.cc b/components/sync_sessions/tab_node_pool_unittest.cc
index 591c8b54..cd125a2 100644
--- a/components/sync_sessions/tab_node_pool_unittest.cc
+++ b/components/sync_sessions/tab_node_pool_unittest.cc
@@ -6,13 +6,16 @@
 
 #include <vector>
 
+#include "components/sync/model/sync_change.h"
+#include "components/sync/protocol/session_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace sync_sessions {
 
 class SyncTabNodePoolTest : public testing::Test {
  protected:
-  SyncTabNodePoolTest() {}
+  SyncTabNodePoolTest() { pool_.SetMachineTag("tag"); }
 
   int GetMaxUsedTabNodeId() const { return pool_.max_used_tab_node_id_; }
 
@@ -29,127 +32,107 @@
 
 namespace {
 
-const int kTabNodeId1 = 10;
-const int kTabNodeId2 = 5;
-const int kTabNodeId3 = 1000;
-const int kTabId1 = 1;
-const int kTabId2 = 2;
-const int kTabId3 = 3;
-
 TEST_F(SyncTabNodePoolTest, TabNodeIdIncreases) {
-  std::set<int> deleted_node_ids;
-
+  syncer::SyncChangeList changes;
   // max_used_tab_node_ always increases.
-  pool_.ReassociateTabNode(kTabNodeId1, kTabId1);
-  EXPECT_EQ(kTabNodeId1, GetMaxUsedTabNodeId());
-  pool_.ReassociateTabNode(kTabNodeId2, kTabId2);
-  EXPECT_EQ(kTabNodeId1, GetMaxUsedTabNodeId());
-  pool_.ReassociateTabNode(kTabNodeId3, kTabId3);
-  EXPECT_EQ(kTabNodeId3, GetMaxUsedTabNodeId());
+  pool_.AddTabNode(10);
+  EXPECT_EQ(10, GetMaxUsedTabNodeId());
+  pool_.AddTabNode(5);
+  EXPECT_EQ(10, GetMaxUsedTabNodeId());
+  pool_.AddTabNode(1000);
+  EXPECT_EQ(1000, GetMaxUsedTabNodeId());
+  pool_.ReassociateTabNode(1000, 1);
+  pool_.ReassociateTabNode(5, 2);
+  pool_.ReassociateTabNode(10, 3);
   // Freeing a tab node does not change max_used_tab_node_id_.
-  pool_.FreeTab(kTabId3);
-  pool_.CleanupTabNodes(&deleted_node_ids);
-  EXPECT_TRUE(deleted_node_ids.empty());
-  pool_.FreeTab(kTabId2);
-  pool_.CleanupTabNodes(&deleted_node_ids);
-  EXPECT_TRUE(deleted_node_ids.empty());
-  pool_.FreeTab(kTabId1);
-  pool_.CleanupTabNodes(&deleted_node_ids);
-  EXPECT_TRUE(deleted_node_ids.empty());
+  pool_.FreeTabNode(1000, &changes);
+  EXPECT_TRUE(changes.empty());
+  pool_.FreeTabNode(5, &changes);
+  EXPECT_TRUE(changes.empty());
+  pool_.FreeTabNode(10, &changes);
+  EXPECT_TRUE(changes.empty());
   for (int i = 0; i < 3; ++i) {
-    int tab_node_id = -1;
-    EXPECT_TRUE(pool_.GetTabNodeForTab(i + 1, &tab_node_id));
-    EXPECT_EQ(kTabNodeId3, GetMaxUsedTabNodeId());
+    pool_.AssociateTabNode(pool_.GetFreeTabNode(&changes), i + 1);
+    EXPECT_EQ(1000, GetMaxUsedTabNodeId());
   }
-  pool_.CleanupTabNodes(&deleted_node_ids);
-  EXPECT_TRUE(deleted_node_ids.empty());
-  EXPECT_EQ(kTabNodeId3, GetMaxUsedTabNodeId());
+  EXPECT_TRUE(changes.empty());
+  EXPECT_EQ(1000, GetMaxUsedTabNodeId());
   EXPECT_TRUE(pool_.Empty());
 }
 
-TEST_F(SyncTabNodePoolTest, Reassociation) {
-  // Reassociate tab node 1 with tab id 1.
-  pool_.ReassociateTabNode(kTabNodeId1, kTabId1);
-  EXPECT_EQ(1U, pool_.Capacity());
+TEST_F(SyncTabNodePoolTest, OldTabNodesAddAndRemove) {
+  syncer::SyncChangeList changes;
+  // VerifyOldTabNodes are added.
+  pool_.AddTabNode(1);
+  pool_.AddTabNode(2);
+  EXPECT_EQ(2u, pool_.Capacity());
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.IsUnassociatedTabNode(1));
+  EXPECT_TRUE(pool_.IsUnassociatedTabNode(2));
+  pool_.ReassociateTabNode(1, 2);
+  EXPECT_TRUE(pool_.Empty());
+  pool_.AssociateTabNode(2, 3);
+  EXPECT_FALSE(pool_.IsUnassociatedTabNode(1));
+  EXPECT_FALSE(pool_.IsUnassociatedTabNode(2));
+  pool_.FreeTabNode(2, &changes);
+  EXPECT_TRUE(changes.empty());
+  // 2 should be returned to free node pool_.
+  EXPECT_EQ(2u, pool_.Capacity());
+  // Should be able to free 1.
+  pool_.FreeTabNode(1, &changes);
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(1, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes.empty());
+  pool_.AssociateTabNode(1, 1);
+  EXPECT_EQ(2, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes.empty());
+  pool_.AssociateTabNode(2, 1);
   EXPECT_TRUE(pool_.Empty());
   EXPECT_FALSE(pool_.Full());
-  EXPECT_EQ(kTabId1, pool_.GetTabIdFromTabNodeId(kTabNodeId1));
-  EXPECT_EQ(TabNodePool::kInvalidTabNodeID,
-            pool_.GetTabIdFromTabNodeId(kTabNodeId2));
-
-  // Introduce a new tab node associated with the same tab. The old tab node
-  // should get added to the free pool
-  pool_.ReassociateTabNode(kTabNodeId2, kTabId1);
-  EXPECT_EQ(2U, pool_.Capacity());
-  EXPECT_FALSE(pool_.Empty());
   EXPECT_FALSE(pool_.Full());
-  EXPECT_EQ(TabNodePool::kInvalidTabNodeID,
-            pool_.GetTabIdFromTabNodeId(kTabNodeId1));
-  EXPECT_EQ(kTabId1, pool_.GetTabIdFromTabNodeId(kTabNodeId2));
-
-  // Reassociating the same tab node/tab should have no effect.
-  pool_.ReassociateTabNode(kTabNodeId2, kTabId1);
-  EXPECT_EQ(2U, pool_.Capacity());
-  EXPECT_FALSE(pool_.Empty());
-  EXPECT_FALSE(pool_.Full());
-  EXPECT_EQ(TabNodePool::kInvalidTabNodeID,
-            pool_.GetTabIdFromTabNodeId(kTabNodeId1));
-  EXPECT_EQ(kTabId1, pool_.GetTabIdFromTabNodeId(kTabNodeId2));
-
-  // Reassociating the new tab node with a new tab should just update the
-  // association tables.
-  pool_.ReassociateTabNode(kTabNodeId2, kTabId2);
-  EXPECT_EQ(2U, pool_.Capacity());
-  EXPECT_FALSE(pool_.Empty());
-  EXPECT_FALSE(pool_.Full());
-  EXPECT_EQ(TabNodePool::kInvalidTabNodeID,
-            pool_.GetTabIdFromTabNodeId(kTabNodeId1));
-  EXPECT_EQ(kTabId2, pool_.GetTabIdFromTabNodeId(kTabNodeId2));
-
-  // Reassociating the first tab node should make the pool empty.
-  pool_.ReassociateTabNode(kTabNodeId1, kTabId1);
-  EXPECT_EQ(2U, pool_.Capacity());
-  EXPECT_TRUE(pool_.Empty());
-  EXPECT_FALSE(pool_.Full());
-  EXPECT_EQ(kTabId1, pool_.GetTabIdFromTabNodeId(kTabNodeId1));
-  EXPECT_EQ(kTabId2, pool_.GetTabIdFromTabNodeId(kTabNodeId2));
 }
 
-TEST_F(SyncTabNodePoolTest, ReassociateThenFree) {
-  std::set<int> deleted_node_ids;
-
-  // Verify old tab nodes are reassociated correctly.
-  pool_.ReassociateTabNode(kTabNodeId1, kTabId1);
-  pool_.ReassociateTabNode(kTabNodeId2, kTabId2);
-  pool_.ReassociateTabNode(kTabNodeId3, kTabId3);
+TEST_F(SyncTabNodePoolTest, OldTabNodesReassociation) {
+  // VerifyOldTabNodes are reassociated correctly.
+  pool_.AddTabNode(4);
+  pool_.AddTabNode(5);
+  pool_.AddTabNode(6);
   EXPECT_EQ(3u, pool_.Capacity());
   EXPECT_TRUE(pool_.Empty());
-  // Free tabs 2 and 3.
-  pool_.FreeTab(kTabId2);
-  pool_.FreeTab(kTabId3);
-  pool_.CleanupTabNodes(&deleted_node_ids);
-  EXPECT_TRUE(deleted_node_ids.empty());
-  // Free node pool should have 2 and 3.
+  EXPECT_TRUE(pool_.IsUnassociatedTabNode(4));
+  pool_.ReassociateTabNode(4, 5);
+  pool_.AssociateTabNode(5, 6);
+  pool_.AssociateTabNode(6, 7);
+  // Free 5 and 6.
+  syncer::SyncChangeList changes;
+  pool_.FreeTabNode(5, &changes);
+  pool_.FreeTabNode(6, &changes);
+  EXPECT_TRUE(changes.empty());
+  // 5 and 6 nodes should not be unassociated.
+  EXPECT_FALSE(pool_.IsUnassociatedTabNode(5));
+  EXPECT_FALSE(pool_.IsUnassociatedTabNode(6));
+  // Free node pool should have 5 and 6.
   EXPECT_FALSE(pool_.Empty());
   EXPECT_EQ(3u, pool_.Capacity());
 
   // Free all nodes
-  pool_.FreeTab(kTabId1);
-  pool_.CleanupTabNodes(&deleted_node_ids);
-  EXPECT_TRUE(deleted_node_ids.empty());
+  pool_.FreeTabNode(4, &changes);
+  EXPECT_TRUE(changes.empty());
   EXPECT_TRUE(pool_.Full());
   std::set<int> free_sync_ids;
   for (int i = 0; i < 3; ++i) {
-    int tab_node_id = -1;
-    EXPECT_TRUE(pool_.GetTabNodeForTab(i, &tab_node_id));
-    free_sync_ids.insert(tab_node_id);
+    free_sync_ids.insert(pool_.GetFreeTabNode(&changes));
+    // GetFreeTabNode will return the same value till the node is
+    // reassociated.
+    pool_.AssociateTabNode(pool_.GetFreeTabNode(&changes), i + 1);
   }
 
   EXPECT_TRUE(pool_.Empty());
   EXPECT_EQ(3u, free_sync_ids.size());
-  EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId1));
-  EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId2));
-  EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId3));
+  EXPECT_EQ(1u, free_sync_ids.count(4));
+  EXPECT_EQ(1u, free_sync_ids.count(5));
+  EXPECT_EQ(1u, free_sync_ids.count(6));
 }
 
 TEST_F(SyncTabNodePoolTest, Init) {
@@ -158,49 +141,106 @@
 }
 
 TEST_F(SyncTabNodePoolTest, AddGet) {
+  syncer::SyncChangeList changes;
   int free_nodes[] = {5, 10};
   AddFreeTabNodes(2, free_nodes);
 
   EXPECT_EQ(2U, pool_.Capacity());
-  int tab_node_id = -1;
-  EXPECT_TRUE(pool_.GetTabNodeForTab(1, &tab_node_id));
-  EXPECT_EQ(5, tab_node_id);
+  EXPECT_EQ(5, pool_.GetFreeTabNode(&changes));
+  pool_.AssociateTabNode(5, 1);
   EXPECT_FALSE(pool_.Empty());
   EXPECT_FALSE(pool_.Full());
   EXPECT_EQ(2U, pool_.Capacity());
   // 5 is now used, should return 10.
-  EXPECT_TRUE(pool_.GetTabNodeForTab(2, &tab_node_id));
-  EXPECT_EQ(10, tab_node_id);
+  EXPECT_EQ(10, pool_.GetFreeTabNode(&changes));
 }
 
-TEST_F(SyncTabNodePoolTest, GetTabNodeForTabCreate) {
-  int tab_node_id = -1;
-  EXPECT_FALSE(pool_.GetTabNodeForTab(1, &tab_node_id));
-  EXPECT_EQ(0, tab_node_id);
+TEST_F(SyncTabNodePoolTest, All) {
+  syncer::SyncChangeList changes;
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(0U, pool_.Capacity());
+
+  // GetFreeTabNode returns the lowest numbered free node.
+  EXPECT_EQ(0, pool_.GetFreeTabNode(&changes));
+  EXPECT_EQ(1U, changes.size());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(1U, pool_.Capacity());
+
+  // Associate 5, next free node should be 10.
+  pool_.AssociateTabNode(0, 1);
+  EXPECT_EQ(1, pool_.GetFreeTabNode(&changes));
+  EXPECT_EQ(2U, changes.size());
+  changes.clear();
+  pool_.AssociateTabNode(1, 2);
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_FALSE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  // Release them in reverse order.
+  pool_.FreeTabNode(1, &changes);
+  pool_.FreeTabNode(0, &changes);
+  EXPECT_EQ(2U, pool_.Capacity());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(0, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes.empty());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  pool_.AssociateTabNode(0, 1);
+  EXPECT_EQ(2U, pool_.Capacity());
+  EXPECT_EQ(1, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes.empty());
+  pool_.AssociateTabNode(1, 2);
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_FALSE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  // Release them again.
+  pool_.FreeTabNode(1, &changes);
+  pool_.FreeTabNode(0, &changes);
+  EXPECT_FALSE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(2U, pool_.Capacity());
+  pool_.Clear();
+  EXPECT_TRUE(pool_.Empty());
+  EXPECT_TRUE(pool_.Full());
+  EXPECT_EQ(0U, pool_.Capacity());
+}
+
+TEST_F(SyncTabNodePoolTest, GetFreeTabNodeCreate) {
+  syncer::SyncChangeList changes;
+  EXPECT_EQ(0, pool_.GetFreeTabNode(&changes));
+  EXPECT_TRUE(changes[0].IsValid());
+  EXPECT_EQ(syncer::SyncChange::ACTION_ADD, changes[0].change_type());
+  EXPECT_TRUE(changes[0].sync_data().IsValid());
+  sync_pb::EntitySpecifics entity = changes[0].sync_data().GetSpecifics();
+  sync_pb::SessionSpecifics specifics(entity.session());
+  EXPECT_EQ(0, specifics.tab_node_id());
 }
 
 TEST_F(SyncTabNodePoolTest, TabPoolFreeNodeLimits) {
-  std::set<int> deleted_node_ids;
-
   // Allocate TabNodePool::kFreeNodesHighWatermark + 1 nodes and verify that
   // freeing the last node reduces the free node pool size to
   // kFreeNodesLowWatermark.
+  syncer::SyncChangeList changes;
   SessionID session_id;
   std::vector<int> used_sync_ids;
   for (size_t i = 1; i <= TabNodePool::kFreeNodesHighWatermark + 1; ++i) {
     session_id.set_id(i);
-    int sync_id = -1;
-    EXPECT_FALSE(pool_.GetTabNodeForTab(i, &sync_id));
+    int sync_id = pool_.GetFreeTabNode(&changes);
+    pool_.AssociateTabNode(sync_id, i);
     used_sync_ids.push_back(sync_id);
   }
 
   // Free all except one node.
+  int last_sync_id = used_sync_ids.back();
   used_sync_ids.pop_back();
 
-  for (size_t i = 1; i <= used_sync_ids.size(); ++i) {
-    pool_.FreeTab(i);
-    pool_.CleanupTabNodes(&deleted_node_ids);
-    EXPECT_TRUE(deleted_node_ids.empty());
+  for (size_t i = 0; i < used_sync_ids.size(); ++i) {
+    pool_.FreeTabNode(used_sync_ids[i], &changes);
   }
 
   // Except one node all nodes should be in FreeNode pool.
@@ -211,11 +251,7 @@
 
   // Freeing the last sync node should drop the free nodes to
   // kFreeNodesLowWatermark.
-  pool_.FreeTab(TabNodePool::kFreeNodesHighWatermark + 1);
-  pool_.CleanupTabNodes(&deleted_node_ids);
-  EXPECT_EQ(TabNodePool::kFreeNodesHighWatermark + 1 -
-                TabNodePool::kFreeNodesLowWatermark,
-            deleted_node_ids.size());
+  pool_.FreeTabNode(last_sync_id, &changes);
   EXPECT_FALSE(pool_.Empty());
   EXPECT_TRUE(pool_.Full());
   EXPECT_EQ(TabNodePool::kFreeNodesLowWatermark, pool_.Capacity());
diff --git a/components/test/data/web_database/OWNERS b/components/test/data/web_database/OWNERS
index dbe16c9b..f9f5300d 100644
--- a/components/test/data/web_database/OWNERS
+++ b/components/test/data/web_database/OWNERS
@@ -2,3 +2,5 @@
 
 # For sqlite stuff:
 shess@chromium.org
+
+# COMPONENT: Test
diff --git a/components/test_runner/layout_test_runtime_flags.cc b/components/test_runner/layout_test_runtime_flags.cc
index 3d6fa2e..8af7ce2c 100644
--- a/components/test_runner/layout_test_runtime_flags.cc
+++ b/components/test_runner/layout_test_runtime_flags.cc
@@ -65,6 +65,9 @@
   set_dump_spell_check_callbacks(false);
   set_dump_javascript_dialogs(true);
 
+  set_has_custom_text_output(false);
+  set_custom_text_output("");
+
   // No need to report the initial state - only the future delta is important.
   tracked_dictionary().ResetChangeTracking();
 }
diff --git a/components/test_runner/layout_test_runtime_flags.h b/components/test_runner/layout_test_runtime_flags.h
index aa7bceb..52bad175 100644
--- a/components/test_runner/layout_test_runtime_flags.h
+++ b/components/test_runner/layout_test_runtime_flags.h
@@ -183,6 +183,12 @@
   // etc.
   DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(dump_javascript_dialogs)
 
+  // True if the test called testRunner.setCustomTextOutput.
+  DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG(has_custom_text_output)
+
+  // Contains text passed by the test to testRunner.setCustomTextOutput.
+  DEFINE_STRING_LAYOUT_TEST_RUNTIME_FLAG(custom_text_output)
+
 #undef DEFINE_BOOL_LAYOUT_TEST_RUNTIME_FLAG
 #undef DEFINE_STRING_LAYOUT_TEST_RUNTIME_FLAG
 
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc
index 4207762..77fc4fb 100644
--- a/components/test_runner/test_runner.cc
+++ b/components/test_runner/test_runner.cc
@@ -1680,8 +1680,6 @@
   test_repaint_ = false;
   sweep_horizontally_ = false;
   midi_accessor_result_ = midi::mojom::Result::OK;
-  has_custom_text_output_ = false;
-  custom_text_output_.clear();
 
   http_headers_to_clear_.clear();
 
@@ -1721,16 +1719,17 @@
 }
 
 bool TestRunner::shouldDumpAsCustomText() const {
-  return has_custom_text_output_;
+  return layout_test_runtime_flags_.has_custom_text_output();
 }
 
 std::string TestRunner::customDumpText() const {
-  return custom_text_output_;
+  return layout_test_runtime_flags_.custom_text_output();
 }
 
 void TestRunner::setCustomTextOutput(const std::string& text) {
-  custom_text_output_ = text;
-  has_custom_text_output_ = true;
+  layout_test_runtime_flags_.set_custom_text_output(text);
+  layout_test_runtime_flags_.set_has_custom_text_output(true);
+  OnLayoutTestRuntimeFlagsChanged();
 }
 
 bool TestRunner::ShouldGeneratePixelResults() {
diff --git a/components/test_runner/test_runner.h b/components/test_runner/test_runner.h
index efdbfb9..7cb3c7c 100644
--- a/components/test_runner/test_runner.h
+++ b/components/test_runner/test_runner.h
@@ -610,9 +610,6 @@
   // startSession() result of MockWebMIDIAccessor for testing.
   midi::mojom::Result midi_accessor_result_;
 
-  bool has_custom_text_output_;
-  std::string custom_text_output_;
-
   std::set<std::string> http_headers_to_clear_;
 
   // WAV audio data is stored here.
diff --git a/components/toolbar/OWNERS b/components/toolbar/OWNERS
index bf426d6..0d3bbb5 100644
--- a/components/toolbar/OWNERS
+++ b/components/toolbar/OWNERS
@@ -1 +1,3 @@
 pkasting@chromium.org
+
+# COMPONENT: UI>Browser>Toolbar
diff --git a/components/tracing/common/process_metrics_memory_dump_provider.cc b/components/tracing/common/process_metrics_memory_dump_provider.cc
index f5a9471..ccac2466 100644
--- a/components/tracing/common/process_metrics_memory_dump_provider.cc
+++ b/components/tracing/common/process_metrics_memory_dump_provider.cc
@@ -28,8 +28,13 @@
 #include <libproc.h>
 #include <mach/mach.h>
 #include <mach/mach_vm.h>
+#include <mach/shared_region.h>
 #include <sys/param.h>
 
+#include <mach-o/dyld_images.h>
+#include <mach-o/loader.h>
+#include <mach/mach.h>
+
 #include "base/numerics/safe_math.h"
 #endif  // defined(OS_MACOSX)
 
@@ -229,12 +234,122 @@
 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
 
 #if defined(OS_MACOSX)
-bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps(
-    const base::trace_event::MemoryDumpArgs& args,
-    base::trace_event::ProcessMemoryDump* pmd) {
+
+namespace {
+
+using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
+
+bool IsAddressInSharedRegion(uint64_t address) {
+  return address >= SHARED_REGION_BASE_X86_64 &&
+         address < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64);
+}
+
+// Creates VMRegions for all dyld images. Returns whether the operation
+// succeeded.
+bool GetDyldRegions(std::vector<VMRegion>* regions) {
+  task_dyld_info_data_t dyld_info;
+  mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+  kern_return_t kr =
+      task_info(mach_task_self(), TASK_DYLD_INFO,
+                reinterpret_cast<task_info_t>(&dyld_info), &count);
+  if (kr != KERN_SUCCESS)
+    return false;
+
+  const struct dyld_all_image_infos* all_image_infos =
+      reinterpret_cast<const struct dyld_all_image_infos*>(
+          dyld_info.all_image_info_addr);
+
+  for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) {
+    const char* image_name = all_image_infos->infoArray[i].imageFilePath;
+
+    // The public definition for dyld_all_image_infos/dyld_image_info is wrong
+    // for 64-bit platforms. We explicitly cast to struct mach_header_64 even
+    // though the public definition claims that this is a struct mach_header.
+    const struct mach_header_64* const header =
+        reinterpret_cast<const struct mach_header_64* const>(
+            all_image_infos->infoArray[i].imageLoadAddress);
+
+    uint64_t next_command = reinterpret_cast<uint64_t>(header + 1);
+    uint64_t command_end = next_command + header->sizeofcmds;
+    for (unsigned int i = 0; i < header->ncmds; ++i) {
+      // Ensure that next_command doesn't run past header->sizeofcmds.
+      if (next_command + sizeof(struct load_command) > command_end)
+        return false;
+      const struct load_command* load_cmd =
+          reinterpret_cast<const struct load_command*>(next_command);
+      next_command += load_cmd->cmdsize;
+
+      if (load_cmd->cmd == LC_SEGMENT_64) {
+        if (load_cmd->cmdsize < sizeof(segment_command_64))
+          return false;
+        const segment_command_64* seg =
+            reinterpret_cast<const segment_command_64*>(load_cmd);
+        if (strcmp(seg->segname, SEG_PAGEZERO) == 0)
+          continue;
+
+        uint32_t protection_flags = 0;
+        if (seg->initprot & VM_PROT_READ)
+          protection_flags |= VMRegion::kProtectionFlagsRead;
+        if (seg->initprot & VM_PROT_WRITE)
+          protection_flags |= VMRegion::kProtectionFlagsWrite;
+        if (seg->initprot & VM_PROT_EXECUTE)
+          protection_flags |= VMRegion::kProtectionFlagsExec;
+
+        VMRegion region;
+        region.size_in_bytes = seg->vmsize;
+        region.protection_flags = protection_flags;
+        region.mapped_file = image_name;
+        region.start_address =
+            reinterpret_cast<uint64_t>(header) + seg->fileoff;
+
+        // We intentionally avoid setting any page information, which is not
+        // available from dyld. The fields will be populated later.
+        regions->push_back(region);
+      }
+    }
+  }
+  return true;
+}
+
+void PopulateByteStats(VMRegion* region, const vm_region_submap_info_64& info) {
+  uint32_t share_mode = info.share_mode;
+  if (share_mode == SM_COW && info.ref_count == 1)
+    share_mode = SM_PRIVATE;
+
+  uint64_t dirty_bytes = info.pages_dirtied * PAGE_SIZE;
+  uint64_t clean_bytes =
+      (info.pages_resident - info.pages_reusable - info.pages_dirtied) *
+      PAGE_SIZE;
+  switch (share_mode) {
+    case SM_LARGE_PAGE:
+    case SM_PRIVATE:
+      region->byte_stats_private_dirty_resident = dirty_bytes;
+      region->byte_stats_private_clean_resident = clean_bytes;
+      break;
+    case SM_COW:
+      region->byte_stats_private_dirty_resident = dirty_bytes;
+      region->byte_stats_shared_clean_resident = clean_bytes;
+      break;
+    case SM_SHARED:
+    case SM_PRIVATE_ALIASED:
+    case SM_TRUESHARED:
+    case SM_SHARED_ALIASED:
+      region->byte_stats_shared_dirty_resident = dirty_bytes;
+      region->byte_stats_shared_clean_resident = clean_bytes;
+      break;
+    case SM_EMPTY:
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+// Creates VMRegions from mach_vm_region_recurse. Returns whether the operation
+// succeeded.
+bool GetAllRegions(std::vector<VMRegion>* regions) {
   const int pid = getpid();
   task_t task = mach_task_self();
-  using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
   mach_vm_size_t size = 0;
   vm_region_submap_info_64 info;
   natural_t depth = 1;
@@ -254,37 +369,8 @@
       continue;
     }
 
-    if (info.share_mode == SM_COW && info.ref_count == 1)
-      info.share_mode = SM_PRIVATE;
-
     VMRegion region;
-    uint64_t dirty_bytes = info.pages_dirtied * PAGE_SIZE;
-    uint64_t clean_bytes =
-        (info.pages_resident - info.pages_reusable - info.pages_dirtied) *
-        PAGE_SIZE;
-    switch (info.share_mode) {
-      case SM_LARGE_PAGE:
-      case SM_PRIVATE:
-        region.byte_stats_private_dirty_resident = dirty_bytes;
-        region.byte_stats_private_clean_resident = clean_bytes;
-        break;
-      case SM_COW:
-        region.byte_stats_private_dirty_resident = dirty_bytes;
-        region.byte_stats_shared_clean_resident = clean_bytes;
-        break;
-      case SM_SHARED:
-      case SM_PRIVATE_ALIASED:
-      case SM_TRUESHARED:
-      case SM_SHARED_ALIASED:
-        region.byte_stats_shared_dirty_resident = dirty_bytes;
-        region.byte_stats_shared_clean_resident = clean_bytes;
-        break;
-      case SM_EMPTY:
-        break;
-      default:
-        NOTREACHED();
-        break;
-    }
+    PopulateByteStats(&region, info);
 
     if (info.protection & VM_PROT_READ)
       region.protection_flags |= VMRegion::kProtectionFlagsRead;
@@ -301,14 +387,87 @@
     region.byte_stats_swapped = info.pages_swapped_out * PAGE_SIZE;
     region.start_address = address;
     region.size_in_bytes = size;
-    pmd->process_mmaps()->AddVMRegion(region);
+    regions->push_back(region);
 
     base::CheckedNumeric<mach_vm_address_t> numeric(address);
     numeric += size;
     if (!numeric.IsValid())
-      break;
+      return false;
     address = numeric.ValueOrDie();
   }
+  return true;
+}
+
+void CopyRegionByteStats(VMRegion* dest, const VMRegion& source) {
+  dest->byte_stats_private_dirty_resident =
+      source.byte_stats_private_dirty_resident;
+  dest->byte_stats_private_clean_resident =
+      source.byte_stats_private_clean_resident;
+  dest->byte_stats_shared_dirty_resident =
+      source.byte_stats_shared_dirty_resident;
+  dest->byte_stats_shared_clean_resident =
+      source.byte_stats_shared_clean_resident;
+  dest->byte_stats_swapped = source.byte_stats_swapped;
+  dest->byte_stats_proportional_resident =
+      source.byte_stats_proportional_resident;
+}
+
+}  // namespace
+
+bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps(
+    const base::trace_event::MemoryDumpArgs& args,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion;
+
+  std::vector<VMRegion> dyld_regions;
+  if (!GetDyldRegions(&dyld_regions))
+    return false;
+  std::vector<VMRegion> all_regions;
+  if (!GetAllRegions(&all_regions))
+    return false;
+
+  // Cache information from dyld_regions in a data-structure more conducive to
+  // fast lookups.
+  std::unordered_map<uint64_t, VMRegion*> address_to_vm_region;
+  std::vector<uint64_t> addresses_in_shared_region;
+  for (VMRegion& region : dyld_regions) {
+    if (IsAddressInSharedRegion(region.start_address))
+      addresses_in_shared_region.push_back(region.start_address);
+    address_to_vm_region[region.start_address] = &region;
+  }
+
+  // Merge information from dyld regions and all regions.
+  for (const VMRegion& region : all_regions) {
+    // Check to see if the region already has a VMRegion created from a dyld
+    // load command. If so, copy the byte stats and move on.
+    auto it = address_to_vm_region.find(region.start_address);
+    if (it != address_to_vm_region.end() &&
+        it->second->size_in_bytes == region.size_in_bytes) {
+      CopyRegionByteStats(it->second, region);
+      continue;
+    }
+
+    // Check to see if the region is likely used for the dyld shared cache.
+    if (IsAddressInSharedRegion(region.start_address)) {
+      uint64_t end_address = region.start_address + region.size_in_bytes;
+      for (uint64_t address : addresses_in_shared_region) {
+        // This region is likely used for the dyld shared cache. Don't record
+        // any byte stats since:
+        //   1. It's not possible to figure out which dyld regions the byte
+        //      stats correspond to.
+        //   2. The region is likely shared by non-Chrome processes, so there's
+        //      no point in charging the pages towards Chrome.
+        if (address >= region.start_address && address < end_address) {
+          continue;
+        }
+      }
+    }
+    pmd->process_mmaps()->AddVMRegion(region);
+  }
+
+  for (VMRegion& region : dyld_regions) {
+    pmd->process_mmaps()->AddVMRegion(region);
+  }
 
   pmd->set_has_process_mmaps();
   return true;
diff --git a/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc b/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc
index fc53f77..4c9ba7c9 100644
--- a/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc
+++ b/components/tracing/common/process_metrics_memory_dump_provider_unittest.cc
@@ -288,7 +288,8 @@
   ASSERT_EQ(0, result);
   std::string name = basename(full_path);
 
-  bool found_components_unittests = false;
+  uint64_t components_unittests_resident_pages = 0;
+  bool found_appkit = false;
   for (const VMRegion& region : dump.process_mmaps()->vm_regions()) {
     EXPECT_NE(0u, region.start_address);
     EXPECT_NE(0u, region.size_in_bytes);
@@ -298,10 +299,19 @@
         VMRegion::kProtectionFlagsRead | VMRegion::kProtectionFlagsExec;
     if (region.mapped_file.find(name) != std::string::npos &&
         region.protection_flags == required_protection_flags) {
-      found_components_unittests = true;
+      components_unittests_resident_pages +=
+          region.byte_stats_private_dirty_resident +
+          region.byte_stats_shared_dirty_resident +
+          region.byte_stats_private_clean_resident +
+          region.byte_stats_shared_clean_resident;
+    }
+
+    if (region.mapped_file.find("AppKit") != std::string::npos) {
+      found_appkit = true;
     }
   }
-  EXPECT_TRUE(found_components_unittests);
+  EXPECT_GT(components_unittests_resident_pages, 0u);
+  EXPECT_TRUE(found_appkit);
 }
 #endif  // defined(OS_MACOSX)
 
diff --git a/components/translate/core/browser/translate_manager.cc b/components/translate/core/browser/translate_manager.cc
index dc8689a..cd10a75 100644
--- a/components/translate/core/browser/translate_manager.cc
+++ b/components/translate/core/browser/translate_manager.cc
@@ -585,6 +585,7 @@
   translate_event_->Clear();
   translate_event_->set_source_language(src_lang);
   translate_event_->set_target_language(dst_lang);
+  translate_event_->set_country(prefs.GetCountry());
   translate_event_->set_accept_count(
       prefs.GetTranslationAcceptedCount(src_lang));
   translate_event_->set_decline_count(
diff --git a/components/url_formatter/OWNERS b/components/url_formatter/OWNERS
index f180384..907aaa2 100644
--- a/components/url_formatter/OWNERS
+++ b/components/url_formatter/OWNERS
@@ -7,3 +7,5 @@
 # require a security review to avoid introducing security bugs.
 per-file elide_url.*=palmer@chromium.org
 per-file elide_url.*=felt@chromium.org
+
+# COMPONENT: UI>Security>UrlFormatting
diff --git a/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc b/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc
index a34d7ad..8b53b920 100644
--- a/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc
+++ b/components/user_prefs/tracked/registry_hash_store_contents_win_unittest.cc
@@ -30,7 +30,8 @@
   RegistryHashStoreContentsWinTest() {}
 
   void SetUp() override {
-    registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER);
+    ASSERT_NO_FATAL_FAILURE(
+        registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
 
     contents.reset(new RegistryHashStoreContentsWin(kRegistryPath, kStoreKey));
   }
diff --git a/components/webdata/OWNERS b/components/webdata/OWNERS
index dbe16c9b..882e1e2 100644
--- a/components/webdata/OWNERS
+++ b/components/webdata/OWNERS
@@ -2,3 +2,5 @@
 
 # For sqlite stuff:
 shess@chromium.org
+
+# COMPONENT: Internals
diff --git a/components/webdata_services/OWNERS b/components/webdata_services/OWNERS
index dbe16c9b..882e1e2 100644
--- a/components/webdata_services/OWNERS
+++ b/components/webdata_services/OWNERS
@@ -2,3 +2,5 @@
 
 # For sqlite stuff:
 shess@chromium.org
+
+# COMPONENT: Internals
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index ffe68664..e75bc9d 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1467,7 +1467,10 @@
     deps += [ "//sandbox" ]
   }
   if (!is_android) {
-    deps += [ "//content/browser/tracing:resources" ]
+    deps += [
+      "//content/browser/tracing:resources",
+      "//ui/vector_icons",
+    ]
   }
   if ((use_udev && is_posix) || is_mac || is_win) {
     deps += [ "//tools/battor_agent:battor_agent_lib" ]
diff --git a/content/browser/DEPS b/content/browser/DEPS
index d31cef3..af18f2d 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -34,6 +34,7 @@
   "+services",
   "+sql",
   "+ui/aura_extra",
+  "+ui/vector_icons",
   "+ui/webui",
   "+win8/util",
 
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc
index b565cc0..430e3c2 100644
--- a/content/browser/cache_storage/cache_storage.cc
+++ b/content/browser/cache_storage/cache_storage.cc
@@ -474,11 +474,11 @@
     }
 
     if (index_modified) {
-      if (!index.SerializeToString(&body))
+      base::FilePath tmp_path = origin_path.AppendASCII("index.txt.tmp");
+      if (!index.SerializeToString(&body) ||
+          !WriteIndexWriteToFileInPool(tmp_path, index_path, body)) {
         return proto::CacheStorageIndex();
-      if (base::WriteFile(index_path, body.c_str(), body.size()) !=
-          base::checked_cast<int>(body.size()))
-        return proto::CacheStorageIndex();
+      }
     }
 
     return index;
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
index 866cd8a2..64de60c4 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -275,26 +275,8 @@
   PurgeMemory(purge_option);
 }
 
-void DOMStorageContextWrapper::OnMemoryStateChange(base::MemoryState state) {
-  // TODO(hajimehoshi): As OnMemoryStateChange changes the state, we should
-  // adjust the limitation to the amount of cache, DomStroageContextImpl doesn't
-  // have such limitation so far though.
-  switch (state) {
-    case base::MemoryState::NORMAL:
-      // Don't have to purge memory here.
-      break;
-    case base::MemoryState::THROTTLED:
-      // TOOD(hajimehoshi): We don't have throttling 'level' so far. When we
-      // have such value, let's change the argument accroding to the value.
-      PurgeMemory(DOMStorageContextImpl::PURGE_AGGRESSIVE);
-      break;
-    case base::MemoryState::SUSPENDED:
-      // Note that SUSPENDED never occurs in the main browser process so far.
-      // Fall through.
-    case base::MemoryState::UNKNOWN:
-      NOTREACHED();
-      break;
-  }
+void DOMStorageContextWrapper::OnPurgeMemory() {
+  PurgeMemory(DOMStorageContextImpl::PURGE_AGGRESSIVE);
 }
 
 void DOMStorageContextWrapper::PurgeMemory(DOMStorageContextImpl::PurgeOption
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h
index 332869f0..2c37e330 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -91,7 +91,7 @@
       base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
 
   // base::MemoryCoordinatorClient implementation:
-  void OnMemoryStateChange(base::MemoryState state) override;
+  void OnPurgeMemory() override;
 
   void PurgeMemory(DOMStorageContextImpl::PurgeOption purge_option);
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 8e6dff6..05bf1397 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2365,7 +2365,7 @@
 #if defined(OS_ANDROID)
   GetInterfaceRegistry()->AddInterface(
       GetGlobalJavaInterfaces()
-          ->CreateInterfaceFactory<device::VibrationManager>());
+          ->CreateInterfaceFactory<device::mojom::VibrationManager>());
 
   // Creates a MojoRendererService, passing it a MediaPlayerRender.
   GetInterfaceRegistry()->AddInterface<media::mojom::Renderer>(base::Bind(
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index f760aecd..83d4acb 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -733,7 +733,8 @@
     command_line->AppendSwitch(switches::kDisableDirectComposition);
   }
   if (use_swiftshader_) {
-    command_line->AppendSwitchASCII(switches::kUseGL, "swiftshader");
+    command_line->AppendSwitchASCII(
+        switches::kUseGL, gl::kGLImplementationSwiftShaderForWebGLName);
   } else if ((IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_WEBGL) ||
               IsFeatureBlacklisted(gpu::GPU_FEATURE_TYPE_GPU_COMPOSITING) ||
               IsFeatureBlacklisted(
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 813a543..4aabfd1 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -425,14 +425,6 @@
   }
 }
 
-GpuProcessHost::EstablishChannelRequest::EstablishChannelRequest()
-    : client_id(0) {}
-
-GpuProcessHost::EstablishChannelRequest::EstablishChannelRequest(
-    const EstablishChannelRequest& other) = default;
-
-GpuProcessHost::EstablishChannelRequest::~EstablishChannelRequest() {}
-
 service_manager::InterfaceProvider* GpuProcessHost::GetRemoteInterfaces() {
   return process_->child_connection()->GetRemoteInterfaces();
 }
@@ -458,7 +450,8 @@
       kind_(kind),
       process_launched_(false),
       initialized_(false),
-      gpu_host_binding_(this) {
+      gpu_host_binding_(this),
+      weak_ptr_factory_(this) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kSingleProcess) ||
       base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -667,7 +660,6 @@
   DCHECK(CalledOnValidThread());
   IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
     IPC_MESSAGE_HANDLER(GpuHostMsg_Initialized, OnInitialized)
-    IPC_MESSAGE_HANDLER(GpuHostMsg_ChannelEstablished, OnChannelEstablished)
     IPC_MESSAGE_HANDLER(GpuHostMsg_GpuMemoryBufferCreated,
                         OnGpuMemoryBufferCreated)
 #if defined(OS_ANDROID)
@@ -707,21 +699,15 @@
     return;
   }
 
-  EstablishChannelParams params;
-  params.client_id = client_id;
-  params.client_tracing_id = client_tracing_id;
-  params.preempts = preempts;
-  params.allow_view_command_buffers = allow_view_command_buffers;
-  params.allow_real_time_streams = allow_real_time_streams;
-  if (Send(new GpuMsg_EstablishChannel(params))) {
-    EstablishChannelRequest request;
-    request.client_id = client_id;
-    request.callback = callback;
-    channel_requests_.push(request);
-  } else {
-    DVLOG(1) << "Failed to send GpuMsg_EstablishChannel.";
-    callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
-  }
+  DCHECK_EQ(preempts, allow_view_command_buffers);
+  DCHECK_EQ(preempts, allow_real_time_streams);
+  bool is_gpu_host = preempts;
+
+  channel_requests_.push(callback);
+  gpu_service_ptr_->EstablishGpuChannel(
+      client_id, client_tracing_id, is_gpu_host,
+      base::Bind(&GpuProcessHost::OnChannelEstablished,
+                 weak_ptr_factory_.GetWeakPtr(), client_id, callback));
 
   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kDisableGpuShaderDiskCache)) {
@@ -796,32 +782,27 @@
 }
 
 void GpuProcessHost::OnChannelEstablished(
-    const IPC::ChannelHandle& channel_handle) {
+    int client_id,
+    const EstablishChannelCallback& callback,
+    mojo::ScopedMessagePipeHandle channel_handle) {
   TRACE_EVENT0("gpu", "GpuProcessHost::OnChannelEstablished");
-
-  if (channel_requests_.empty()) {
-    // This happens when GPU process is compromised.
-    RouteOnUIThread(GpuHostMsg_OnLogMessage(
-        logging::LOG_WARNING, "WARNING",
-        "Received a ChannelEstablished message but no requests in queue."));
-    return;
-  }
-  EstablishChannelRequest request = channel_requests_.front();
+  DCHECK(!channel_requests_.empty());
+  DCHECK(channel_requests_.front().Equals(callback));
   channel_requests_.pop();
 
   // Currently if any of the GPU features are blacklisted, we don't establish a
   // GPU channel.
-  if (channel_handle.mojo_handle.is_valid() &&
-      !GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(NULL)) {
-    Send(new GpuMsg_CloseChannel(request.client_id));
-    request.callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
+  if (channel_handle.is_valid() &&
+      !GpuDataManagerImpl::GetInstance()->GpuAccessAllowed(nullptr)) {
+    Send(new GpuMsg_CloseChannel(client_id));
+    callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
     RouteOnUIThread(
         GpuHostMsg_OnLogMessage(logging::LOG_WARNING, "WARNING",
                                 "Hardware acceleration is unavailable."));
     return;
   }
 
-  request.callback.Run(channel_handle, gpu_info_);
+  callback.Run(IPC::ChannelHandle(channel_handle.release()), gpu_info_);
 }
 
 void GpuProcessHost::OnGpuMemoryBufferCreated(
@@ -1046,8 +1027,8 @@
   GpuDataManagerImpl::GetInstance()->AppendGpuCommandLine(cmd_line.get(),
                                                           gpu_preferences);
   if (cmd_line->HasSwitch(switches::kUseGL)) {
-    swiftshader_rendering_ =
-        (cmd_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader");
+    swiftshader_rendering_ = (cmd_line->GetSwitchValueASCII(switches::kUseGL) ==
+                              gl::kGLImplementationSwiftShaderForWebGLName);
   }
 
   bool current_gpu_type_enabled =
@@ -1076,11 +1057,12 @@
 
 void GpuProcessHost::SendOutstandingReplies() {
   valid_ = false;
+
   // First send empty channel handles for all EstablishChannel requests.
   while (!channel_requests_.empty()) {
-    EstablishChannelRequest request = channel_requests_.front();
+    auto callback = channel_requests_.front();
     channel_requests_.pop();
-    request.callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
+    callback.Run(IPC::ChannelHandle(), gpu::GPUInfo());
   }
 
   while (!create_gpu_memory_buffer_requests_.empty()) {
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 27b5c93b..5d52b91 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -72,14 +72,6 @@
   typedef base::Callback<void(const IPC::ChannelHandle&, const gpu::GPUInfo&)>
       EstablishChannelCallback;
 
-  struct EstablishChannelRequest {
-    EstablishChannelRequest();
-    EstablishChannelRequest(const EstablishChannelRequest& other);
-    ~EstablishChannelRequest();
-    int32_t client_id;
-    EstablishChannelCallback callback;
-  };
-
   typedef base::Callback<void(const gfx::GpuMemoryBufferHandle& handle)>
       CreateGpuMemoryBufferCallback;
 
@@ -196,11 +188,14 @@
                          const std::string& key,
                          const std::string& shader) override;
 
+  void OnChannelEstablished(int client_id,
+                            const EstablishChannelCallback& callback,
+                            mojo::ScopedMessagePipeHandle channel_handle);
+
   // Message handlers.
   void OnInitialized(bool result,
                      const gpu::GPUInfo& gpu_info,
                      const gpu::GpuFeatureInfo& gpu_feature_info);
-  void OnChannelEstablished(const IPC::ChannelHandle& channel_handle);
   void OnGpuMemoryBufferCreated(const gfx::GpuMemoryBufferHandle& handle);
 #if defined(OS_ANDROID)
   void OnDestroyingVideoSurfaceAck(int surface_id);
@@ -225,7 +220,7 @@
 
   // These are the channel requests that we have already sent to
   // the GPU process, but haven't heard back about yet.
-  std::queue<EstablishChannelRequest> channel_requests_;
+  std::queue<EstablishChannelCallback> channel_requests_;
 
   // The pending create gpu memory buffer requests we need to reply to.
   std::queue<CreateGpuMemoryBufferCallback> create_gpu_memory_buffer_requests_;
@@ -292,6 +287,8 @@
   ui::mojom::GpuServicePtr gpu_service_ptr_;
   mojo::Binding<ui::mojom::GpuHost> gpu_host_binding_;
 
+  base::WeakPtrFactory<GpuProcessHost> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(GpuProcessHost);
 };
 
diff --git a/content/browser/loader/resource_hints_impl.cc b/content/browser/loader/resource_hints_impl.cc
index b1bcf020..3bc81c7 100644
--- a/content/browser/loader/resource_hints_impl.cc
+++ b/content/browser/loader/resource_hints_impl.cc
@@ -34,9 +34,8 @@
   std::unique_ptr<net::HostResolver::Request> request_;
 };
 
-// Note that the lifetime of |request| and |addresses| is managed by the caller.
-void OnResolveComplete(RequestHolder* request_holder,
-                       net::AddressList* addresses,
+void OnResolveComplete(std::unique_ptr<RequestHolder> request_holder,
+                       std::unique_ptr<net::AddressList> addresses,
                        const net::CompletionCallback& callback,
                        int result) {
   // Plumb the resolution result into the callback if future consumers want
@@ -93,16 +92,22 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(resource_context);
 
-  RequestHolder* request_holder = new RequestHolder();
-  net::AddressList* addresses = new net::AddressList;
+  auto request_holder = base::MakeUnique<RequestHolder>();
+  auto addresses = base::MakeUnique<net::AddressList>();
+
+  // Save raw pointers before the unique_ptr is invalidated by base::Passed.
+  net::AddressList* raw_addresses = addresses.get();
+  std::unique_ptr<net::HostResolver::Request>* out_request =
+      request_holder->GetRequest();
+
   net::HostResolver* resolver = resource_context->GetHostResolver();
   net::HostResolver::RequestInfo resolve_info(net::HostPortPair::FromURL(url));
   resolve_info.set_is_speculative(true);
   return resolver->Resolve(
-      resolve_info, net::IDLE, addresses,
-      base::Bind(&OnResolveComplete, base::Owned(request_holder),
-                 base::Owned(addresses), callback),
-      request_holder->GetRequest(), net::NetLogWithSource());
+      resolve_info, net::IDLE, raw_addresses,
+      base::Bind(&OnResolveComplete, base::Passed(&request_holder),
+                 base::Passed(&addresses), callback),
+      out_request, net::NetLogWithSource());
 }
 
 }  // namespace content
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
index 0fb5bd9..ca48ca40 100644
--- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -34,7 +34,6 @@
 #include "content/test/test_web_contents.h"
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
-#include "media/base/yuv_convert.h"
 #include "media/capture/video/video_capture_buffer_pool_impl.h"
 #include "media/capture/video/video_capture_buffer_tracker_factory_impl.h"
 #include "media/capture/video/video_capture_device_client.h"
@@ -42,6 +41,7 @@
 #include "skia/ext/platform_canvas.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libyuv/include/libyuv.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/layout.h"
 #include "ui/display/display.h"
@@ -85,8 +85,8 @@
 
 SkColor ConvertRgbToYuv(SkColor rgb) {
   uint8_t yuv[3];
-  media::ConvertRGB32ToYUV(reinterpret_cast<uint8_t*>(&rgb), yuv, yuv + 1,
-                           yuv + 2, 1, 1, 1, 1, 1);
+  libyuv::ARGBToI420(reinterpret_cast<uint8_t*>(&rgb), 1, yuv, 1, yuv + 1, 1,
+                     yuv + 2, 1, 1, 1);
   return SkColorSetRGB(yuv[0], yuv[1], yuv[2]);
 }
 
diff --git a/content/browser/memory/memory_coordinator_impl_unittest.cc b/content/browser/memory/memory_coordinator_impl_unittest.cc
index 9c3c992..3e83a12 100644
--- a/content/browser/memory/memory_coordinator_impl_unittest.cc
+++ b/content/browser/memory/memory_coordinator_impl_unittest.cc
@@ -35,7 +35,8 @@
  public:
   MockChildMemoryCoordinator()
       : state_(mojom::MemoryState::NORMAL),
-        on_state_change_calls_(0) {}
+        on_state_change_calls_(0),
+        purge_memory_calls_(0) {}
 
   ~MockChildMemoryCoordinator() override {}
 
@@ -44,12 +45,16 @@
     ++on_state_change_calls_;
   }
 
+  void PurgeMemory() override { ++purge_memory_calls_; }
+
   mojom::MemoryState state() const { return state_; }
   int on_state_change_calls() const { return on_state_change_calls_; }
+  int purge_memory_calls() const { return purge_memory_calls_; }
 
  private:
   mojom::MemoryState state_;
   int on_state_change_calls_;
+  int purge_memory_calls_;
 };
 
 // A mock MemoryCoordinatorClient, for testing interaction between MC and
@@ -57,15 +62,15 @@
 class MockMemoryCoordinatorClient : public base::MemoryCoordinatorClient {
  public:
   void OnMemoryStateChange(base::MemoryState state) override {
-    is_called_ = true;
+    did_state_changed_ = true;
     state_ = state;
   }
 
-  bool is_called() { return is_called_; }
-  base::MemoryState state() { return state_; }
+  bool did_state_changed() const { return did_state_changed_; }
+  base::MemoryState state() const { return state_; }
 
  private:
-  bool is_called_ = false;
+  bool did_state_changed_ = false;
   base::MemoryState state_ = base::MemoryState::NORMAL;
 };
 
@@ -243,6 +248,14 @@
   EXPECT_EQ(mojom::MemoryState::THROTTLED, cmc2->state());
 }
 
+TEST_F(MemoryCoordinatorImplTest, PurgeMemoryChild) {
+  auto* child = coordinator_->CreateChildMemoryCoordinator(1);
+  EXPECT_EQ(0, child->purge_memory_calls());
+  child->PurgeMemory();
+  RunUntilIdle();
+  EXPECT_EQ(1, child->purge_memory_calls());
+}
+
 TEST_F(MemoryCoordinatorImplTest, SetChildMemoryState) {
   auto cmc = coordinator_->CreateChildMemoryCoordinator(1);
   auto iter = coordinator_->children().find(1);
@@ -368,7 +381,7 @@
     GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(40);
     state_updater->UpdateState();
     RunUntilIdle();
-    EXPECT_TRUE(client.is_called());
+    EXPECT_TRUE(client.did_state_changed());
     EXPECT_EQ(base::MemoryState::THROTTLED, client.state());
     base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(&client);
   }
@@ -381,7 +394,7 @@
     GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(50);
     state_updater->UpdateState();
     RunUntilIdle();
-    EXPECT_FALSE(client.is_called());
+    EXPECT_FALSE(client.did_state_changed());
     EXPECT_EQ(base::MemoryState::NORMAL, client.state());
     base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(&client);
   }
@@ -422,7 +435,7 @@
             base::MemoryCoordinatorProxy::GetInstance()->
             GetCurrentMemoryState());
   RunUntilIdle();
-  EXPECT_TRUE(client.is_called());
+  EXPECT_TRUE(client.did_state_changed());
   EXPECT_EQ(base::MemoryState::THROTTLED, client.state());
   base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(&client);
 }
diff --git a/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc b/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
index 4382f43..e78b971 100644
--- a/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_network_monitor_host.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
 #include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
@@ -85,9 +86,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   // Call GetNetworkList() on a thread that allows blocking IO.
-  base::PostTaskAndReplyWithResult(
-      BrowserThread::GetBlockingPool(),
-      FROM_HERE,
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, base::TaskTraits().MayBlock().WithPriority(
+                     base::TaskPriority::BACKGROUND),
       base::Bind(&GetNetworkList),
       base::Bind(&PepperNetworkMonitorHost::SendNetworkList,
                  weak_factory_.GetWeakPtr()));
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index b56d17ef..c60d39a 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -218,7 +218,7 @@
       render_process_id_, params->opener_render_frame_id, params->opener_url,
       params->opener_top_level_frame_url, params->opener_security_origin,
       params->window_container_type, params->target_url, params->referrer,
-      params->frame_name, params->disposition, params->features,
+      params->frame_name, params->disposition, *params->features,
       params->user_gesture, params->opener_suppressed, resource_context_,
       &no_javascript_access);
 
diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc
index e4ba933..2db301c 100644
--- a/content/browser/service_worker/service_worker_database.cc
+++ b/content/browser/service_worker/service_worker_database.cc
@@ -1291,6 +1291,9 @@
       out->navigation_preload_state.header = state.header();
   }
 
+  for (uint32_t feature : data.used_features())
+    out->used_features.insert(feature);
+
   return ServiceWorkerDatabase::STATUS_OK;
 }
 
@@ -1337,6 +1340,9 @@
   state->set_enabled(registration.navigation_preload_state.enabled);
   state->set_header(registration.navigation_preload_state.header);
 
+  for (uint32_t feature : registration.used_features)
+    data.add_used_features(feature);
+
   std::string value;
   bool success = data.SerializeToString(&value);
   DCHECK(success);
diff --git a/content/browser/service_worker/service_worker_database.h b/content/browser/service_worker/service_worker_database.h
index 2a609d9..95db8e6 100644
--- a/content/browser/service_worker/service_worker_database.h
+++ b/content/browser/service_worker/service_worker_database.h
@@ -75,6 +75,7 @@
     std::vector<url::Origin> foreign_fetch_origins;
     base::Optional<TrialTokenValidator::FeatureToTokensMap> origin_trial_tokens;
     NavigationPreloadState navigation_preload_state;
+    std::set<uint32_t> used_features;
 
     // Not populated until ServiceWorkerStorage::StoreRegistration is called.
     int64_t resources_total_size_bytes;
diff --git a/content/browser/service_worker/service_worker_database.proto b/content/browser/service_worker/service_worker_database.proto
index 3ae7551..892001d0 100644
--- a/content/browser/service_worker/service_worker_database.proto
+++ b/content/browser/service_worker/service_worker_database.proto
@@ -50,6 +50,10 @@
   optional ServiceWorkerOriginTrialInfo origin_trial_tokens = 11;
 
   optional ServiceWorkerNavigationPreloadState navigation_preload_state = 12;
+
+  // The set of features that the worker used up until the time installation
+  // completed. The values must be from blink::UseCounter::Feature enum.
+  repeated uint32 used_features = 13;
 }
 
 message ServiceWorkerResourceRecord {
diff --git a/content/browser/service_worker/service_worker_database_unittest.cc b/content/browser/service_worker/service_worker_database_unittest.cc
index 6806a8b..e654e886 100644
--- a/content/browser/service_worker/service_worker_database_unittest.cc
+++ b/content/browser/service_worker/service_worker_database_unittest.cc
@@ -72,6 +72,7 @@
             actual.resources_total_size_bytes);
   EXPECT_EQ(expected.foreign_fetch_scopes, actual.foreign_fetch_scopes);
   EXPECT_EQ(expected.foreign_fetch_origins, actual.foreign_fetch_origins);
+  EXPECT_EQ(expected.used_features, actual.used_features);
 }
 
 void VerifyResourceRecords(const std::vector<Resource>& expected,
@@ -623,6 +624,7 @@
   data.version_id = 200;
   data.resources_total_size_bytes = 10939 + 200;
   data.foreign_fetch_scopes.push_back(URL(origin, "/foo/bar"));
+  data.used_features = {124, 901, 1019};
 
   std::vector<Resource> resources;
   resources.push_back(CreateResource(1, URL(origin, "/resource1"), 10939));
@@ -762,6 +764,7 @@
   data.foreign_fetch_scopes.push_back(URL(origin, "/foo"));
   data.foreign_fetch_origins.push_back(
       url::Origin(GURL("https://chromium.org")));
+  data.used_features = {124, 901, 1019};
 
   std::vector<Resource> resources1;
   resources1.push_back(CreateResource(1, URL(origin, "/resource1"), 10));
@@ -794,6 +797,7 @@
   updated_data.foreign_fetch_scopes.clear();
   updated_data.foreign_fetch_origins.push_back(
       url::Origin(GURL("https://example.com")));
+  updated_data.used_features = {109, 421, 9101};
   std::vector<Resource> resources2;
   resources2.push_back(CreateResource(3, URL(origin, "/resource3"), 12));
   resources2.push_back(CreateResource(4, URL(origin, "/resource4"), 13));
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index 0c4a3d3..51c500c 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -211,6 +211,7 @@
                         OnWorkerStarted)
     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_WorkerStopped,
                         OnWorkerStopped)
+    IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_CountFeature, OnCountFeature)
     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportException,
                         OnReportException)
     IPC_MESSAGE_HANDLER(EmbeddedWorkerHostMsg_ReportConsoleMessage,
@@ -1484,6 +1485,16 @@
   registry->OnWorkerStopped(render_process_id_, embedded_worker_id);
 }
 
+void ServiceWorkerDispatcherHost::OnCountFeature(int64_t version_id,
+                                                 uint32_t feature) {
+  if (!GetContext())
+    return;
+  ServiceWorkerVersion* version = GetContext()->GetLiveVersion(version_id);
+  if (!version)
+    return;
+  version->CountFeature(feature);
+}
+
 void ServiceWorkerDispatcherHost::OnReportException(
     int embedded_worker_id,
     const base::string16& error_message,
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index ae1e551..0e63d000 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -156,6 +156,7 @@
   void OnWorkerScriptEvaluated(int embedded_worker_id, bool success);
   void OnWorkerStarted(int embedded_worker_id);
   void OnWorkerStopped(int embedded_worker_id);
+  void OnCountFeature(int64_t version_id, uint32_t feature);
   void OnReportException(int embedded_worker_id,
                          const base::string16& error_message,
                          int line_number,
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index a32fdd3..2e6394b 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -248,7 +248,8 @@
   DCHECK(IsProviderForClient());
   Send(new ServiceWorkerMsg_SetControllerServiceWorker(
       render_thread_id_, provider_id(), GetOrCreateServiceWorkerHandle(version),
-      notify_controllerchange));
+      notify_controllerchange,
+      version ? version->used_features() : std::set<uint32_t>()));
 }
 
 void ServiceWorkerProviderHost::SetHostedVersion(
@@ -459,6 +460,16 @@
   Send(new ServiceWorkerMsg_MessageToDocument(params));
 }
 
+void ServiceWorkerProviderHost::CountFeature(uint32_t feature) {
+  if (!dispatcher_host_)
+    return;  // Could be nullptr in some tests.
+
+  // CountFeature message should be sent only for controllees.
+  DCHECK(IsProviderForClient());
+  Send(new ServiceWorkerMsg_CountFeature(render_thread_id_, provider_id(),
+                                         feature));
+}
+
 void ServiceWorkerProviderHost::AddScopedProcessReferenceToPattern(
     const GURL& pattern) {
   associated_patterns_.push_back(pattern);
@@ -731,7 +742,8 @@
           render_thread_id_, provider_id(),
           GetOrCreateServiceWorkerHandle(
               associated_registration_->active_version()),
-          false /* shouldNotifyControllerChange */));
+          false /* shouldNotifyControllerChange */,
+          associated_registration_->active_version()->used_features()));
     }
   }
 }
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 3ed67ba..af78af83 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -234,6 +234,10 @@
                            const base::string16& message,
                            const std::vector<int>& sent_message_ports);
 
+  // Notifies the client that its controller used a feature, for UseCounter
+  // purposes. This can only be called if IsProviderForClient() is true.
+  void CountFeature(uint32_t feature);
+
   // Adds reference of this host's process to the |pattern|, the reference will
   // be removed in destructor.
   void AddScopedProcessReferenceToPattern(const GURL& pattern);
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc
index b9730196..e1adc7c 100644
--- a/content/browser/service_worker/service_worker_storage.cc
+++ b/content/browser/service_worker/service_worker_storage.cc
@@ -417,6 +417,7 @@
   if (version->origin_trial_tokens())
     data.origin_trial_tokens = *version->origin_trial_tokens();
   data.navigation_preload_state = registration->navigation_preload_state();
+  data.used_features = version->used_features();
 
   ResourceList resources;
   version->script_cache_map()->GetResources(&resources);
@@ -1324,6 +1325,7 @@
     version->set_foreign_fetch_origins(data.foreign_fetch_origins);
     if (data.origin_trial_tokens)
       version->SetValidOriginTrialTokens(*data.origin_trial_tokens);
+    version->set_used_features(data.used_features);
   }
 
   if (version->status() == ServiceWorkerVersion::ACTIVATED)
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc
index 9598586..51e0cb6 100644
--- a/content/browser/service_worker/service_worker_storage_unittest.cc
+++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -636,6 +636,7 @@
   const url::Origin kForeignFetchOrigin(GURL("https://example.com/"));
   const base::Time kToday = base::Time::Now();
   const base::Time kYesterday = kToday - base::TimeDelta::FromDays(1);
+  std::set<uint32_t> used_features = {124, 901, 1019};
 
   scoped_refptr<ServiceWorkerRegistration> found_registration;
 
@@ -673,6 +674,7 @@
       std::vector<GURL>(1, kForeignFetchScope));
   live_version->set_foreign_fetch_origins(
       std::vector<url::Origin>(1, kForeignFetchOrigin));
+  live_version->set_used_features(used_features);
   live_registration->SetWaitingVersion(live_version);
   live_registration->set_last_update_check(kYesterday);
   EXPECT_EQ(SERVICE_WORKER_OK,
@@ -686,6 +688,8 @@
             live_registration->resources_total_size_bytes());
   EXPECT_EQ(kResource1Size + kResource2Size,
             found_registration->resources_total_size_bytes());
+  EXPECT_EQ(used_features,
+            found_registration->waiting_version()->used_features());
   found_registration = NULL;
 
   // But FindRegistrationForPattern is always async.
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index c205b9c9..b82770ce 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -1104,6 +1104,13 @@
   return NavigationPreloadSupportStatus::NOT_SUPPORTED_FIELD_TRIAL_STOPPED;
 }
 
+void ServiceWorkerVersion::CountFeature(uint32_t feature) {
+  if (!used_features_.insert(feature).second)
+    return;
+  for (auto provider_host_by_uuid : controllee_map_)
+    provider_host_by_uuid.second->CountFeature(feature);
+}
+
 void ServiceWorkerVersion::OnSimpleEventResponse(
     int request_id,
     blink::WebServiceWorkerEventResult result,
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index deaac57..cf37ce59 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -465,6 +465,12 @@
   // for both A and B case. So the methods and attributes are available in JS.
   NavigationPreloadSupportStatus GetNavigationPreloadSupportStatus() const;
 
+  void CountFeature(uint32_t feature);
+  void set_used_features(const std::set<uint32_t>& used_features) {
+    used_features_ = used_features;
+  }
+  const std::set<uint32_t>& used_features() const { return used_features_; }
+
  private:
   friend class base::RefCounted<ServiceWorkerVersion>;
   friend class ServiceWorkerMetrics;
@@ -850,6 +856,11 @@
   // FinishStartWorker().
   base::Optional<ServiceWorkerMetrics::EventType> start_worker_first_purpose_;
 
+  // This is the set of features that were used up until installation of this
+  // version completed, or used during the lifetime of |this|. The values must
+  // be from blink::UseCounter::Feature enum.
+  std::set<uint32_t> used_features_;
+
   base::WeakPtrFactory<ServiceWorkerVersion> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerVersion);
diff --git a/content/browser/vibration_browsertest.cc b/content/browser/vibration_browsertest.cc
index 9aedfb8..342e58b 100644
--- a/content/browser/vibration_browsertest.cc
+++ b/content/browser/vibration_browsertest.cc
@@ -49,12 +49,12 @@
   g_wait_cancel_runner = new MessageLoopRunner();
 }
 
-class FakeVibrationManager : public device::VibrationManager {
+class FakeVibrationManager : public device::mojom::VibrationManager {
  public:
   FakeVibrationManager() {}
   ~FakeVibrationManager() override {}
 
-  static void Create(device::VibrationManagerRequest request) {
+  static void Create(device::mojom::VibrationManagerRequest request) {
     mojo::MakeStrongBinding(base::MakeUnique<FakeVibrationManager>(),
                             std::move(request));
   }
diff --git a/content/browser/web_contents/aura/gesture_nav_simple.cc b/content/browser/web_contents/aura/gesture_nav_simple.cc
index cef6749..e6c3601 100644
--- a/content/browser/web_contents/aura/gesture_nav_simple.cc
+++ b/content/browser/web_contents/aura/gesture_nav_simple.cc
@@ -7,33 +7,59 @@
 #include <utility>
 
 #include "base/macros.h"
-#include "cc/layers/layer.h"
 #include "cc/paint/paint_flags.h"
 #include "content/browser/frame_host/navigation_controller_impl.h"
 #include "content/browser/renderer_host/overscroll_controller.h"
 #include "content/browser/web_contents/web_contents_impl.h"
-#include "content/browser/web_contents/web_contents_view.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/overscroll_configuration.h"
-#include "content/public/common/content_client.h"
+#include "third_party/skia/include/core/SkDrawLooper.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
-#include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/layer_delegate.h"
 #include "ui/compositor/paint_recorder.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/gfx/animation/animation_delegate.h"
+#include "ui/gfx/animation/linear_animation.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/image/image.h"
-#include "ui/resources/grit/ui_resources.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/shadow_value.h"
+#include "ui/gfx/skia_paint_util.h"
+#include "ui/vector_icons/vector_icons.h"
 
 namespace content {
 
 namespace {
 
-const int kArrowHeight = 280;
-const int kArrowWidth = 140;
-const float kMinOpacity = 0.25f;
+// Parameters defining the arrow icon inside the affordance.
+const int kArrowSize = 16;
+const SkColor kArrowColor = gfx::kGoogleBlue500;
+
+// Parameters defining the background circle of the affordance.
+const int kBackgroundRadius = 18;
+const SkColor kBackgroundColor = SK_ColorWHITE;
+const int kBgShadowOffsetY = 2;
+const int kBgShadowBlurRadius = 8;
+const SkColor kBgShadowColor = SkColorSetA(SK_ColorBLACK, 0x4D);
+
+// Parameters defining the affordance ripple. The ripple fades in and grows as
+// the user drags the affordance until it reaches |kMaxRippleRadius|. If the
+// overscroll is successful, the ripple will burst by fading out and growing to
+// |kMaxRippleBurstRadius|.
+const int kMaxRippleRadius = 54;
+const SkColor kRippleColor = SkColorSetA(gfx::kGoogleBlue500, 0x33);
+const int kMaxRippleBurstRadius = 72;
+const gfx::Tween::Type kBurstAnimationTweenType = gfx::Tween::EASE_IN;
+const int kRippleBurstAnimationDuration = 160;
+
+// Offset of the affordance when it is at the maximum distance with content
+// border. Since the affordance is initially out of content bounds, this is the
+// offset of the farther side of the affordance (which equals 128 + 18).
+const int kMaxAffordanceOffset = 146;
+
+// Parameters defining animation when the affordance is aborted.
+const gfx::Tween::Type kAbortAnimationTweenType = gfx::Tween::EASE_IN;
+const int kAbortAnimationDuration = 300;
 
 bool ShouldNavigateForward(const NavigationController& controller,
                            OverscrollMode mode) {
@@ -47,124 +73,282 @@
          controller.CanGoBack();
 }
 
-// An animation observers that deletes itself and a pointer after the end of the
-// animation.
-template <class T>
-class DeleteAfterAnimation : public ui::ImplicitAnimationObserver {
- public:
-  explicit DeleteAfterAnimation(std::unique_ptr<T> object)
-      : object_(std::move(object)) {}
-
- private:
-  friend class base::DeleteHelper<DeleteAfterAnimation<T> >;
-
-  ~DeleteAfterAnimation() override {}
-
-  // ui::ImplicitAnimationObserver:
-  void OnImplicitAnimationsCompleted() override {
-    // Deleting an observer when a ScopedLayerAnimationSettings is iterating
-    // over them can cause a crash (which can happen during tests). So instead,
-    // schedule this observer to be deleted soon.
-    BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
-  }
-
-  std::unique_ptr<T> object_;
-  DISALLOW_COPY_AND_ASSIGN(DeleteAfterAnimation);
-};
-
 }  // namespace
 
-// A layer delegate that paints the shield with the arrow in it.
-class ArrowLayerDelegate : public ui::LayerDelegate {
+// This class is responsible for creating, painting, and positioning the layer
+// for the gesture nav affordance.
+class GestureNavSimple::Affordance : public ui::LayerDelegate,
+                                     public gfx::AnimationDelegate {
  public:
-  explicit ArrowLayerDelegate(int resource_id)
-      : image_(GetContentClient()->GetNativeImageNamed(resource_id)),
-        left_arrow_(resource_id == IDR_BACK_ARROW) {
-    CHECK(!image_.IsEmpty());
-  }
+  Affordance(OverscrollMode mode, const gfx::Rect& content_bounds);
+  ~Affordance() override;
 
-  ~ArrowLayerDelegate() override {}
+  // Sets progress of affordance drag as a value between 0 and 1.
+  void SetDragProgress(float progress);
 
-  bool left() const { return left_arrow_; }
+  // Aborts the affordance and animates it back. This will delete |this|
+  // instance after the animation.
+  void Abort();
+
+  // Completes the affordance by doing a ripple burst animation. This will
+  // delete |this| instance after the animation.
+  void Complete();
+
+  // Returns the root layer of the affordance.
+  ui::Layer* root_layer() const { return root_layer_.get(); }
 
  private:
+  enum class State { DRAGGING, ABORTING, COMPLETING };
+
+  void UpdateTransform();
+  void SchedulePaint();
+  void SetAbortProgress(float progress);
+  void SetCompleteProgress(float progress);
+
   // ui::LayerDelegate:
-  void OnPaintLayer(const ui::PaintContext& context) override {
-    cc::PaintFlags paint;
-    paint.setColor(SkColorSetARGB(0xa0, 0, 0, 0));
-    paint.setStyle(cc::PaintFlags::kFill_Style);
-    paint.setAntiAlias(true);
+  void OnPaintLayer(const ui::PaintContext& context) override;
+  void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
+  void OnDeviceScaleFactorChanged(float device_scale_factor) override;
 
-    // Set the recording size to be the size of the |arrow_| layer, and draw a
-    // half circle (the other half will be clipped), then an arrow image inside
-    // it.
-    ui::PaintRecorder recorder(context, gfx::Size(kArrowWidth, kArrowHeight));
-    recorder.canvas()->DrawCircle(
-        gfx::Point(left_arrow_ ? 0 : kArrowWidth, kArrowHeight / 2),
-        kArrowWidth, paint);
-    recorder.canvas()->DrawImageInt(
-        *image_.ToImageSkia(), left_arrow_ ? 0 : kArrowWidth - image_.Width(),
-        (kArrowHeight - image_.Height()) / 2);
-  }
+  // gfx::AnimationDelegate:
+  void AnimationEnded(const gfx::Animation* animation) override;
+  void AnimationProgressed(const gfx::Animation* animation) override;
+  void AnimationCanceled(const gfx::Animation* animation) override;
 
-  void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
+  const OverscrollMode mode_;
 
-  void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
+  // Root layer of the affordance. This is used to clip the affordance to the
+  // content bounds.
+  std::unique_ptr<ui::Layer> root_layer_;
 
-  const gfx::Image& image_;
-  const bool left_arrow_;
+  // Layer that actually paints the affordance.
+  std::unique_ptr<ui::Layer> painted_layer_;
 
-  DISALLOW_COPY_AND_ASSIGN(ArrowLayerDelegate);
+  // Arrow image to be used for the affordance.
+  const gfx::Image image_;
+
+  // Values that determine current state of the affordance.
+  State state_ = State::DRAGGING;
+  float drag_progress_ = 0.f;
+  float abort_progress_ = 0.f;
+  float complete_progress_ = 0.f;
+
+  std::unique_ptr<gfx::LinearAnimation> animation_;
+
+  DISALLOW_COPY_AND_ASSIGN(Affordance);
 };
 
+GestureNavSimple::Affordance::Affordance(OverscrollMode mode,
+                                         const gfx::Rect& content_bounds)
+    : mode_(mode),
+      root_layer_(base::MakeUnique<ui::Layer>(ui::LAYER_NOT_DRAWN)),
+      painted_layer_(base::MakeUnique<ui::Layer>(ui::LAYER_TEXTURED)),
+      image_(gfx::CreateVectorIcon(
+          mode == OVERSCROLL_EAST ? ui::kBackArrowIcon : ui::kForwardArrowIcon,
+          kArrowSize,
+          kArrowColor)) {
+  DCHECK(mode == OVERSCROLL_EAST || mode == OVERSCROLL_WEST);
+  DCHECK(!image_.IsEmpty());
+
+  root_layer_->SetBounds(content_bounds);
+  root_layer_->SetMasksToBounds(true);
+
+  painted_layer_->SetFillsBoundsOpaquely(false);
+  int x =
+      mode_ == OVERSCROLL_EAST
+          ? -kMaxRippleBurstRadius - kBackgroundRadius
+          : content_bounds.width() - kMaxRippleBurstRadius + kBackgroundRadius;
+  int y = std::max(0, content_bounds.height() / 2 - kMaxRippleBurstRadius);
+  painted_layer_->SetBounds(
+      gfx::Rect(x, y, 2 * kMaxRippleBurstRadius, 2 * kMaxRippleBurstRadius));
+  painted_layer_->set_delegate(this);
+
+  root_layer_->Add(painted_layer_.get());
+}
+
+GestureNavSimple::Affordance::~Affordance() {}
+
+void GestureNavSimple::Affordance::SetDragProgress(float progress) {
+  DCHECK_EQ(State::DRAGGING, state_);
+  DCHECK_LE(0.f, progress);
+  DCHECK_GE(1.f, progress);
+
+  if (drag_progress_ == progress)
+    return;
+  drag_progress_ = progress;
+
+  UpdateTransform();
+  SchedulePaint();
+}
+
+void GestureNavSimple::Affordance::Abort() {
+  DCHECK_EQ(State::DRAGGING, state_);
+
+  state_ = State::ABORTING;
+
+  animation_.reset(
+      new gfx::LinearAnimation(drag_progress_ * kAbortAnimationDuration,
+                               gfx::LinearAnimation::kDefaultFrameRate, this));
+  animation_->Start();
+}
+
+void GestureNavSimple::Affordance::Complete() {
+  DCHECK_EQ(State::DRAGGING, state_);
+  DCHECK_EQ(1.f, drag_progress_);
+
+  state_ = State::COMPLETING;
+
+  animation_.reset(
+      new gfx::LinearAnimation(kRippleBurstAnimationDuration,
+                               gfx::LinearAnimation::kDefaultFrameRate, this));
+  animation_->Start();
+}
+
+void GestureNavSimple::Affordance::UpdateTransform() {
+  float offset = (1 - abort_progress_) * drag_progress_ * kMaxAffordanceOffset;
+  gfx::Transform transform;
+  transform.Translate(mode_ == OVERSCROLL_EAST ? offset : -offset, 0);
+  painted_layer_->SetTransform(transform);
+}
+
+void GestureNavSimple::Affordance::SchedulePaint() {
+  painted_layer_->SchedulePaint(gfx::Rect(painted_layer_->size()));
+}
+
+void GestureNavSimple::Affordance::SetAbortProgress(float progress) {
+  DCHECK_EQ(State::ABORTING, state_);
+  DCHECK_LE(0.f, progress);
+  DCHECK_GE(1.f, progress);
+
+  if (abort_progress_ == progress)
+    return;
+  abort_progress_ = progress;
+
+  UpdateTransform();
+  SchedulePaint();
+}
+
+void GestureNavSimple::Affordance::SetCompleteProgress(float progress) {
+  DCHECK_EQ(State::COMPLETING, state_);
+  DCHECK_LE(0.f, progress);
+  DCHECK_GE(1.f, progress);
+
+  if (complete_progress_ == progress)
+    return;
+  complete_progress_ = progress;
+
+  painted_layer_->SetOpacity(1 - complete_progress_);
+  SchedulePaint();
+}
+
+void GestureNavSimple::Affordance::OnPaintLayer(
+    const ui::PaintContext& context) {
+  DCHECK(drag_progress_ == 1.f || state_ != State::COMPLETING);
+  DCHECK(abort_progress_ == 0.f || state_ == State::ABORTING);
+  DCHECK(complete_progress_ == 0.f || state_ == State::COMPLETING);
+
+  ui::PaintRecorder recorder(context, painted_layer_->size());
+  gfx::Canvas* canvas = recorder.canvas();
+
+  gfx::PointF center_point(kMaxRippleBurstRadius, kMaxRippleBurstRadius);
+  float progress = (1 - abort_progress_) * drag_progress_;
+
+  // Draw the ripple.
+  cc::PaintFlags ripple_paint;
+  ripple_paint.setAntiAlias(true);
+  ripple_paint.setStyle(cc::PaintFlags::kFill_Style);
+  ripple_paint.setColor(kRippleColor);
+  float ripple_radius;
+  if (state_ == State::COMPLETING) {
+    ripple_radius =
+        kMaxRippleRadius +
+        complete_progress_ * (kMaxRippleBurstRadius - kMaxRippleRadius);
+  } else {
+    ripple_radius =
+        kBackgroundRadius + progress * (kMaxRippleRadius - kBackgroundRadius);
+  }
+  canvas->DrawCircle(center_point, ripple_radius, ripple_paint);
+
+  // Draw the arrow background circle with the shadow.
+  cc::PaintFlags bg_paint;
+  bg_paint.setAntiAlias(true);
+  bg_paint.setStyle(cc::PaintFlags::kFill_Style);
+  bg_paint.setColor(kBackgroundColor);
+  gfx::ShadowValues shadow;
+  shadow.emplace_back(gfx::Vector2d(0, kBgShadowOffsetY), kBgShadowBlurRadius,
+                      kBgShadowColor);
+  bg_paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadow));
+  canvas->DrawCircle(center_point, kBackgroundRadius, bg_paint);
+
+  // Draw the arrow.
+  float arrow_x = center_point.x() - kArrowSize / 2.f;
+  float arrow_y = center_point.y() - kArrowSize / 2.f;
+  // Calculate the offset for the arrow relative to its circular background.
+  float arrow_x_offset =
+      (1 - progress) * (-kBackgroundRadius + kArrowSize / 2.f);
+  arrow_x += mode_ == OVERSCROLL_EAST ? arrow_x_offset : -arrow_x_offset;
+  uint8_t arrow_alpha =
+      static_cast<uint8_t>(std::min(0xFF, static_cast<int>(progress * 0xFF)));
+  canvas->DrawImageInt(*image_.ToImageSkia(), static_cast<int>(arrow_x),
+                       static_cast<int>(arrow_y), arrow_alpha);
+}
+
+void GestureNavSimple::Affordance::OnDelegatedFrameDamage(
+    const gfx::Rect& damage_rect_in_dip) {}
+
+void GestureNavSimple::Affordance::OnDeviceScaleFactorChanged(
+    float device_scale_factor) {}
+
+void GestureNavSimple::Affordance::AnimationEnded(
+    const gfx::Animation* animation) {
+  delete this;
+}
+
+void GestureNavSimple::Affordance::AnimationProgressed(
+    const gfx::Animation* animation) {
+  switch (state_) {
+    case State::DRAGGING:
+      NOTREACHED();
+      break;
+    case State::ABORTING:
+      SetAbortProgress(gfx::Tween::CalculateValue(
+          kAbortAnimationTweenType, animation->GetCurrentValue()));
+      break;
+    case State::COMPLETING:
+      SetCompleteProgress(gfx::Tween::CalculateValue(
+          kBurstAnimationTweenType, animation->GetCurrentValue()));
+      break;
+  }
+}
+
+void GestureNavSimple::Affordance::AnimationCanceled(
+    const gfx::Animation* animation) {
+  NOTREACHED();
+}
+
+
 GestureNavSimple::GestureNavSimple(WebContentsImpl* web_contents)
     : web_contents_(web_contents),
       completion_threshold_(0.f) {}
 
 GestureNavSimple::~GestureNavSimple() {}
 
-void GestureNavSimple::ApplyEffectsAndDestroy(const gfx::Transform& transform,
-                                              float opacity) {
-  ui::Layer* layer = arrow_.get();
-  ui::ScopedLayerAnimationSettings settings(arrow_->GetAnimator());
-  settings.AddObserver(
-      new DeleteAfterAnimation<ArrowLayerDelegate>(std::move(arrow_delegate_)));
-  settings.AddObserver(new DeleteAfterAnimation<ui::Layer>(std::move(arrow_)));
-  settings.AddObserver(
-      new DeleteAfterAnimation<ui::Layer>(std::move(clip_layer_)));
-  layer->SetTransform(transform);
-  layer->SetOpacity(opacity);
-}
-
 void GestureNavSimple::AbortGestureAnimation() {
-  if (!arrow_)
+  if (!affordance_)
     return;
-  gfx::Transform transform;
-  transform.Translate(arrow_delegate_->left() ? -kArrowWidth : kArrowWidth, 0);
-  ApplyEffectsAndDestroy(transform, kMinOpacity);
+  // Release the unique pointer. The affordance will delete itself upon
+  // completion of animation.
+  Affordance* affordance = affordance_.release();
+  affordance->Abort();
 }
 
 void GestureNavSimple::CompleteGestureAnimation() {
-  if (!arrow_)
+  if (!affordance_)
     return;
-  // Make sure the fade-out starts from the complete state.
-  ApplyEffectsForDelta(completion_threshold_);
-  ApplyEffectsAndDestroy(arrow_->transform(), 0.f);
-}
-
-bool GestureNavSimple::ApplyEffectsForDelta(float delta_x) {
-  if (!arrow_)
-    return false;
-  CHECK_GT(completion_threshold_, 0.f);
-  CHECK_GE(delta_x, 0.f);
-  double complete = std::min(1.f, delta_x / completion_threshold_);
-  float translate_x = gfx::Tween::FloatValueBetween(complete, -kArrowWidth, 0);
-  gfx::Transform transform;
-  transform.Translate(arrow_delegate_->left() ? translate_x : -translate_x,
-                      0.f);
-  arrow_->SetTransform(transform);
-  arrow_->SetOpacity(gfx::Tween::FloatValueBetween(complete, kMinOpacity, 1.f));
-  return true;
+  // Release the unique pointer. The affordance will delete itself upon
+  // completion of animation.
+  Affordance* affordance = affordance_.release();
+  affordance->Complete();
 }
 
 gfx::Rect GestureNavSimple::GetVisibleBounds() const {
@@ -172,7 +356,11 @@
 }
 
 bool GestureNavSimple::OnOverscrollUpdate(float delta_x, float delta_y) {
-  return ApplyEffectsForDelta(std::abs(delta_x) + 50.f);
+  if (!affordance_)
+    return false;
+  affordance_->SetDragProgress(
+      std::min(1.f, std::abs(delta_x) / completion_threshold_));
+  return true;
 }
 
 void GestureNavSimple::OnOverscrollComplete(OverscrollMode overscroll_mode) {
@@ -194,47 +382,24 @@
     return;
   }
 
-  arrow_.reset(new ui::Layer(ui::LAYER_TEXTURED));
-  // Note that RTL doesn't affect the arrow that should be displayed.
-  int resource_id = 0;
-  if (new_mode == OVERSCROLL_WEST)
-    resource_id = IDR_FORWARD_ARROW;
-  else if (new_mode == OVERSCROLL_EAST)
-    resource_id = IDR_BACK_ARROW;
-  else
-    NOTREACHED();
-
-  arrow_delegate_.reset(new ArrowLayerDelegate(resource_id));
-  arrow_->set_delegate(arrow_delegate_.get());
-  arrow_->SetFillsBoundsOpaquely(false);
-
   aura::Window* window = web_contents_->GetNativeView();
   const gfx::Rect& window_bounds = window->bounds();
-  completion_threshold_ = window_bounds.width() *
-      GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE);
+  completion_threshold_ =
+      window_bounds.width() *
+          GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_COMPLETE) -
+      GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN);
 
-  // Align on the left or right edge.
-  int x = (resource_id == IDR_BACK_ARROW) ? 0 :
-      (window_bounds.width() - kArrowWidth);
-  // Align in the center vertically.
-  int y = std::max(0, (window_bounds.height() - kArrowHeight) / 2);
-  arrow_->SetBounds(gfx::Rect(x, y, kArrowWidth, kArrowHeight));
-  ApplyEffectsForDelta(0.f);
+  affordance_.reset(new Affordance(new_mode, window_bounds));
 
-  // Adding the arrow as a child of the content window is not sufficient,
-  // because it is possible for a new layer to be parented on top of the arrow
-  // layer (e.g. when the navigated-to page is displayed while the completion
-  // animation is in progress). So instead, a clip layer (that doesn't paint) is
-  // installed on top of the content window as its sibling, and the arrow layer
-  // is added to that clip layer.
-  clip_layer_.reset(new ui::Layer(ui::LAYER_NOT_DRAWN));
-  clip_layer_->SetBounds(window->layer()->bounds());
-  clip_layer_->SetMasksToBounds(true);
-  clip_layer_->Add(arrow_.get());
-
+  // Adding the affordance as a child of the content window is not sufficient,
+  // because it is possible for a new layer to be parented on top of the
+  // affordance layer (e.g. when the navigated-to page is displayed while the
+  // completion animation is in progress). So instead, it is installed on top of
+  // the content window as its sibling. Note that the affordance itself makes
+  // sure that its contents are clipped to the bounds given to it.
   ui::Layer* parent = window->layer()->parent();
-  parent->Add(clip_layer_.get());
-  parent->StackAtTop(clip_layer_.get());
+  parent->Add(affordance_->root_layer());
+  parent->StackAtTop(affordance_->root_layer());
 }
 
 }  // namespace content
diff --git a/content/browser/web_contents/aura/gesture_nav_simple.h b/content/browser/web_contents/aura/gesture_nav_simple.h
index d2c5937..44dc2b6 100644
--- a/content/browser/web_contents/aura/gesture_nav_simple.h
+++ b/content/browser/web_contents/aura/gesture_nav_simple.h
@@ -10,17 +10,8 @@
 #include "base/macros.h"
 #include "content/browser/renderer_host/overscroll_controller_delegate.h"
 
-namespace gfx {
-class Transform;
-}
-
-namespace ui {
-class Layer;
-}
-
 namespace content {
 
-class ArrowLayerDelegate;
 class WebContentsImpl;
 
 // A simple delegate for the overscroll controller that paints an arrow on top
@@ -31,23 +22,20 @@
   ~GestureNavSimple() override;
 
  private:
-  void ApplyEffectsAndDestroy(const gfx::Transform& transform, float opacity);
+  class Affordance;
+
   void AbortGestureAnimation();
   void CompleteGestureAnimation();
-  bool ApplyEffectsForDelta(float delta_x);
 
   // OverscrollControllerDelegate:
   gfx::Rect GetVisibleBounds() const override;
-  // Returns true if the scroll update was consumed.
   bool OnOverscrollUpdate(float delta_x, float delta_y) override;
   void OnOverscrollComplete(OverscrollMode overscroll_mode) override;
   void OnOverscrollModeChange(OverscrollMode old_mode,
                               OverscrollMode new_mode) override;
 
   WebContentsImpl* web_contents_;
-  std::unique_ptr<ui::Layer> clip_layer_;
-  std::unique_ptr<ui::Layer> arrow_;
-  std::unique_ptr<ArrowLayerDelegate> arrow_delegate_;
+  std::unique_ptr<Affordance> affordance_;
   float completion_threshold_;
 
   DISALLOW_COPY_AND_ASSIGN(GestureNavSimple);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 260f219b..6fcb922d 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2116,8 +2116,6 @@
     // Save the created window associated with the route so we can show it
     // later.
     DCHECK_NE(MSG_ROUTING_NONE, main_frame_widget_route_id);
-    CHECK(RenderWidgetHostImpl::FromID(render_process_id,
-                                       main_frame_widget_route_id));
     pending_contents_[std::make_pair(
         render_process_id, main_frame_widget_route_id)] = new_contents;
     AddDestructionObserver(new_contents);
@@ -2135,9 +2133,15 @@
     bool was_blocked = false;
     if (delegate_) {
       gfx::Rect initial_rect;
+      base::WeakPtr<WebContentsImpl> weak_new_contents =
+          new_contents->weak_factory_.GetWeakPtr();
+
       delegate_->AddNewContents(
           this, new_contents, params.disposition, initial_rect,
           params.user_gesture, &was_blocked);
+
+      if (!weak_new_contents)
+        return;  // The delegate deleted |new_contents| during AddNewContents().
     }
     if (!was_blocked) {
       OpenURLParams open_params(params.target_url, params.referrer,
@@ -2215,27 +2219,25 @@
                                         WindowOpenDisposition disposition,
                                         const gfx::Rect& initial_rect,
                                         bool user_gesture) {
-  WebContentsImpl* contents =
+  WebContentsImpl* popup =
       GetCreatedWindow(process_id, main_frame_widget_route_id);
-  if (contents) {
-    RenderWidgetHostImpl* rwh =
-        RenderWidgetHostImpl::FromID(process_id, main_frame_widget_route_id);
-    if (!rwh) {
-      // TODO(nick): Temporary for https://crbug.com/680876
-      base::debug::DumpWithoutCrashing();
-      return;
-    }
-
+  if (popup) {
     WebContentsDelegate* delegate = GetDelegate();
-    contents->is_resume_pending_ = true;
+    popup->is_resume_pending_ = true;
     if (!delegate || delegate->ShouldResumeRequestsForCreatedWindow())
-      contents->ResumeLoadingCreatedWebContents();
+      popup->ResumeLoadingCreatedWebContents();
 
     if (delegate) {
-      delegate->AddNewContents(this, contents, disposition, initial_rect,
-                               user_gesture, NULL);
+      base::WeakPtr<WebContentsImpl> weak_popup =
+          popup->weak_factory_.GetWeakPtr();
+      delegate->AddNewContents(this, popup, disposition, initial_rect,
+                               user_gesture, nullptr);
+      if (!weak_popup)
+        return;  // The delegate deleted |popup| during AddNewContents().
     }
 
+    RenderWidgetHostImpl* rwh = popup->GetMainFrame()->GetRenderWidgetHost();
+    DCHECK_EQ(main_frame_widget_route_id, rwh->GetRoutingID());
     rwh->Send(new ViewMsg_Move_ACK(rwh->GetRoutingID()));
   }
 }
diff --git a/content/child/memory/child_memory_coordinator_impl.cc b/content/child/memory/child_memory_coordinator_impl.cc
index 8477942..de9f8b8 100644
--- a/content/child/memory/child_memory_coordinator_impl.cc
+++ b/content/child/memory/child_memory_coordinator_impl.cc
@@ -59,10 +59,8 @@
 }
 
 void ChildMemoryCoordinatorImpl::PurgeMemory() {
-  // TODO(bashi): Remove Notify() call when all clients implement
-  // OnPurgeMemory();
-  base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(
-      base::MemoryState::SUSPENDED);
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory-infra"),
+               "ChildMemoryCoordinatorImpl::PurgeMemory");
   base::MemoryCoordinatorClientRegistry::GetInstance()->PurgeMemory();
 }
 
diff --git a/content/child/memory/child_memory_coordinator_impl.h b/content/child/memory/child_memory_coordinator_impl.h
index ccac9b41..04b7576d 100644
--- a/content/child/memory/child_memory_coordinator_impl.h
+++ b/content/child/memory/child_memory_coordinator_impl.h
@@ -35,11 +35,9 @@
                              ChildMemoryCoordinatorDelegate* delegate);
   ~ChildMemoryCoordinatorImpl() override;
 
-  // Requests purging memory to clients.
-  void PurgeMemory();
-
   // mojom::ChildMemoryCoordinator implementations:
   void OnStateChange(mojom::MemoryState state) override;
+  void PurgeMemory() override;
 
  protected:
   ChildMemoryCoordinatorDelegate* delegate() { return delegate_; }
diff --git a/content/child/service_worker/service_worker_dispatcher.cc b/content/child/service_worker/service_worker_dispatcher.cc
index 7c682b0..a3ffdf6 100644
--- a/content/child/service_worker/service_worker_dispatcher.cc
+++ b/content/child/service_worker/service_worker_dispatcher.cc
@@ -113,6 +113,7 @@
                         OnSetControllerServiceWorker)
     IPC_MESSAGE_HANDLER(ServiceWorkerMsg_MessageToDocument,
                         OnPostMessage)
+    IPC_MESSAGE_HANDLER(ServiceWorkerMsg_CountFeature, OnCountFeature)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   DCHECK(handled) << "Unhandled message:" << msg.type();
@@ -820,7 +821,8 @@
     int thread_id,
     int provider_id,
     const ServiceWorkerObjectInfo& info,
-    bool should_notify_controllerchange) {
+    bool should_notify_controllerchange,
+    const std::set<uint32_t>& used_features) {
   TRACE_EVENT2("ServiceWorker",
                "ServiceWorkerDispatcher::OnSetControllerServiceWorker",
                "Thread ID", thread_id,
@@ -830,17 +832,26 @@
   // provider context if it exists.
   std::unique_ptr<ServiceWorkerHandleReference> handle_ref = Adopt(info);
   ProviderContextMap::iterator provider = provider_contexts_.find(provider_id);
-  if (provider != provider_contexts_.end())
-    provider->second->OnSetControllerServiceWorker(std::move(handle_ref));
+  if (provider != provider_contexts_.end()) {
+    provider->second->OnSetControllerServiceWorker(std::move(handle_ref),
+                                                   used_features);
+  }
 
   ProviderClientMap::iterator found = provider_clients_.find(provider_id);
   if (found != provider_clients_.end()) {
+    // Sync the controllee's use counter with the service worker's one.
+    for (uint32_t feature : used_features)
+      found->second->countFeature(feature);
+
     // Get the existing worker object or create a new one with a new reference
     // to populate the .controller field.
     scoped_refptr<WebServiceWorkerImpl> worker = GetOrCreateServiceWorker(
         ServiceWorkerHandleReference::Create(info, thread_safe_sender_.get()));
     found->second->setController(WebServiceWorkerImpl::CreateHandle(worker),
                                  should_notify_controllerchange);
+    // You must not access |found| after setController() because it may fire the
+    // controllerchange event that may remove the provider client, for example,
+    // by detaching an iframe.
   }
 }
 
@@ -875,6 +886,14 @@
       blink::WebString::fromUTF16(params.message), ports);
 }
 
+void ServiceWorkerDispatcher::OnCountFeature(int thread_id,
+                                             int provider_id,
+                                             uint32_t feature) {
+  ProviderClientMap::iterator found = provider_clients_.find(provider_id);
+  if (found != provider_clients_.end())
+    found->second->countFeature(feature);
+}
+
 void ServiceWorkerDispatcher::AddServiceWorker(
     int handle_id, WebServiceWorkerImpl* worker) {
   DCHECK(!base::ContainsKey(service_workers_, handle_id));
diff --git a/content/child/service_worker/service_worker_dispatcher.h b/content/child/service_worker/service_worker_dispatcher.h
index 54cf63be..5c6cabe 100644
--- a/content/child/service_worker/service_worker_dispatcher.h
+++ b/content/child/service_worker/service_worker_dispatcher.h
@@ -9,6 +9,7 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <vector>
 
 #include "base/id_map.h"
@@ -291,8 +292,10 @@
   void OnSetControllerServiceWorker(int thread_id,
                                     int provider_id,
                                     const ServiceWorkerObjectInfo& info,
-                                    bool should_notify_controllerchange);
+                                    bool should_notify_controllerchange,
+                                    const std::set<uint32_t>& used_features);
   void OnPostMessage(const ServiceWorkerMsg_MessageToDocument_Params& params);
+  void OnCountFeature(int thread_id, int provider_id, uint32_t feature);
 
   // Keeps map from handle_id to ServiceWorker object.
   void AddServiceWorker(int handle_id, WebServiceWorkerImpl* worker);
diff --git a/content/child/service_worker/service_worker_dispatcher_unittest.cc b/content/child/service_worker/service_worker_dispatcher_unittest.cc
index 0452229..0f9b789a 100644
--- a/content/child/service_worker/service_worker_dispatcher_unittest.cc
+++ b/content/child/service_worker/service_worker_dispatcher_unittest.cc
@@ -86,9 +86,11 @@
   void OnSetControllerServiceWorker(int thread_id,
                                     int provider_id,
                                     const ServiceWorkerObjectInfo& info,
-                                    bool should_notify_controllerchange) {
+                                    bool should_notify_controllerchange,
+                                    const std::set<uint32_t>& used_features) {
     dispatcher_->OnSetControllerServiceWorker(thread_id, provider_id, info,
-                                              should_notify_controllerchange);
+                                              should_notify_controllerchange,
+                                              used_features);
   }
 
   void OnPostMessage(const ServiceWorkerMsg_MessageToDocument_Params& params) {
@@ -142,6 +144,10 @@
     is_dispatch_message_event_called_ = true;
   }
 
+  void countFeature(uint32_t feature) override {
+    used_features_.insert(feature);
+  }
+
   bool is_set_controlled_called() const { return is_set_controlled_called_; }
 
   bool is_dispatch_message_event_called() const {
@@ -153,6 +159,7 @@
   bool is_set_controlled_called_ = false;
   bool is_dispatch_message_event_called_ = false;
   ServiceWorkerDispatcher* dispatcher_;
+  std::set<uint32_t> used_features_;
 };
 
 TEST_F(ServiceWorkerDispatcherTest, OnAssociateRegistration_NoProviderContext) {
@@ -259,7 +266,8 @@
   // the provider, the passed reference to the active worker should be adopted
   // but immediately released because there is no provider context to own it.
   OnSetControllerServiceWorker(kDocumentMainThreadId, kProviderId, attrs.active,
-                               should_notify_controllerchange);
+                               should_notify_controllerchange,
+                               std::set<uint32_t>());
   ASSERT_EQ(1UL, ipc_sink()->message_count());
   EXPECT_EQ(ServiceWorkerHostMsg_DecrementServiceWorkerRefCount::ID,
             ipc_sink()->GetMessageAt(0)->type());
@@ -275,7 +283,8 @@
   OnAssociateRegistration(kDocumentMainThreadId, kProviderId, info, attrs);
   ipc_sink()->ClearMessages();
   OnSetControllerServiceWorker(kDocumentMainThreadId, kProviderId, attrs.active,
-                               should_notify_controllerchange);
+                               should_notify_controllerchange,
+                               std::set<uint32_t>());
   EXPECT_EQ(0UL, ipc_sink()->message_count());
 
   // Destruction of the provider context should release references to the
@@ -298,7 +307,8 @@
       new MockWebServiceWorkerProviderClientImpl(kProviderId, dispatcher()));
   ASSERT_FALSE(provider_client->is_set_controlled_called());
   OnSetControllerServiceWorker(kDocumentMainThreadId, kProviderId, attrs.active,
-                               should_notify_controllerchange);
+                               should_notify_controllerchange,
+                               std::set<uint32_t>());
   EXPECT_TRUE(provider_client->is_set_controlled_called());
   ASSERT_EQ(3UL, ipc_sink()->message_count());
   EXPECT_EQ(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount::ID,
@@ -323,7 +333,8 @@
   ASSERT_FALSE(provider_client->is_set_controlled_called());
   ipc_sink()->ClearMessages();
   OnSetControllerServiceWorker(kDocumentMainThreadId, kProviderId, attrs.active,
-                               should_notify_controllerchange);
+                               should_notify_controllerchange,
+                               std::set<uint32_t>());
   EXPECT_TRUE(provider_client->is_set_controlled_called());
   ASSERT_EQ(2UL, ipc_sink()->message_count());
   EXPECT_EQ(ServiceWorkerHostMsg_IncrementServiceWorkerRefCount::ID,
@@ -352,9 +363,9 @@
   OnAssociateRegistration(kDocumentMainThreadId, kProviderId, info, attrs);
 
   // Set the controller to kInvalidServiceWorkerHandle.
-  OnSetControllerServiceWorker(kDocumentMainThreadId, kProviderId,
-                               ServiceWorkerObjectInfo(),
-                               should_notify_controllerchange);
+  OnSetControllerServiceWorker(
+      kDocumentMainThreadId, kProviderId, ServiceWorkerObjectInfo(),
+      should_notify_controllerchange, std::set<uint32_t>());
 
   // Check that it became null.
   EXPECT_EQ(nullptr, provider_context->controller());
diff --git a/content/child/service_worker/service_worker_message_filter.cc b/content/child/service_worker/service_worker_message_filter.cc
index d73d4c4..47d7787be 100644
--- a/content/child/service_worker/service_worker_message_filter.cc
+++ b/content/child/service_worker/service_worker_message_filter.cc
@@ -143,7 +143,8 @@
     int thread_id,
     int provider_id,
     const ServiceWorkerObjectInfo& info,
-    bool should_notify_controllerchange) {
+    bool should_notify_controllerchange,
+    const std::set<uint32_t>& used_features) {
   SendServiceWorkerObjectDestroyed(thread_safe_sender(), info.handle_id);
 }
 
diff --git a/content/child/service_worker/service_worker_message_filter.h b/content/child/service_worker/service_worker_message_filter.h
index b9785d5..de0b266 100644
--- a/content/child/service_worker/service_worker_message_filter.h
+++ b/content/child/service_worker/service_worker_message_filter.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
 #define CONTENT_CHILD_SERVICE_WORKER_SERVICE_WORKER_MESSAGE_FILTER_H_
 
+#include <set>
 #include <vector>
 
 #include "base/macros.h"
@@ -61,7 +62,8 @@
       int thread_id,
       int provider_id,
       const ServiceWorkerObjectInfo& info,
-      bool should_notify_controllerchange);
+      bool should_notify_controllerchange,
+      const std::set<uint32_t>& used_features);
   void OnStaleMessageToDocument(
       const ServiceWorkerMsg_MessageToDocument_Params& params);
 
diff --git a/content/child/service_worker/service_worker_provider_context.cc b/content/child/service_worker/service_worker_provider_context.cc
index b0c0e9d..bdb318d 100644
--- a/content/child/service_worker/service_worker_provider_context.cc
+++ b/content/child/service_worker/service_worker_provider_context.cc
@@ -187,9 +187,11 @@
 }
 
 void ServiceWorkerProviderContext::OnSetControllerServiceWorker(
-    std::unique_ptr<ServiceWorkerHandleReference> controller) {
+    std::unique_ptr<ServiceWorkerHandleReference> controller,
+    const std::set<uint32_t>& used_features) {
   DCHECK(main_thread_task_runner_->RunsTasksOnCurrentThread());
   delegate_->SetController(std::move(controller));
+  used_features_ = used_features;
 }
 
 void ServiceWorkerProviderContext::GetAssociatedRegistration(
diff --git a/content/child/service_worker/service_worker_provider_context.h b/content/child/service_worker/service_worker_provider_context.h
index b005e22f..192be96 100644
--- a/content/child/service_worker/service_worker_provider_context.h
+++ b/content/child/service_worker/service_worker_provider_context.h
@@ -58,7 +58,8 @@
       std::unique_ptr<ServiceWorkerHandleReference> active);
   void OnDisassociateRegistration();
   void OnSetControllerServiceWorker(
-      std::unique_ptr<ServiceWorkerHandleReference> controller);
+      std::unique_ptr<ServiceWorkerHandleReference> controller,
+      const std::set<uint32_t>& used_features);
 
   // Called on the worker thread. Used for initializing
   // ServiceWorkerGlobalScope.
@@ -71,6 +72,7 @@
   int provider_id() const { return provider_id_; }
 
   ServiceWorkerHandleReference* controller();
+  const std::set<uint32_t>& used_features() const { return used_features_; }
 
  private:
   friend class base::DeleteHelper<ServiceWorkerProviderContext>;
@@ -91,6 +93,8 @@
 
   std::unique_ptr<Delegate> delegate_;
 
+  std::set<uint32_t> used_features_;
+
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerProviderContext);
 };
 
diff --git a/content/child/service_worker/web_service_worker_provider_impl.cc b/content/child/service_worker/web_service_worker_provider_impl.cc
index e2a2574..22039f2 100644
--- a/content/child/service_worker/web_service_worker_provider_impl.cc
+++ b/content/child/service_worker/web_service_worker_provider_impl.cc
@@ -53,6 +53,10 @@
       GetDispatcher()->GetOrCreateServiceWorker(
           ServiceWorkerHandleReference::Create(context_->controller()->info(),
                                                thread_safe_sender_.get()));
+
+  // Sync the controllee's use counter with the service worker's one.
+  for (uint32_t feature : context_->used_features())
+    client->countFeature(feature);
   client->setController(WebServiceWorkerImpl::CreateHandle(controller),
                         false /* shouldNotifyControllerChange */);
 }
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index cf899ff0..dbc58dc 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -390,7 +390,6 @@
     "//services/video_capture/public/interfaces",
     "//skia",
     "//storage/common",
-    "//third_party/WebKit/public:blink_minimal",
     "//third_party/boringssl",
     "//third_party/icu",
     "//third_party/libjingle",
diff --git a/content/common/child_memory_coordinator.mojom b/content/common/child_memory_coordinator.mojom
index 0a20b7fb..fe2d4f3 100644
--- a/content/common/child_memory_coordinator.mojom
+++ b/content/common/child_memory_coordinator.mojom
@@ -20,4 +20,8 @@
   // Called when the central memory coodinator changes the state for child
   // processes.
   OnStateChange(MemoryState state);
+
+  // Requests the child process to purge memory (e.g. by dropping caches that
+  // can be easily rebuilt).
+  PurgeMemory();
 };
diff --git a/content/common/gpu_host_messages.h b/content/common/gpu_host_messages.h
index d2967df..6eff42066 100644
--- a/content/common/gpu_host_messages.h
+++ b/content/common/gpu_host_messages.h
@@ -55,14 +55,6 @@
   IPC_STRUCT_MEMBER(gpu::SurfaceHandle, surface_handle)
 IPC_STRUCT_END()
 
-IPC_STRUCT_TRAITS_BEGIN(content::EstablishChannelParams)
-  IPC_STRUCT_TRAITS_MEMBER(client_id)
-  IPC_STRUCT_TRAITS_MEMBER(client_tracing_id)
-  IPC_STRUCT_TRAITS_MEMBER(preempts)
-  IPC_STRUCT_TRAITS_MEMBER(allow_view_command_buffers)
-  IPC_STRUCT_TRAITS_MEMBER(allow_real_time_streams)
-IPC_STRUCT_TRAITS_END()
-
 IPC_STRUCT_TRAITS_BEGIN(gpu::GpuPreferences)
   IPC_STRUCT_TRAITS_MEMBER(single_process)
   IPC_STRUCT_TRAITS_MEMBER(in_process_gpu)
@@ -110,15 +102,6 @@
 // Tells the GPU process to shutdown itself.
 IPC_MESSAGE_CONTROL0(GpuMsg_Finalize)
 
-// Tells the GPU process to create a new channel for communication with a
-// given client.  The channel name is returned in a
-// GpuHostMsg_ChannelEstablished message.  The client ID is passed so
-// that the GPU process reuses an existing channel to that process if it exists.
-// This ID is a unique opaque identifier generated by the browser process.
-// The client_tracing_id is a unique ID used for the purposes of tracing.
-IPC_MESSAGE_CONTROL1(GpuMsg_EstablishChannel,
-                     content::EstablishChannelParams /* params */)
-
 // Tells the GPU process to close the channel identified by |client_id|.
 // If no channel can be identified, do nothing.
 IPC_MESSAGE_CONTROL1(GpuMsg_CloseChannel, int32_t /* client_id */)
@@ -175,10 +158,6 @@
                      ::gpu::GPUInfo /* gpu_info */,
                      ::gpu::GpuFeatureInfo /* gpu_feature_info */)
 
-// Response from GPU to a GpuHostMsg_EstablishChannel message.
-IPC_MESSAGE_CONTROL1(GpuHostMsg_ChannelEstablished,
-                     IPC::ChannelHandle /* channel_handle */)
-
 // Message to the GPU that a shader was loaded from disk.
 IPC_MESSAGE_CONTROL1(GpuMsg_LoadedShader, std::string /* encoded shader */)
 
diff --git a/content/common/service_worker/embedded_worker_messages.h b/content/common/service_worker/embedded_worker_messages.h
index 17c594a..8cc8c280 100644
--- a/content/common/service_worker/embedded_worker_messages.h
+++ b/content/common/service_worker/embedded_worker_messages.h
@@ -90,6 +90,12 @@
 IPC_MESSAGE_CONTROL1(EmbeddedWorkerHostMsg_WorkerStopped,
                      int /* embedded_worker_id */)
 
+// Renderer -> Browser message to count an API use. |feature| must be one of the
+// values from blink::UseCounter::Feature enum.
+IPC_MESSAGE_CONTROL2(EmbeddedWorkerHostMsg_CountFeature,
+                     int64_t /* service_worker_version_id */,
+                     uint32_t /* feature */)
+
 // Renderer -> Browser message to report an exception.
 IPC_MESSAGE_CONTROL5(EmbeddedWorkerHostMsg_ReportException,
                      int /* embedded_worker_id */,
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index 77b4f6c..04f8f61 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -472,12 +472,14 @@
                      int /* registration_handle_id */)
 
 // Tells the child process to set the controller ServiceWorker for the given
-// provider.
-IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_SetControllerServiceWorker,
+// provider. |used_features| is the set of features that the worker has used.
+// The values must be from blink::UseCounter::Feature enum.
+IPC_MESSAGE_CONTROL5(ServiceWorkerMsg_SetControllerServiceWorker,
                      int /* thread_id */,
                      int /* provider_id */,
                      content::ServiceWorkerObjectInfo,
-                     bool /* should_notify_controllerchange */)
+                     bool /* should_notify_controllerchange */,
+                     std::set<uint32_t> /* used_features */)
 
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_DidEnableNavigationPreload,
                      int /* thread_id */,
@@ -509,6 +511,14 @@
 IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_MessageToDocument,
                      ServiceWorkerMsg_MessageToDocument_Params)
 
+// Notifies a client that its controller used a feature, for UseCounter
+// purposes (browser->renderer). |feature| must be one of the values from
+// blink::UseCounter::Feature enum.
+IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_CountFeature,
+                     int /* thread_id */,
+                     int /* provider_id */,
+                     uint32_t /* feature */)
+
 // Sent via EmbeddedWorker to dispatch events.
 IPC_MESSAGE_CONTROL1(ServiceWorkerMsg_InstallEvent,
                      int /* request_id */)
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index 44318de6..3f53ad1 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -271,7 +271,6 @@
 
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(GpuChildThread, msg)
-    IPC_MESSAGE_HANDLER(GpuMsg_EstablishChannel, OnEstablishChannel)
     IPC_MESSAGE_HANDLER(GpuMsg_CloseChannel, OnCloseChannel)
     IPC_MESSAGE_HANDLER(GpuMsg_DestroyGpuMemoryBuffer, OnDestroyGpuMemoryBuffer)
     IPC_MESSAGE_HANDLER(GpuMsg_LoadedShader, OnLoadedShader)
@@ -466,17 +465,6 @@
     ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
 }
 
-void GpuChildThread::OnEstablishChannel(const EstablishChannelParams& params) {
-  if (!gpu_channel_manager())
-    return;
-
-  IPC::ChannelHandle channel_handle = gpu_channel_manager()->EstablishChannel(
-      params.client_id, params.client_tracing_id, params.preempts,
-      params.allow_view_command_buffers, params.allow_real_time_streams);
-  gpu_service_->media_gpu_channel_manager()->AddChannel(params.client_id);
-  Send(new GpuHostMsg_ChannelEstablished(channel_handle));
-}
-
 void GpuChildThread::OnCloseChannel(int32_t client_id) {
   if (gpu_channel_manager())
     gpu_channel_manager()->RemoveChannel(client_id);
diff --git a/content/gpu/gpu_child_thread.h b/content/gpu/gpu_child_thread.h
index c8b7724e..f1dc4e92 100644
--- a/content/gpu/gpu_child_thread.h
+++ b/content/gpu/gpu_child_thread.h
@@ -46,7 +46,6 @@
 
 namespace content {
 class GpuServiceFactory;
-struct EstablishChannelParams;
 
 // The main thread of the GPU child process. There will only ever be one of
 // these per process. It does process initialization and shutdown. It forwards
@@ -124,7 +123,6 @@
 #endif
   void OnGpuSwitched();
 
-  void OnEstablishChannel(const EstablishChannelParams& params);
   void OnCloseChannel(int32_t client_id);
   void OnLoadedShader(const std::string& shader);
   void OnDestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
diff --git a/content/ppapi_plugin/OWNERS b/content/ppapi_plugin/OWNERS
index bf182062..aba37b3 100644
--- a/content/ppapi_plugin/OWNERS
+++ b/content/ppapi_plugin/OWNERS
@@ -4,3 +4,5 @@
 # Mac Sandbox profiles.
 per-file *.sb=set noparent
 per-file *.sb=rsesek@chromium.org
+
+# COMPONENT: Internals>Plugins>Pepper
diff --git a/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.java b/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.java
index e6a8443..8831ec63 100644
--- a/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.java
+++ b/content/public/android/java/src/org/chromium/content/app/ChildProcessServiceImpl.java
@@ -87,7 +87,8 @@
 
     private final Semaphore mActivitySemaphore = new Semaphore(1);
 
-    ChildProcessServiceImpl() {
+    @UsedByReflection("WebApkSandboxedProcessService")
+    public ChildProcessServiceImpl() {
         KillChildUncaughtExceptionHandler.maybeInstallHandler();
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
index 1a8996c8..b17d282b5f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
@@ -42,6 +42,10 @@
 
 /**
  * This class provides the method to start/stop ChildProcess called by native.
+ *
+ * Note about threading. The threading here is complicated and not well documented.
+ * Code can run on these threads: UI, Launcher, async thread pool, binder, and one-off
+ * background threads.
  */
 @JNINamespace("content")
 public class ChildProcessLauncher {
@@ -65,7 +69,8 @@
         private final boolean mInSandbox;
         // Each Allocator keeps a queue for the pending spawn data. Once a connection is free, we
         // dequeue the pending spawn data from the same allocator as the connection.
-        private final PendingSpawnQueue mPendingSpawnQueue = new PendingSpawnQueue();
+        // SHOULD BE ACCESSED WITH mConnectionLock.
+        private final Queue<SpawnData> mPendingSpawnQueue = new LinkedList<>();
 
         public ChildConnectionAllocator(boolean inSandbox, int numChildServices,
                 String serviceClassName) {
@@ -78,28 +83,32 @@
             mInSandbox = inSandbox;
         }
 
-        public ChildProcessConnection allocate(
-                Context context, ChildProcessConnection.DeathCallback deathCallback,
-                ChromiumLinkerParams chromiumLinkerParams,
-                boolean alwaysInForeground,
-                ChildProcessCreationParams creationParams) {
+        // Allocate or enqueue. If there are no free slots, return null and enqueue the spawn data.
+        public ChildProcessConnection allocate(SpawnData spawnData,
+                ChildProcessConnection.DeathCallback deathCallback,
+                ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForeground) {
+            assert spawnData.inSandbox() == mInSandbox;
             synchronized (mConnectionLock) {
                 if (mFreeConnectionIndices.isEmpty()) {
                     Log.d(TAG, "Ran out of services to allocate.");
+                    if (!spawnData.forWarmUp()) {
+                        mPendingSpawnQueue.add(spawnData);
+                    }
                     return null;
                 }
                 int slot = mFreeConnectionIndices.remove(0);
                 assert mChildProcessConnections[slot] == null;
-                mChildProcessConnections[slot] = new ChildProcessConnectionImpl(context, slot,
-                        mInSandbox, deathCallback, mChildClassName, chromiumLinkerParams,
-                        alwaysInForeground, creationParams);
+                mChildProcessConnections[slot] = new ChildProcessConnectionImpl(spawnData.context(),
+                        slot, mInSandbox, deathCallback, mChildClassName, chromiumLinkerParams,
+                        alwaysInForeground, spawnData.getCreationParams());
                 Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox,
                         slot);
                 return mChildProcessConnections[slot];
             }
         }
 
-        public void free(ChildProcessConnection connection) {
+        // Also return the first SpawnData in the pending queue, if any.
+        public SpawnData free(ChildProcessConnection connection) {
             synchronized (mConnectionLock) {
                 int slot = connection.getServiceNumber();
                 if (mChildProcessConnections[slot] != connection) {
@@ -115,6 +124,7 @@
                     Log.d(TAG, "Allocator freed a connection, sandbox: %b, slot: %d", mInSandbox,
                             slot);
                 }
+                return mPendingSpawnQueue.poll();
             }
         }
 
@@ -124,10 +134,6 @@
             }
         }
 
-        public PendingSpawnQueue getPendingSpawnQueue() {
-            return mPendingSpawnQueue;
-        }
-
         /** @return the count of connections managed by the allocator */
         @VisibleForTesting
         int allocatedConnectionsCountForTesting() {
@@ -138,9 +144,24 @@
         ChildProcessConnection[] connectionArrayForTesting() {
             return mChildProcessConnections;
         }
+
+        @VisibleForTesting
+        void enqueuePendingQueueForTesting(SpawnData spawnData) {
+            synchronized (mConnectionLock) {
+                mPendingSpawnQueue.add(spawnData);
+            }
+        }
+
+        @VisibleForTesting
+        int pendingSpawnsCountForTesting() {
+            synchronized (mConnectionLock) {
+                return mPendingSpawnQueue.size();
+            }
+        }
     }
 
-    private static class PendingSpawnData {
+    private static class SpawnData {
+        private final boolean mForWarmup; // Do not queue up if failed.
         private final Context mContext;
         private final String[] mCommandLine;
         private final int mChildProcessId;
@@ -150,15 +171,10 @@
         private final boolean mInSandbox;
         private final ChildProcessCreationParams mCreationParams;
 
-        private PendingSpawnData(
-                Context context,
-                String[] commandLine,
-                int childProcessId,
-                FileDescriptorInfo[] filesToBeMapped,
-                long clientContext,
-                int callbackType,
-                boolean inSandbox,
-                ChildProcessCreationParams creationParams) {
+        private SpawnData(boolean forWarmUp, Context context, String[] commandLine,
+                int childProcessId, FileDescriptorInfo[] filesToBeMapped, long clientContext,
+                int callbackType, boolean inSandbox, ChildProcessCreationParams creationParams) {
+            mForWarmup = forWarmUp;
             mContext = context;
             mCommandLine = commandLine;
             mChildProcessId = childProcessId;
@@ -169,6 +185,10 @@
             mCreationParams = creationParams;
         }
 
+        private boolean forWarmUp() {
+            return mForWarmup;
+        }
+
         private Context context() {
             return mContext;
         }
@@ -195,37 +215,6 @@
         }
     }
 
-    private static class PendingSpawnQueue {
-        // The list of pending process spawn requests and its lock.
-        // Operations on this queue must be atomical w.r.t. free connections updates.
-        private Queue<PendingSpawnData> mPendingSpawns = new LinkedList<PendingSpawnData>();
-        final Object mPendingSpawnsLock = new Object();
-
-        /**
-         * Queue up a spawn requests to be processed once a free service is available.
-         * Called when a spawn is requested while we are at the capacity.
-         */
-        public void enqueueLocked(final PendingSpawnData pendingSpawn) {
-            assert Thread.holdsLock(mPendingSpawnsLock);
-            mPendingSpawns.add(pendingSpawn);
-        }
-
-        /**
-         * Pop the next request from the queue. Called when a free service is available.
-         * @return the next spawn request waiting in the queue.
-         */
-        public PendingSpawnData dequeueLocked() {
-            assert Thread.holdsLock(mPendingSpawnsLock);
-            return mPendingSpawns.poll();
-        }
-
-        /** @return the count of pending spawns in the queue */
-        public int sizeLocked() {
-            assert Thread.holdsLock(mPendingSpawnsLock);
-            return mPendingSpawns.size();
-        }
-    }
-
     // Service class for child process.
     // Map from package name to ChildConnectionAllocator.
     private static Map<String, ChildConnectionAllocator> sSandboxedChildConnectionAllocatorMap;
@@ -356,18 +345,14 @@
         return sSandboxedChildConnectionAllocatorMap.get(packageName);
     }
 
-    /**
-     * Get the PendingSpawnQueue of the Allocator. Initialize the Allocator if needed.
-     */
-    private static PendingSpawnQueue getPendingSpawnQueue(Context context, String packageName,
-            boolean inSandbox) {
+    private static ChildConnectionAllocator getAllocatorForTesting(
+            Context context, String packageName, boolean inSandbox) {
         initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
-        return getConnectionAllocator(packageName, inSandbox).getPendingSpawnQueue();
+        return getConnectionAllocator(packageName, inSandbox);
     }
 
-    private static ChildProcessConnection allocateConnection(Context context, boolean inSandbox,
-            ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForeground,
-            ChildProcessCreationParams creationParams) {
+    private static ChildProcessConnection allocateConnection(SpawnData spawnData,
+            ChromiumLinkerParams chromiumLinkerParams, boolean alwaysInForeground) {
         ChildProcessConnection.DeathCallback deathCallback =
                 new ChildProcessConnection.DeathCallback() {
                     @Override
@@ -379,12 +364,14 @@
                         }
                     }
                 };
-        String packageName = creationParams != null ? creationParams.getPackageName()
-                : context.getPackageName();
+        final ChildProcessCreationParams creationParams = spawnData.getCreationParams();
+        final Context context = spawnData.context();
+        final boolean inSandbox = spawnData.inSandbox();
+        String packageName =
+                creationParams != null ? creationParams.getPackageName() : context.getPackageName();
         initConnectionAllocatorsIfNecessary(context, inSandbox, packageName);
         return getConnectionAllocator(packageName, inSandbox)
-                .allocate(context, deathCallback, chromiumLinkerParams, alwaysInForeground,
-                        creationParams);
+                .allocate(spawnData, deathCallback, chromiumLinkerParams, alwaysInForeground);
     }
 
     private static boolean sLinkerInitialized;
@@ -417,20 +404,23 @@
         }
     }
 
-    private static ChildProcessConnection allocateBoundConnection(Context context,
-            String[] commandLine, boolean inSandbox, boolean alwaysInForeground,
-            ChildProcessCreationParams creationParams,
-            ChildProcessConnection.StartCallback startCallback) {
+    private static ChildProcessConnection allocateBoundConnection(SpawnData spawnData,
+            boolean alwaysInForeground, ChildProcessConnection.StartCallback startCallback) {
+        final Context context = spawnData.context();
+        final String[] commandLine = spawnData.commandLine();
+        final boolean inSandbox = spawnData.inSandbox();
+        final ChildProcessCreationParams creationParams = spawnData.getCreationParams();
         ChromiumLinkerParams chromiumLinkerParams = getLinkerParamsForNewConnection();
-        ChildProcessConnection connection = allocateConnection(
-                context, inSandbox, chromiumLinkerParams, alwaysInForeground, creationParams);
+        ChildProcessConnection connection =
+                allocateConnection(spawnData, chromiumLinkerParams, alwaysInForeground);
         if (connection != null) {
             connection.start(commandLine, startCallback);
 
             String packageName = creationParams != null ? creationParams.getPackageName()
-                    : context.getPackageName();
-            if (inSandbox && !getConnectionAllocator(packageName, inSandbox)
-                    .isFreeConnectionAvailable()) {
+                                                        : context.getPackageName();
+            if (inSandbox
+                    && !getConnectionAllocator(packageName, inSandbox)
+                                .isFreeConnectionAvailable()) {
                 // Proactively releases all the moderate bindings once all the sandboxed services
                 // are allocated, which will be very likely to have some of them killed by OOM
                 // killer.
@@ -456,7 +446,7 @@
         ThreadUtils.postOnUiThreadDelayed(new Runnable() {
             @Override
             public void run() {
-                final PendingSpawnData pendingSpawn = freeConnectionAndDequeuePending(conn);
+                final SpawnData pendingSpawn = freeConnectionAndDequeuePending(conn);
                 if (pendingSpawn != null) {
                     new Thread(new Runnable() {
                         @Override
@@ -472,15 +462,11 @@
         }, FREE_CONNECTION_DELAY_MILLIS);
     }
 
-    private static PendingSpawnData freeConnectionAndDequeuePending(ChildProcessConnection conn) {
+    private static SpawnData freeConnectionAndDequeuePending(ChildProcessConnection conn) {
         ChildConnectionAllocator allocator = getConnectionAllocator(
                 conn.getPackageName(), conn.isInSandbox());
         assert allocator != null;
-        PendingSpawnQueue pendingSpawnQueue = allocator.getPendingSpawnQueue();
-        synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
-            allocator.free(conn);
-            return pendingSpawnQueue.dequeueLocked();
-        }
+        return allocator.free(conn);
     }
 
     // Represents an invalid process handle; same as base/process/process.h kNullProcessHandle.
@@ -612,8 +598,12 @@
                                 }
                             }
                         };
-                sSpareSandboxedConnection = allocateBoundConnection(context, null, true, false,
-                        params, startCallback);
+                SpawnData spawnData = new SpawnData(true /* forWarmUp*/, context,
+                        null /* commandLine */, -1 /* child process id */,
+                        null /* filesToBeMapped */, 0 /* clientContext */,
+                        CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, params);
+                sSpareSandboxedConnection = allocateBoundConnection(
+                        spawnData, false /* alwaysInForeground */, startCallback);
             }
         }
     }
@@ -722,8 +712,6 @@
             if (allocatedConnection == null) {
                 boolean alwaysInForeground = false;
                 if (callbackType == CALLBACK_FOR_GPU_PROCESS) alwaysInForeground = true;
-                PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(
-                        context, packageName, inSandbox);
                 ChildProcessConnection.StartCallback startCallback =
                         new ChildProcessConnection.StartCallback() {
                             @Override
@@ -747,17 +735,14 @@
                                 });
                             }
                         };
-                synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
-                    allocatedConnection = allocateBoundConnection(
-                            context, commandLine, inSandbox, alwaysInForeground, creationParams,
-                            startCallback);
-                    if (allocatedConnection == null) {
-                        Log.d(TAG, "Allocation of new service failed. Queuing up pending spawn.");
-                        pendingSpawnQueue.enqueueLocked(new PendingSpawnData(context, commandLine,
-                                childProcessId, filesToBeMapped, clientContext,
-                                callbackType, inSandbox, creationParams));
-                        return null;
-                    }
+
+                SpawnData spawnData = new SpawnData(false /* forWarmUp */, context, commandLine,
+                        childProcessId, filesToBeMapped, clientContext, callbackType, inSandbox,
+                        creationParams);
+                allocatedConnection =
+                        allocateBoundConnection(spawnData, alwaysInForeground, startCallback);
+                if (allocatedConnection == null) {
+                    return null;
                 }
             }
 
@@ -893,14 +878,21 @@
     @VisibleForTesting
     static ChildProcessConnection allocateBoundConnectionForTesting(Context context,
             ChildProcessCreationParams creationParams) {
-        return allocateBoundConnection(context, null, true, false, creationParams, null);
+        return allocateBoundConnection(
+                new SpawnData(false /* forWarmUp */, context, null /* commandLine */,
+                        0 /* childProcessId */, null /* filesToBeMapped */, 0 /* clientContext */,
+                        CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, creationParams),
+                false /* alwaysInForeground */, null);
     }
 
     @VisibleForTesting
     static ChildProcessConnection allocateConnectionForTesting(Context context,
             ChildProcessCreationParams creationParams) {
         return allocateConnection(
-                context, true, getLinkerParamsForNewConnection(), false, creationParams);
+                new SpawnData(false /* forWarmUp */, context, null /* commandLine */,
+                        0 /* childProcessId */, null /* filesToBeMapped */, 0 /* clientContext */,
+                        CALLBACK_FOR_RENDERER_PROCESS, true /* inSandbox */, creationParams),
+                getLinkerParamsForNewConnection(), false);
     }
 
     /**
@@ -911,13 +903,11 @@
             ChildProcessCreationParams creationParams, boolean inSandbox) {
         String packageName = creationParams != null ? creationParams.getPackageName()
                 : context.getPackageName();
-        PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(context,
-                packageName, inSandbox);
-        synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
-            pendingSpawnQueue.enqueueLocked(new PendingSpawnData(context, commandLine, 1,
-                    new FileDescriptorInfo[0], 0, CALLBACK_FOR_RENDERER_PROCESS, true,
-                    creationParams));
-        }
+        ChildConnectionAllocator allocator =
+                getAllocatorForTesting(context, packageName, inSandbox);
+        allocator.enqueuePendingQueueForTesting(new SpawnData(false /* forWarmUp*/, context,
+                commandLine, 1, new FileDescriptorInfo[0], 0, CALLBACK_FOR_RENDERER_PROCESS, true,
+                creationParams));
     }
 
     /**
@@ -935,8 +925,7 @@
      * @return gets the service connection array for a specific package name.
      */
     @VisibleForTesting
-    static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(
-            String packageName) {
+    static ChildProcessConnection[] getSandboxedConnectionArrayForTesting(String packageName) {
         return sSandboxedChildConnectionAllocatorMap.get(packageName).connectionArrayForTesting();
     }
 
@@ -953,12 +942,11 @@
      * @return the count of pending spawns in the queue.
      */
     @VisibleForTesting
-    static int pendingSpawnsCountForTesting(Context context, String packageName,
-            boolean inSandbox) {
-        PendingSpawnQueue pendingSpawnQueue = getPendingSpawnQueue(context, packageName, inSandbox);
-        synchronized (pendingSpawnQueue.mPendingSpawnsLock) {
-            return pendingSpawnQueue.sizeLocked();
-        }
+    static int pendingSpawnsCountForTesting(
+            Context context, String packageName, boolean inSandbox) {
+        ChildConnectionAllocator allocator =
+                getAllocatorForTesting(context, packageName, inSandbox);
+        return allocator.pendingSpawnsCountForTesting();
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java b/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java
index c7d1eff..ec7a125 100644
--- a/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/InterfaceRegistrarImpl.java
@@ -12,8 +12,8 @@
 import org.chromium.content_public.browser.InterfaceRegistrar;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.device.BatteryMonitor;
-import org.chromium.device.VibrationManager;
 import org.chromium.device.battery.BatteryMonitorFactory;
+import org.chromium.device.mojom.VibrationManager;
 import org.chromium.device.nfc.mojom.Nfc;
 import org.chromium.device.vibration.VibrationManagerImpl;
 import org.chromium.mojo.system.impl.CoreImpl;
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index a13caab8..c1dad323 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -81,7 +81,7 @@
           // TODO(beng): figure out how to overlay test interfaces like this.
           "content::mojom::BrowserTarget",
           "device::mojom::VRService",
-          "device::VibrationManager",
+          "device::mojom::VibrationManager",
           "device::mojom::GeolocationService",
           "device::mojom::SensorProvider",
           "device::mojom::WakeLockService",
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 42f2932..f625bd9 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -287,7 +287,7 @@
     const Referrer& referrer,
     const std::string& frame_name,
     WindowOpenDisposition disposition,
-    const blink::WebWindowFeatures& features,
+    const blink::mojom::WindowFeatures& features,
     bool user_gesture,
     bool opener_suppressed,
     ResourceContext* context,
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index cc5f198..4dd626e 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -33,6 +33,7 @@
 #include "storage/browser/fileapi/file_system_context.h"
 #include "storage/browser/quota/quota_manager.h"
 #include "third_party/WebKit/public/platform/WebPageVisibilityState.h"
+#include "third_party/WebKit/public/web/window_features.mojom.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
 
@@ -52,10 +53,6 @@
 class SchedulerWorkerPoolParams;
 }
 
-namespace blink {
-struct WebWindowFeatures;
-}
-
 namespace gfx {
 class ImageSkia;
 }
@@ -512,7 +509,7 @@
       const Referrer& referrer,
       const std::string& frame_name,
       WindowOpenDisposition disposition,
-      const blink::WebWindowFeatures& features,
+      const blink::mojom::WindowFeatures& features,
       bool user_gesture,
       bool opener_suppressed,
       ResourceContext* context,
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index ab84e813..a7d9da6 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -23,7 +23,7 @@
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
 #include "third_party/WebKit/public/web/WebFrameSerializerCacheControlPolicy.h"
-#include "third_party/WebKit/public/web/WebWindowFeatures.h"
+#include "third_party/WebKit/public/web/window_features.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_relative_bounds.h"
 #include "ui/accessibility/ax_tree_update.h"
@@ -252,20 +252,20 @@
   IPC_STRUCT_TRAITS_MEMBER(presentation_receiver)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(blink::WebWindowFeatures)
+IPC_STRUCT_TRAITS_BEGIN(blink::mojom::WindowFeatures)
   IPC_STRUCT_TRAITS_MEMBER(x)
-  IPC_STRUCT_TRAITS_MEMBER(xSet)
+  IPC_STRUCT_TRAITS_MEMBER(has_x)
   IPC_STRUCT_TRAITS_MEMBER(y)
-  IPC_STRUCT_TRAITS_MEMBER(ySet)
+  IPC_STRUCT_TRAITS_MEMBER(has_y)
   IPC_STRUCT_TRAITS_MEMBER(width)
-  IPC_STRUCT_TRAITS_MEMBER(widthSet)
+  IPC_STRUCT_TRAITS_MEMBER(has_width)
   IPC_STRUCT_TRAITS_MEMBER(height)
-  IPC_STRUCT_TRAITS_MEMBER(heightSet)
-  IPC_STRUCT_TRAITS_MEMBER(menuBarVisible)
-  IPC_STRUCT_TRAITS_MEMBER(statusBarVisible)
-  IPC_STRUCT_TRAITS_MEMBER(toolBarVisible)
-  IPC_STRUCT_TRAITS_MEMBER(locationBarVisible)
-  IPC_STRUCT_TRAITS_MEMBER(scrollbarsVisible)
+  IPC_STRUCT_TRAITS_MEMBER(has_height)
+  IPC_STRUCT_TRAITS_MEMBER(menu_bar_visible)
+  IPC_STRUCT_TRAITS_MEMBER(status_bar_visible)
+  IPC_STRUCT_TRAITS_MEMBER(tool_bar_visible)
+  IPC_STRUCT_TRAITS_MEMBER(location_bar_visible)
+  IPC_STRUCT_TRAITS_MEMBER(scrollbars_visible)
   IPC_STRUCT_TRAITS_MEMBER(resizable)
   IPC_STRUCT_TRAITS_MEMBER(fullscreen)
   IPC_STRUCT_TRAITS_MEMBER(dialog)
diff --git a/content/public/renderer/BUILD.gn b/content/public/renderer/BUILD.gn
index ce33d5f66..90f1847c 100644
--- a/content/public/renderer/BUILD.gn
+++ b/content/public/renderer/BUILD.gn
@@ -62,6 +62,8 @@
     "resource_fetcher.h",
     "video_encode_accelerator.cc",
     "video_encode_accelerator.h",
+    "window_features_converter.cc",
+    "window_features_converter.h",
   ]
 
   configs += [ "//content:content_implementation" ]
diff --git a/content/public/renderer/window_features_converter.cc b/content/public/renderer/window_features_converter.cc
new file mode 100644
index 0000000..283e842
--- /dev/null
+++ b/content/public/renderer/window_features_converter.cc
@@ -0,0 +1,53 @@
+// 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 "content/public/renderer/window_features_converter.h"
+
+namespace content {
+
+blink::mojom::WindowFeaturesPtr ConvertWebWindowFeaturesToMojoWindowFeatures(
+    const blink::WebWindowFeatures& web_window_features) {
+  blink::mojom::WindowFeaturesPtr result = blink::mojom::WindowFeatures::New();
+  result->x = web_window_features.x;
+  result->has_x = web_window_features.xSet;
+  result->y = web_window_features.y;
+  result->has_y = web_window_features.ySet;
+  result->width = web_window_features.width;
+  result->has_width = web_window_features.widthSet;
+  result->height = web_window_features.height;
+  result->has_height = web_window_features.heightSet;
+  result->menu_bar_visible = web_window_features.menuBarVisible;
+  result->status_bar_visible = web_window_features.statusBarVisible;
+  result->tool_bar_visible = web_window_features.toolBarVisible;
+  result->location_bar_visible = web_window_features.locationBarVisible;
+  result->scrollbars_visible = web_window_features.scrollbarsVisible;
+  result->resizable = web_window_features.resizable;
+  result->fullscreen = web_window_features.fullscreen;
+  result->dialog = web_window_features.dialog;
+  return result;
+}
+
+blink::WebWindowFeatures ConvertMojoWindowFeaturesToWebWindowFeatures(
+    const blink::mojom::WindowFeatures& window_features) {
+  blink::WebWindowFeatures result;
+  result.x = window_features.x;
+  result.xSet = window_features.has_x;
+  result.y = window_features.y;
+  result.ySet = window_features.has_y;
+  result.width = window_features.width;
+  result.widthSet = window_features.has_width;
+  result.height = window_features.height;
+  result.heightSet = window_features.has_height;
+  result.menuBarVisible = window_features.menu_bar_visible;
+  result.statusBarVisible = window_features.status_bar_visible;
+  result.toolBarVisible = window_features.tool_bar_visible;
+  result.locationBarVisible = window_features.location_bar_visible;
+  result.scrollbarsVisible = window_features.scrollbars_visible;
+  result.resizable = window_features.resizable;
+  result.fullscreen = window_features.fullscreen;
+  result.dialog = window_features.dialog;
+  return result;
+}
+
+}  // namespace content
diff --git a/content/public/renderer/window_features_converter.h b/content/public/renderer/window_features_converter.h
new file mode 100644
index 0000000..45c620b
--- /dev/null
+++ b/content/public/renderer/window_features_converter.h
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_RENDERER_WINDOW_FEATURES_CONVERTER_H_
+#define CONTENT_PUBLIC_RENDERER_WINDOW_FEATURES_CONVERTER_H_
+
+#include "content/common/content_export.h"
+#include "third_party/WebKit/public/web/WebWindowFeatures.h"
+#include "third_party/WebKit/public/web/window_features.mojom.h"
+
+namespace content {
+
+CONTENT_EXPORT blink::mojom::WindowFeaturesPtr
+ConvertWebWindowFeaturesToMojoWindowFeatures(
+    const blink::WebWindowFeatures& web_window_features);
+
+CONTENT_EXPORT blink::WebWindowFeatures
+ConvertMojoWindowFeaturesToWebWindowFeatures(
+    const blink::mojom::WindowFeatures& window_features);
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_RENDERER_WINDOW_FEATURES_CONVERTER_H_
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 648b0c86..38e9043e 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1167,13 +1167,18 @@
 // should probably merge these.
 namespace {
 
-bool ContainsSurfaceId(cc::SurfaceId container_surface_id,
+bool ContainsSurfaceId(const cc::SurfaceId& container_surface_id,
                        RenderWidgetHostViewChildFrame* target_view) {
   if (!container_surface_id.is_valid())
     return false;
-  for (cc::SurfaceId id : GetSurfaceManager()
-                              ->GetSurfaceForId(container_surface_id)
-                              ->active_referenced_surfaces()) {
+
+  cc::Surface* container_surface =
+      GetSurfaceManager()->GetSurfaceForId(container_surface_id);
+  if (!container_surface || !container_surface->active_referenced_surfaces())
+    return false;
+
+  for (const cc::SurfaceId& id :
+       *container_surface->active_referenced_surfaces()) {
     if (id == target_view->SurfaceIdForTesting() ||
         ContainsSurfaceId(id, target_view))
       return true;
diff --git a/content/renderer/android/synchronous_compositor_frame_sink.cc b/content/renderer/android/synchronous_compositor_frame_sink.cc
index 161880d3..580924cc 100644
--- a/content/renderer/android/synchronous_compositor_frame_sink.cc
+++ b/content/renderer/android/synchronous_compositor_frame_sink.cc
@@ -23,8 +23,8 @@
 #include "cc/output/texture_mailbox_deleter.h"
 #include "cc/quads/render_pass.h"
 #include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/display.h"
-#include "cc/surfaces/surface_factory.h"
 #include "cc/surfaces/surface_id_allocator.h"
 #include "cc/surfaces/surface_manager.h"
 #include "content/common/android/sync_compositor_messages.h"
@@ -124,12 +124,6 @@
       frame_swap_message_queue_(frame_swap_message_queue),
       surface_manager_(new cc::SurfaceManager),
       surface_id_allocator_(new cc::SurfaceIdAllocator()),
-      root_factory_(new cc::SurfaceFactory(kRootFrameSinkId,
-                                           surface_manager_.get(),
-                                           this)),
-      child_factory_(new cc::SurfaceFactory(kChildFrameSinkId,
-                                            surface_manager_.get(),
-                                            this)),
       begin_frame_source_(std::move(begin_frame_source)) {
   DCHECK(registry_);
   DCHECK(sender_);
@@ -174,10 +168,12 @@
                  base::Unretained(this)));
   registry_->RegisterCompositorFrameSink(routing_id_, this);
 
-  surface_manager_->RegisterFrameSinkId(kRootFrameSinkId);
-  surface_manager_->RegisterFrameSinkId(kChildFrameSinkId);
-  surface_manager_->RegisterSurfaceFactoryClient(kRootFrameSinkId, this);
-  surface_manager_->RegisterSurfaceFactoryClient(kChildFrameSinkId, this);
+  root_support_.reset(new cc::CompositorFrameSinkSupport(
+      this, surface_manager_.get(), kRootFrameSinkId,
+      true /* submits_to_display_compositor */));
+  child_support_.reset(new cc::CompositorFrameSinkSupport(
+      this, surface_manager_.get(), kChildFrameSinkId,
+      false /* submits_to_display_compositor */));
 
   cc::RendererSettings software_renderer_settings;
 
@@ -207,24 +203,16 @@
   begin_frame_source_ = nullptr;
   registry_->UnregisterCompositorFrameSink(routing_id_, this);
   client_->SetTreeActivationCallback(base::Closure());
-  root_factory_->EvictSurface();
-  child_factory_->EvictSurface();
-  surface_manager_->UnregisterSurfaceFactoryClient(kRootFrameSinkId);
-  surface_manager_->UnregisterSurfaceFactoryClient(kChildFrameSinkId);
-  surface_manager_->InvalidateFrameSinkId(kRootFrameSinkId);
-  surface_manager_->InvalidateFrameSinkId(kChildFrameSinkId);
+  root_support_.reset();
+  child_support_.reset();
   software_output_surface_ = nullptr;
   display_ = nullptr;
-  child_factory_ = nullptr;
-  root_factory_ = nullptr;
   surface_id_allocator_ = nullptr;
   surface_manager_ = nullptr;
   cc::CompositorFrameSink::DetachFromClient();
   CancelFallbackTick();
 }
 
-static void NoOpDrawCallback() {}
-
 void SynchronousCompositorFrameSink::SubmitCompositorFrame(
     cc::CompositorFrame frame) {
   DCHECK(CalledOnValidThread());
@@ -233,7 +221,7 @@
   if (fallback_tick_running_) {
     DCHECK(frame.resource_list.empty());
     cc::ReturnedResourceArray return_resources;
-    ReturnResources(return_resources);
+    ReclaimResources(return_resources);
     did_submit_frame_ = true;
     return;
   }
@@ -297,12 +285,10 @@
         shared_quad_state, gfx::Rect(child_size), gfx::Rect(child_size),
         cc::SurfaceId(kChildFrameSinkId, child_local_surface_id_));
 
-    child_factory_->SubmitCompositorFrame(child_local_surface_id_,
-                                          std::move(frame),
-                                          base::Bind(&NoOpDrawCallback));
-    root_factory_->SubmitCompositorFrame(root_local_surface_id_,
-                                         std::move(embed_frame),
-                                         base::Bind(&NoOpDrawCallback));
+    child_support_->SubmitCompositorFrame(child_local_surface_id_,
+                                          std::move(frame));
+    root_support_->SubmitCompositorFrame(root_local_surface_id_,
+                                         std::move(embed_frame));
     display_->DrawAndSwap();
   } else {
     // For hardware draws we send the whole frame to the client so it can draw
@@ -465,16 +451,17 @@
   return thread_checker_.CalledOnValidThread();
 }
 
-void SynchronousCompositorFrameSink::ReturnResources(
+void SynchronousCompositorFrameSink::DidReceiveCompositorFrameAck() {}
+
+void SynchronousCompositorFrameSink::OnBeginFrame(
+    const cc::BeginFrameArgs& args) {}
+
+void SynchronousCompositorFrameSink::ReclaimResources(
     const cc::ReturnedResourceArray& resources) {
   DCHECK(resources.empty());
   client_->ReclaimResources(resources);
 }
 
-void SynchronousCompositorFrameSink::SetBeginFrameSource(
-    cc::BeginFrameSource* begin_frame_source) {
-  // Software output is synchronous and doesn't use a BeginFrameSource.
-  NOTREACHED();
-}
+void SynchronousCompositorFrameSink::WillDrawSurface() {}
 
 }  // namespace content
diff --git a/content/renderer/android/synchronous_compositor_frame_sink.h b/content/renderer/android/synchronous_compositor_frame_sink.h
index 4cb920a..61906c5 100644
--- a/content/renderer/android/synchronous_compositor_frame_sink.h
+++ b/content/renderer/android/synchronous_compositor_frame_sink.h
@@ -18,17 +18,18 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/compositor_frame_sink.h"
 #include "cc/output/managed_memory_policy.h"
+#include "cc/surfaces/compositor_frame_sink_support_client.h"
 #include "cc/surfaces/display_client.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "ipc/ipc_message.h"
 #include "ui/gfx/transform.h"
 
 class SkCanvas;
 
 namespace cc {
+class BeginFrameSource;
+class CompositorFrameSinkSupport;
 class ContextProvider;
 class Display;
-class SurfaceFactory;
 class SurfaceIdAllocator;
 class SurfaceManager;
 }
@@ -64,7 +65,7 @@
 // to a fixed thread when BindToClient is called.
 class SynchronousCompositorFrameSink
     : NON_EXPORTED_BASE(public cc::CompositorFrameSink),
-      public cc::SurfaceFactoryClient {
+      public cc::CompositorFrameSinkSupportClient {
  public:
   SynchronousCompositorFrameSink(
       scoped_refptr<cc::ContextProvider> context_provider,
@@ -92,9 +93,11 @@
                     const gfx::Transform& transform_for_tile_priority);
   void DemandDrawSw(SkCanvas* canvas);
 
-  // SurfaceFactoryClient implementation.
-  void ReturnResources(const cc::ReturnedResourceArray& resources) override;
-  void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source) override;
+  // CompositorFrameSinkSupportClient implementation.
+  void DidReceiveCompositorFrameAck() override;
+  void OnBeginFrame(const cc::BeginFrameArgs& args) override;
+  void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+  void WillDrawSurface() override;
 
  private:
   class SoftwareOutputSurface;
@@ -149,8 +152,9 @@
   cc::LocalSurfaceId child_local_surface_id_;
   cc::LocalSurfaceId root_local_surface_id_;
   // Uses surface_manager_.
-  std::unique_ptr<cc::SurfaceFactory> root_factory_;
-  std::unique_ptr<cc::SurfaceFactory> child_factory_;
+  std::unique_ptr<cc::CompositorFrameSinkSupport> root_support_;
+  // Uses surface_manager_.
+  std::unique_ptr<cc::CompositorFrameSinkSupport> child_support_;
   StubDisplayClient display_client_;
   // Uses surface_manager_.
   std::unique_ptr<cc::Display> display_;
diff --git a/content/renderer/pepper/pepper_media_stream_video_track_host.cc b/content/renderer/pepper/pepper_media_stream_video_track_host.cc
index f536ef3..bbded169a 100644
--- a/content/renderer/pepper/pepper_media_stream_video_track_host.cc
+++ b/content/renderer/pepper/pepper_media_stream_video_track_host.cc
@@ -15,7 +15,6 @@
 #include "content/renderer/media/media_stream_video_track.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/video_util.h"
-#include "media/base/yuv_convert.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/ppb_media_stream_video_track.h"
 #include "ppapi/c/ppb_video_frame.h"
@@ -110,20 +109,17 @@
                          dst_size.width(),
                          dst_size.height());
     } else {
-      media::ScaleYUVToRGB32(src->visible_data(VideoFrame::kYPlane),
-                             src->visible_data(VideoFrame::kUPlane),
-                             src->visible_data(VideoFrame::kVPlane),
-                             dst,
-                             src->visible_rect().width(),
-                             src->visible_rect().height(),
-                             dst_size.width(),
-                             dst_size.height(),
-                             src->stride(VideoFrame::kYPlane),
-                             src->stride(VideoFrame::kUPlane),
-                             dst_size.width() * 4,
-                             media::YV12,
-                             media::ROTATE_0,
-                             media::FILTER_BILINEAR);
+      libyuv::YUVToARGBScaleClip(
+          src->visible_data(VideoFrame::kYPlane),
+          src->stride(VideoFrame::kYPlane),
+          src->visible_data(VideoFrame::kUPlane),
+          src->stride(VideoFrame::kUPlane),
+          src->visible_data(VideoFrame::kVPlane),
+          src->stride(VideoFrame::kVPlane), libyuv::FOURCC_YV12,
+          src->visible_rect().width(), src->visible_rect().height(), dst,
+          dst_size.width() * 4, libyuv::FOURCC_ARGB, dst_size.width(),
+          dst_size.height(), 0, 0, dst_size.width(), dst_size.height(),
+          kFilterMode);
     }
   } else if (dst_format == PP_VIDEOFRAME_FORMAT_YV12 ||
              dst_format == PP_VIDEOFRAME_FORMAT_I420) {
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 8867e039..9675f6cba 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -429,6 +429,7 @@
   volatile void* ptr = nullptr;
   do {
     ptr = malloc(0x10000000);
+    base::debug::Alias(&ptr);
   } while (ptr);
 }
 
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index d4ca564..9ee6916b 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -71,6 +71,7 @@
 #include "content/public/renderer/navigation_state.h"
 #include "content/public/renderer/render_view_observer.h"
 #include "content/public/renderer/render_view_visitor.h"
+#include "content/public/renderer/window_features_converter.h"
 #include "content/renderer/browser_plugin/browser_plugin.h"
 #include "content/renderer/browser_plugin/browser_plugin_manager.h"
 #include "content/renderer/dom_storage/webstoragenamespace_impl.h"
@@ -1452,7 +1453,7 @@
     params->target_url = request.url();
     params->referrer = GetReferrerFromRequest(creator, request);
   }
-  params->features = features;
+  params->features = ConvertWebWindowFeaturesToMojoWindowFeatures(features);
 
   // We preserve this information before sending the message since |params| is
   // moved on send.
diff --git a/content/renderer/renderer_main_platform_delegate_android.cc b/content/renderer/renderer_main_platform_delegate_android.cc
index b41da3c2..5341528f 100644
--- a/content/renderer/renderer_main_platform_delegate_android.cc
+++ b/content/renderer/renderer_main_platform_delegate_android.cc
@@ -4,6 +4,8 @@
 
 #include "content/renderer/renderer_main_platform_delegate.h"
 
+#include <signal.h>
+
 #include "base/android/build_info.h"
 #include "base/feature_list.h"
 #include "base/logging.h"
@@ -111,6 +113,14 @@
   if (base::FeatureList::IsEnabled(features::kSeccompSandboxAndroid)) {
     status_uma.set_status(RecordSeccompStatus::FEATURE_ENABLED);
 
+    // TODO(rsesek): When "the thing after N" has an sdk_int(), restrict this to
+    // that platform version or higher.
+    sig_t old_handler = signal(SIGSYS, SIG_DFL);
+    if (old_handler != SIG_DFL) {
+      DLOG(WARNING) << "Un-hooking existing SIGSYS handler before "
+                    << "starting Seccomp sandbox";
+    }
+
     sandbox::SandboxBPF sandbox(new SandboxBPFBasePolicyAndroid());
     CHECK(sandbox.StartSandbox(
         sandbox::SandboxBPF::SeccompLevel::MULTI_THREADED));
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 6708357..b05b622 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -623,6 +623,11 @@
                  embedded_worker_id_));
 }
 
+void ServiceWorkerContextClient::countFeature(uint32_t feature) {
+  Send(new EmbeddedWorkerHostMsg_CountFeature(service_worker_version_id_,
+                                              feature));
+}
+
 void ServiceWorkerContextClient::reportException(
     const blink::WebString& error_message,
     int line_number,
@@ -655,6 +660,9 @@
     int call_id,
     const blink::WebString& message,
     const blink::WebString& state_cookie) {
+  // Return if this context has been stopped.
+  if (!embedded_worker_client_)
+    return;
   embedded_worker_client_->devtools_agent()->SendMessage(
       sender_.get(), session_id, call_id, message.utf8(), state_cookie.utf8());
 }
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index b410f0e93..22640bba 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -123,6 +123,7 @@
   void didInitializeWorkerContext(v8::Local<v8::Context> context) override;
   void willDestroyWorkerContext(v8::Local<v8::Context> context) override;
   void workerContextDestroyed() override;
+  void countFeature(uint32_t feature) override;
   void reportException(const blink::WebString& error_message,
                        int line_number,
                        int column_number,
@@ -303,7 +304,8 @@
   // This is bound on the worker thread.
   mojom::ServiceWorkerEventDispatcherRequest pending_dispatcher_request_;
 
-  // Renderer-side object corresponding to WebEmbeddedWorkerInstance
+  // Renderer-side object corresponding to WebEmbeddedWorkerInstance.
+  // This is valid from the ctor to workerContextDestroyed.
   std::unique_ptr<EmbeddedWorkerInstanceClientImpl> embedded_worker_client_;
 
   // Initialized on the worker thread in workerContextStarted and
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index 3fe409fdd..45664e8 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -319,12 +319,17 @@
 }
 
 bool SurfaceHitTestReadyNotifier::ContainsSurfaceId(
-    cc::SurfaceId container_surface_id) {
+    const cc::SurfaceId& container_surface_id) {
   if (!container_surface_id.is_valid())
     return false;
-  for (cc::SurfaceId id :
-       surface_manager_->GetSurfaceForId(container_surface_id)
-           ->active_referenced_surfaces()) {
+
+  cc::Surface* container_surface =
+      surface_manager_->GetSurfaceForId(container_surface_id);
+  if (!container_surface || !container_surface->active_referenced_surfaces())
+    return false;
+
+  for (const cc::SurfaceId& id :
+       *container_surface->active_referenced_surfaces()) {
     if (id == target_view_->SurfaceIdForTesting() || ContainsSurfaceId(id))
       return true;
   }
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index bdcbb8d..2d0afd5 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -130,7 +130,7 @@
   void WaitForSurfaceReady();
 
  private:
-  bool ContainsSurfaceId(cc::SurfaceId container_surface_id);
+  bool ContainsSurfaceId(const cc::SurfaceId& container_surface_id);
 
   cc::SurfaceManager* surface_manager_;
   cc::SurfaceId root_surface_id_;
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index 0ad1f3e..2bc0e42 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -1258,6 +1258,19 @@
     ],
     'test': 'gles2_conform_test',
   },
+  'service_unittests': {
+    'tester_configs': [
+      {
+        # Run this on the FYI waterfall and optional tryservers.
+        'predicate': Predicates.FYI_AND_OPTIONAL,
+        'os_types': ['mac'],
+      },
+    ],
+    'args': [
+      '--gtest_filter=*Detection*',
+      '--use-gpu-in-tests'
+    ]
+  },
   'swiftshader_unittests': {
     'tester_configs': [
       {
diff --git a/device/base/BUILD.gn b/device/base/BUILD.gn
index 6240ae9..60fd3442 100644
--- a/device/base/BUILD.gn
+++ b/device/base/BUILD.gn
@@ -14,6 +14,8 @@
     "device_info_query_win.h",
     "device_monitor_win.cc",
     "device_monitor_win.h",
+    "features.cc",
+    "features.h",
   ]
 
   defines = [ "DEVICE_BASE_IMPLEMENTATION" ]
diff --git a/device/base/features.cc b/device/base/features.cc
new file mode 100644
index 0000000..822c0da
--- /dev/null
+++ b/device/base/features.cc
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/base/features.h"
+
+#include "build/build_config.h"
+
+namespace device {
+
+#if defined(OS_WIN)
+const base::Feature kNewUsbBackend{"NewUsbBackend",
+                                   base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // defined(OS_WIN)
+
+}  // namespace device
diff --git a/device/base/features.h b/device/base/features.h
new file mode 100644
index 0000000..efb9979
--- /dev/null
+++ b/device/base/features.h
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_BASE_FEATURES_H_
+#define DEVICE_BASE_FEATURES_H_
+
+#include "base/feature_list.h"
+#include "build/build_config.h"
+#include "device/base/device_base_export.h"
+
+namespace device {
+
+#if defined(OS_WIN)
+DEVICE_BASE_EXPORT extern const base::Feature kNewUsbBackend;
+#endif  // defined(OS_WIN)
+
+}  // namespace device
+
+#endif  // DEVICE_BASE_FEATURES_H_
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
index 3a8abb33b..9443ba9 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
@@ -278,15 +278,14 @@
 // rid of the entire check, and run SubscribeToNotifications on all
 // platforms.
 //
-// TODO(http://crbug.com/633191): Remove OS_MACOSX from this check.
 // TODO(http://crbug.com/636270): Remove OS_WIN from this check.
-#if defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_WIN)
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
                  GetWeakPtr(), session, callback,
                  BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED));
-#else   // !(defined(OS_MACOSX) || defined(OS_WIN))
+#else   // defined(OS_WIN))
   // Find the Client Characteristic Configuration descriptor.
   std::vector<BluetoothRemoteGattDescriptor*> ccc_descriptor =
       GetDescriptorsByUUID(BluetoothRemoteGattDescriptor::
@@ -309,7 +308,7 @@
                  GetWeakPtr(), session, callback),
       base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
                  GetWeakPtr(), session, callback));
-#endif  // defined(OS_MACOSX) || defined(OS_WIN)
+#endif  // defined(OS_WIN)
 }
 
 void BluetoothRemoteGattCharacteristic::CancelStopNotifySession(
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
index 01aed06..b0f8d69 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
@@ -122,10 +122,13 @@
   std::pair<ValueCallback, ErrorCallback> read_characteristic_value_callbacks_;
   // WriteRemoteCharacteristic request callbacks.
   std::pair<base::Closure, ErrorCallback> write_characteristic_value_callbacks_;
-  // Stores SubscribeToNotifications request callbacks.
+  // Stores callbacks for SubscribeToNotifications and
+  // UnsubscribeFromNotifications requests.
   typedef std::pair<base::Closure, ErrorCallback> PendingNotifyCallbacks;
   // Stores SubscribeToNotifications request callbacks.
   PendingNotifyCallbacks subscribe_to_notification_callbacks_;
+  // Stores UnsubscribeFromNotifications request callbacks.
+  PendingNotifyCallbacks unsubscribe_from_notification_callbacks_;
   // Map of descriptors, keyed by descriptor identifier.
   std::unordered_map<std::string,
                      std::unique_ptr<BluetoothRemoteGattDescriptorMac>>
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
index 92d7847c..ae721181 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
@@ -212,6 +212,8 @@
     const ErrorCallback& error_callback) {
   DCHECK(subscribe_to_notification_callbacks_.first.is_null());
   DCHECK(subscribe_to_notification_callbacks_.second.is_null());
+  DCHECK(unsubscribe_from_notification_callbacks_.first.is_null());
+  DCHECK(unsubscribe_from_notification_callbacks_.second.is_null());
   subscribe_to_notification_callbacks_ =
       std::make_pair(callback, error_callback);
   [GetCBPeripheral() setNotifyValue:YES
@@ -222,8 +224,14 @@
     BluetoothRemoteGattDescriptor* ccc_descriptor,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
-  // TODO(http://crbug.com/633191): Implement this method
-  NOTIMPLEMENTED();
+  DCHECK(subscribe_to_notification_callbacks_.first.is_null());
+  DCHECK(subscribe_to_notification_callbacks_.second.is_null());
+  DCHECK(unsubscribe_from_notification_callbacks_.first.is_null());
+  DCHECK(unsubscribe_from_notification_callbacks_.second.is_null());
+  unsubscribe_from_notification_callbacks_ =
+      std::make_pair(callback, error_callback);
+  [GetCBPeripheral() setNotifyValue:NO
+                  forCharacteristic:cb_characteristic_.get()];
 }
 
 void BluetoothRemoteGattCharacteristicMac::DiscoverDescriptors() {
@@ -295,7 +303,17 @@
 void BluetoothRemoteGattCharacteristicMac::DidUpdateNotificationState(
     NSError* error) {
   PendingNotifyCallbacks reentrant_safe_callbacks;
-  reentrant_safe_callbacks.swap(subscribe_to_notification_callbacks_);
+  if (!subscribe_to_notification_callbacks_.first.is_null()) {
+    DCHECK([GetCBCharacteristic() isNotifying] || error);
+    reentrant_safe_callbacks.swap(subscribe_to_notification_callbacks_);
+  } else if (!unsubscribe_from_notification_callbacks_.first.is_null()) {
+    DCHECK(![GetCBCharacteristic() isNotifying] || error);
+    reentrant_safe_callbacks.swap(unsubscribe_from_notification_callbacks_);
+  } else {
+    VLOG(1) << "No pending notification update for characteristic "
+            << GetUUID().value();
+    return;
+  }
   if (error) {
     VLOG(1) << "Bluetooth error while modifying notification state for "
                "characteristic, domain: "
@@ -304,14 +322,10 @@
             << base::SysNSStringToUTF8(error.localizedDescription);
     BluetoothGattService::GattErrorCode error_code =
         BluetoothDeviceMac::GetGattErrorCodeFromNSError(error);
-    if (!reentrant_safe_callbacks.second.is_null()) {
-      reentrant_safe_callbacks.second.Run(error_code);
-    }
+    reentrant_safe_callbacks.second.Run(error_code);
     return;
   }
-  if (!reentrant_safe_callbacks.first.is_null()) {
-    reentrant_safe_callbacks.first.Run();
-  }
+  reentrant_safe_callbacks.first.Run();
 }
 
 void BluetoothRemoteGattCharacteristicMac::DidDiscoverDescriptors() {
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
index a0ee705..52fabd3 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
@@ -132,6 +132,9 @@
     uint8_t expected_byte1 = (expected_config_descriptor_value >> 8) & 0xFF;
     EXPECT_EQ(expected_byte0, last_write_value_[0]);
     EXPECT_EQ(expected_byte1, last_write_value_[1]);
+#else
+    EXPECT_EQ(1, gatt_notify_characteristic_attempts_);
+    EXPECT_TRUE(last_notify_value);
 #endif  // !defined(OS_MACOSX)
   }
 
@@ -1010,12 +1013,15 @@
 }
 #endif  // defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
 
-#if defined(OS_ANDROID) || defined(OS_WIN)
+#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
 // StartNotifySession fails if the characteristic is missing the Client
 // Characteristic Configuration descriptor.
-// macOS: TODO(crbug.com/624017) Need to implement CCC descriptors.
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StartNotifySession_NoConfigDescriptor) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1,
@@ -1030,14 +1036,17 @@
   EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_NOT_SUPPORTED,
             last_gatt_error_code_);
 }
-#endif  // defined(OS_ANDROID) || defined(OS_WIN)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
 
-#if defined(OS_ANDROID) || defined(OS_WIN)
+#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
 // StartNotifySession fails if the characteristic has multiple Client
 // Characteristic Configuration descriptors.
-// macOS: TODO(crbug.com/624017) Need to implement CCC descriptors.
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StartNotifySession_MultipleConfigDescriptor) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1,
@@ -1052,7 +1061,7 @@
   EXPECT_EQ(BluetoothRemoteGattService::GATT_ERROR_FAILED,
             last_gatt_error_code_);
 }
-#endif  // defined(OS_ANDROID) || defined(OS_WIN)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
 
 #if defined(OS_ANDROID)
 // StartNotifySession fails synchronously when failing to set a characteristic
@@ -1155,10 +1164,7 @@
       characteristic1_,
       BluetoothRemoteGattDescriptor::ClientCharacteristicConfigurationUuid()
           .canonical_value());
-#if !defined(OS_MACOSX)
-  // TODO(crbug.com/624017): Need implementation for descriptors.
   ASSERT_EQ(1u, characteristic1_->GetDescriptors().size());
-#endif  // !defined(OS_MACOSX)
 
   characteristic1_->StartNotifySession(
       GetNotifyCallback(Call::EXPECTED),
@@ -1198,10 +1204,7 @@
       characteristic1_,
       BluetoothRemoteGattDescriptor::ClientCharacteristicConfigurationUuid()
           .canonical_value());
-#if !defined(OS_MACOSX)
-  // TODO(crbug.com/624017): Need implementation for descriptors.
   ASSERT_EQ(1u, characteristic1_->GetDescriptors().size());
-#endif  // !defined(OS_MACOSX)
 
   characteristic1_->StartNotifySession(GetNotifyCallback(Call::NOT_EXPECTED),
                                        GetGattErrorCallback(Call::EXPECTED));
@@ -1251,10 +1254,14 @@
 }
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests StartNotifySession completing before chrome objects are deleted.
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StartNotifySession_BeforeDeleted) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(
       FakeCharacteristicBoilerplate(/* properties: NOTIFY */ 0x10));
   SimulateGattDescriptor(
@@ -1288,7 +1295,7 @@
             notify_sessions_[0]->GetCharacteristicIdentifier());
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
 #if defined(OS_MACOSX) || defined(OS_WIN)
 // Tests StartNotifySession reentrant in start notify session success callback
@@ -1304,10 +1311,7 @@
   SimulateGattDescriptor(
       characteristic1_,
       BluetoothGattDescriptor::ClientCharacteristicConfigurationUuid().value());
-#if !defined(OS_MACOSX)
-  // TODO(crbug.com/624017): Need implementation for descriptors.
   ASSERT_EQ(1u, characteristic1_->GetDescriptors().size());
-#endif  // !defined(OS_MACOSX)
 
   characteristic1_->StartNotifySession(
       GetReentrantStartNotifySessionSuccessCallback(Call::EXPECTED,
@@ -1408,70 +1412,111 @@
 }
 #endif  // defined(OS_WIN)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests StopNotifySession success on a characteristic that enabled Notify.
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1));
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+#else
+  EXPECT_EQ(1, gatt_notify_characteristic_attempts_);
+  EXPECT_TRUE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   notify_sessions_[0]->Stop(GetStopNotifyCallback(Call::EXPECTED));
   SimulateGattNotifySessionStopped(characteristic1_);
   base::RunLoop().RunUntilIdle();
 
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   // Check that the right values were written to the descriptor.
   EXPECT_EQ(2, gatt_write_descriptor_attempts_);
   ASSERT_EQ(2u, last_write_value_.size());
   EXPECT_EQ(0, last_write_value_[0]);
   EXPECT_EQ(0, last_write_value_[1]);
+#else
+  EXPECT_EQ(2, gatt_notify_characteristic_attempts_);
+  EXPECT_FALSE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   // Check that the notify session is inactive.
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests that deleted sessions are stopped.
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StopNotifySession_SessionDeleted) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1));
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+#else
+  EXPECT_EQ(1, gatt_notify_characteristic_attempts_);
+  EXPECT_TRUE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   notify_sessions_.clear();
   SimulateGattNotifySessionStopped(characteristic1_);
   base::RunLoop().RunUntilIdle();
 
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   // Check that the right values were written to the descriptor.
   EXPECT_EQ(2, gatt_write_descriptor_attempts_);
   ASSERT_EQ(2u, last_write_value_.size());
   EXPECT_EQ(0, last_write_value_[0]);
   EXPECT_EQ(0, last_write_value_[1]);
+#else
+  EXPECT_EQ(2, gatt_notify_characteristic_attempts_);
+  EXPECT_FALSE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   // Check that the notify session is inactive.
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests that deleting the sessions before the stop callbacks have been
 // invoked does not cause problems.
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StopNotifySession_SessionDeleted2) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(
       FakeCharacteristicBoilerplate(/* properties: NOTIFY */ 0x10));
 
-#if !defined(OS_MACOSX)
-  // TODO(624017) enable for macosx
   SimulateGattDescriptor(
       characteristic1_,
       BluetoothRemoteGattDescriptor::ClientCharacteristicConfigurationUuid()
           .canonical_value());
   ASSERT_EQ(1u, characteristic1_->GetDescriptors().size());
-#endif
 
   // Start notify sessions.
   characteristic1_->StartNotifySession(
@@ -1511,15 +1556,17 @@
   EXPECT_TRUE("Did not crash!");
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests that cancelling StopNotifySession works.
-// TODO(crbug.com/633191): Enable on macOS when SubscribeToNotifications is
-// implemented.
 // TODO(crbug.com/636270): Enable on Windows when SubscribeToNotifications is
 // implemented.
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession_Cancelled) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1));
@@ -1537,11 +1584,15 @@
   // Cancel Stop by deleting the device before Stop finishes.
   DeleteDevice(device_);  // TODO(576906) delete only the characteristic.
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests that deleted sessions are stopped.
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession_AfterDeleted) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1));
@@ -1571,61 +1622,105 @@
             notify_sessions_[0]->GetCharacteristicIdentifier());
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests StopNotifySession success on a characteristic that enabled Indicate.
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession_OnIndicate) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: INDICATE */ 0x20,
       /* expected_config_descriptor_value: INDICATE */ 2));
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+#else
+  EXPECT_EQ(1, gatt_notify_characteristic_attempts_);
+  EXPECT_TRUE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   notify_sessions_[0]->Stop(GetStopNotifyCallback(Call::EXPECTED));
   SimulateGattNotifySessionStopped(characteristic1_);
   base::RunLoop().RunUntilIdle();
 
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   // Check that the right values were written to the descriptor.
   EXPECT_EQ(2, gatt_write_descriptor_attempts_);
   ASSERT_EQ(2u, last_write_value_.size());
   EXPECT_EQ(0, last_write_value_[0]);
   EXPECT_EQ(0, last_write_value_[1]);
+#else
+  EXPECT_EQ(2, gatt_notify_characteristic_attempts_);
+  EXPECT_FALSE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   // Check that the notify session is inactive.
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests StopNotifySession success on a characteristic that enabled Notify &
 // Indicate.
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StopNotifySession_OnNotifyAndIndicate) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY and INDICATE bits set */ 0x30,
       /* expected_config_descriptor_value: INDICATE */ 1));
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+#else
+  EXPECT_EQ(1, gatt_notify_characteristic_attempts_);
+  EXPECT_TRUE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   notify_sessions_[0]->Stop(GetStopNotifyCallback(Call::EXPECTED));
   SimulateGattNotifySessionStopped(characteristic1_);
   base::RunLoop().RunUntilIdle();
 
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   // Check that the right values were written to the descriptor.
   EXPECT_EQ(2, gatt_write_descriptor_attempts_);
   ASSERT_EQ(2u, last_write_value_.size());
   EXPECT_EQ(0, last_write_value_[0]);
   EXPECT_EQ(0, last_write_value_[1]);
+#else
+  EXPECT_EQ(2, gatt_notify_characteristic_attempts_);
+  EXPECT_FALSE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   // Check that the notify session is inactive.
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests StopNotifySession error
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession_Error) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1));
@@ -1646,22 +1741,23 @@
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests multiple StopNotifySession calls for a single session.
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession_Multiple1) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(
       FakeCharacteristicBoilerplate(/* properties: NOTIFY */ 0x10));
 
-#if !defined(OS_MACOSX)
-  // TODO(624017) enable for macosx
   SimulateGattDescriptor(
       characteristic1_,
       BluetoothRemoteGattDescriptor::ClientCharacteristicConfigurationUuid()
           .canonical_value());
   ASSERT_EQ(1u, characteristic1_->GetDescriptors().size());
-#endif
 
   // Start notify session
   characteristic1_->StartNotifySession(
@@ -1690,22 +1786,23 @@
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests multiple StartNotifySession calls and multiple StopNotifySession calls.
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession_Multiple2) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(
       FakeCharacteristicBoilerplate(/* properties: NOTIFY */ 0x10));
 
-#if !defined(OS_MACOSX)
-  // TODO(624017) enable for macosx
   SimulateGattDescriptor(
       characteristic1_,
       BluetoothRemoteGattDescriptor::ClientCharacteristicConfigurationUuid()
           .canonical_value());
   ASSERT_EQ(1u, characteristic1_->GetDescriptors().size());
-#endif
 
   // Start notify sessions
   characteristic1_->StartNotifySession(
@@ -1745,12 +1842,16 @@
   EXPECT_FALSE(notify_sessions_[1]->IsActive());
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests starting a new notify session before the previous stop request
 // resolves.
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession_StopStart) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(
       FakeCharacteristicBoilerplate(/* properties: NOTIFY */ 0x10));
   SimulateGattDescriptor(
@@ -1791,11 +1892,15 @@
   EXPECT_TRUE(notify_sessions_[1]->IsActive());
   EXPECT_TRUE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StopNotifySession_StartStopStart) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1));
@@ -1843,12 +1948,16 @@
 
   EXPECT_TRUE(characteristic1_->IsNotifying());
 }
-#endif
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 // Tests starting a new notify session before the previous stop requests
 // resolve.
 TEST_F(BluetoothRemoteGattCharacteristicTest, StopNotifySession_StopStopStart) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(
       FakeCharacteristicBoilerplate(/* properties: NOTIFY */ 0x10));
   SimulateGattDescriptor(
@@ -1867,25 +1976,48 @@
   ASSERT_EQ(1u, notify_sessions_.size());
   ASSERT_TRUE(notify_sessions_[0]);
   EXPECT_TRUE(notify_sessions_[0]->IsActive());
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   EXPECT_EQ(1, gatt_write_descriptor_attempts_);
+#else
+  EXPECT_EQ(1, gatt_notify_characteristic_attempts_);
+  EXPECT_TRUE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   // Stop the notify session twice
   notify_sessions_[0]->Stop(GetStopNotifyCheckForPrecedingCalls(1));
   notify_sessions_[0]->Stop(GetStopNotifyCheckForPrecedingCalls(2));
 
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   // Check that the right values were written to the descriptor.
   EXPECT_EQ(2, gatt_write_descriptor_attempts_);
   ASSERT_EQ(2u, last_write_value_.size());
   EXPECT_EQ(0, last_write_value_[0]);
   EXPECT_EQ(0, last_write_value_[1]);
+#else
+  EXPECT_EQ(2, gatt_notify_characteristic_attempts_);
+  EXPECT_FALSE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   // Start another notify session
   characteristic1_->StartNotifySession(
       GetNotifyCheckForPrecedingCalls(3),
       GetGattErrorCallback(Call::NOT_EXPECTED));
 
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   // Check that nothing was written by the StartNotifySession call above
   EXPECT_EQ(2, gatt_write_descriptor_attempts_);
+#else
+  EXPECT_EQ(2, gatt_notify_characteristic_attempts_);
+#endif  // !defined(OS_MACOSX)
 
   SimulateGattNotifySessionStopped(characteristic1_);
   base::RunLoop().RunUntilIdle();
@@ -1894,11 +2026,19 @@
   SimulateGattNotifySessionStarted(characteristic1_);
   base::RunLoop().RunUntilIdle();
 
+// macOS: Not applicable. CoreBluetooth exposes -[CBPeripheral
+// setNotifyValue:forCharacteristic:] which handles all interactions with
+// the CCC descriptor.
+#if !defined(OS_MACOSX)
   // Check that the right values were written to the descriptor.
   EXPECT_EQ(3, gatt_write_descriptor_attempts_);
   ASSERT_EQ(2u, last_write_value_.size());
   EXPECT_EQ(1, last_write_value_[0]);
   EXPECT_EQ(0, last_write_value_[1]);
+#else
+  EXPECT_EQ(3, gatt_notify_characteristic_attempts_);
+  EXPECT_TRUE(last_notify_value);
+#endif  // !defined(OS_MACOSX)
 
   // Check the notify state
   ASSERT_EQ(2u, notify_sessions_.size());
@@ -1908,11 +2048,15 @@
   EXPECT_TRUE(notify_sessions_[1]->IsActive());
   EXPECT_TRUE(characteristic1_->IsNotifying());
 }
-#endif  // defined(OS_ANDROID)
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StopNotifySession_Reentrant_Success_Stop) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(
       FakeCharacteristicBoilerplate(/* properties: NOTIFY */ 0x10));
   SimulateGattDescriptor(
@@ -1948,11 +2092,15 @@
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StopNotifySession_Reentrant_Stop_StartSuccess) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1));
@@ -1990,11 +2138,15 @@
   EXPECT_TRUE(notify_sessions_[1]->IsActive());
   EXPECT_TRUE(characteristic1_->IsNotifying());
 }
-#endif
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
 TEST_F(BluetoothRemoteGattCharacteristicTest,
        StopNotifySession_Reentrant_Stop_StartError) {
+  if (!PlatformSupportsLowEnergy()) {
+    LOG(WARNING) << "Low Energy Bluetooth unavailable, skipping unit test.";
+    return;
+  }
   ASSERT_NO_FATAL_FAILURE(StartNotifyBoilerplate(
       /* properties: NOTIFY */ 0x10,
       /* expected_config_descriptor_value: NOTIFY */ 1));
@@ -2030,7 +2182,7 @@
   EXPECT_FALSE(notify_sessions_[0]->IsActive());
   EXPECT_FALSE(characteristic1_->IsNotifying());
 }
-#endif
+#endif  // defined(OS_ANDROID) || defined(OS_MACOSX)
 
 #if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
 // Tests Characteristic Value changes during a Notify Session.
diff --git a/device/bluetooth/test/bluetooth_test_mac.h b/device/bluetooth/test/bluetooth_test_mac.h
index 90a7e89..3370856 100644
--- a/device/bluetooth/test/bluetooth_test_mac.h
+++ b/device/bluetooth/test/bluetooth_test_mac.h
@@ -73,6 +73,11 @@
   void SimulateGattNotifySessionStartError(
       BluetoothRemoteGattCharacteristic* characteristic,
       BluetoothRemoteGattService::GattErrorCode error_code) override;
+  void SimulateGattNotifySessionStopped(
+      BluetoothRemoteGattCharacteristic* characteristic) override;
+  void SimulateGattNotifySessionStopError(
+      BluetoothRemoteGattCharacteristic* characteristic,
+      BluetoothRemoteGattService::GattErrorCode error_code) override;
   void SimulateGattCharacteristicChanged(
       BluetoothRemoteGattCharacteristic* characteristic,
       const std::vector<uint8_t>& value) override;
@@ -88,7 +93,7 @@
   void OnFakeBluetoothServiceDiscovery();
   void OnFakeBluetoothCharacteristicReadValue();
   void OnFakeBluetoothCharacteristicWriteValue(std::vector<uint8_t> value);
-  void OnFakeBluetoothGattSetCharacteristicNotification();
+  void OnFakeBluetoothGattSetCharacteristicNotification(bool notify_value);
 
   // Returns the service UUIDs used to retrieve connected peripherals.
   BluetoothDevice::UUIDSet RetrieveConnectedPeripheralServiceUUIDs();
@@ -113,6 +118,9 @@
 
   BluetoothAdapterMac* adapter_mac_ = nullptr;
   std::unique_ptr<ScopedMockCentralManager> mock_central_manager_;
+
+  // Value set by -[CBPeripheral setNotifyValue:forCharacteristic:] call.
+  bool last_notify_value = false;
 };
 
 // Defines common test fixture name. Use TEST_F(BluetoothTest, YourTestName).
diff --git a/device/bluetooth/test/bluetooth_test_mac.mm b/device/bluetooth/test/bluetooth_test_mac.mm
index f0e3b882..eb4bf905e 100644
--- a/device/bluetooth/test/bluetooth_test_mac.mm
+++ b/device/bluetooth/test/bluetooth_test_mac.mm
@@ -421,6 +421,22 @@
   [characteristic_mock simulateGattNotifySessionFailedWithError:error];
 }
 
+void BluetoothTestMac::SimulateGattNotifySessionStopped(
+    BluetoothRemoteGattCharacteristic* characteristic) {
+  MockCBCharacteristic* characteristic_mock =
+      GetCBMockCharacteristic(characteristic);
+  [characteristic_mock simulateGattNotifySessionStopped];
+}
+
+void BluetoothTestMac::SimulateGattNotifySessionStopError(
+    BluetoothRemoteGattCharacteristic* characteristic,
+    BluetoothRemoteGattService::GattErrorCode error_code) {
+  MockCBCharacteristic* characteristic_mock =
+      GetCBMockCharacteristic(characteristic);
+  NSError* error = BluetoothDeviceMac::GetNSErrorFromGattErrorCode(error_code);
+  [characteristic_mock simulateGattNotifySessionStoppedWithError:error];
+}
+
 void BluetoothTestMac::SimulateGattCharacteristicChanged(
     BluetoothRemoteGattCharacteristic* characteristic,
     const std::vector<uint8_t>& value) {
@@ -471,7 +487,9 @@
   gatt_write_characteristic_attempts_++;
 }
 
-void BluetoothTest::OnFakeBluetoothGattSetCharacteristicNotification() {
+void BluetoothTest::OnFakeBluetoothGattSetCharacteristicNotification(
+    bool notify_value) {
+  last_notify_value = notify_value;
   gatt_notify_characteristic_attempts_++;
 }
 
diff --git a/device/bluetooth/test/mock_bluetooth_cbcharacteristic_mac.h b/device/bluetooth/test/mock_bluetooth_cbcharacteristic_mac.h
index a231970..e3bbabf 100644
--- a/device/bluetooth/test/mock_bluetooth_cbcharacteristic_mac.h
+++ b/device/bluetooth/test/mock_bluetooth_cbcharacteristic_mac.h
@@ -26,6 +26,8 @@
 - (void)simulateWriteWithError:(NSError*)error;
 - (void)simulateGattNotifySessionStarted;
 - (void)simulateGattNotifySessionFailedWithError:(NSError*)error;
+- (void)simulateGattNotifySessionStopped;
+- (void)simulateGattNotifySessionStoppedWithError:(NSError*)error;
 - (void)simulateGattCharacteristicChangedWithValue:(NSData*)value;
 - (void)simulateDescriptorWithUUID:(CBUUID*)uuid;
 - (void)discoverDescriptors;
diff --git a/device/bluetooth/test/mock_bluetooth_cbcharacteristic_mac.mm b/device/bluetooth/test/mock_bluetooth_cbcharacteristic_mac.mm
index 31816c7..2cc9eb7b 100644
--- a/device/bluetooth/test/mock_bluetooth_cbcharacteristic_mac.mm
+++ b/device/bluetooth/test/mock_bluetooth_cbcharacteristic_mac.mm
@@ -158,6 +158,23 @@
 }
 
 - (void)simulateGattNotifySessionFailedWithError:(NSError*)error {
+  _notifying = NO;
+  CBPeripheral* peripheral = _service.peripheral;
+  [peripheral.delegate peripheral:peripheral
+      didUpdateNotificationStateForCharacteristic:self.characteristic
+                                            error:error];
+}
+
+- (void)simulateGattNotifySessionStopped {
+  _notifying = NO;
+  CBPeripheral* peripheral = _service.peripheral;
+  [peripheral.delegate peripheral:peripheral
+      didUpdateNotificationStateForCharacteristic:self.characteristic
+                                            error:nil];
+}
+
+- (void)simulateGattNotifySessionStoppedWithError:(NSError*)error {
+  _notifying = NO;
   CBPeripheral* peripheral = _service.peripheral;
   [peripheral.delegate peripheral:peripheral
       didUpdateNotificationStateForCharacteristic:self.characteristic
diff --git a/device/bluetooth/test/mock_bluetooth_cbperipheral_mac.mm b/device/bluetooth/test/mock_bluetooth_cbperipheral_mac.mm
index 8a5eafe..a11a11b 100644
--- a/device/bluetooth/test/mock_bluetooth_cbperipheral_mac.mm
+++ b/device/bluetooth/test/mock_bluetooth_cbperipheral_mac.mm
@@ -190,7 +190,8 @@
 
 - (void)setNotifyValue:(BOOL)notification
      forCharacteristic:(CBCharacteristic*)characteristic {
-  _bluetoothTestMac->OnFakeBluetoothGattSetCharacteristicNotification();
+  _bluetoothTestMac->OnFakeBluetoothGattSetCharacteristicNotification(
+      notification == YES);
 }
 
 @end
diff --git a/device/geolocation/wifi_data_provider_chromeos_unittest.cc b/device/geolocation/wifi_data_provider_chromeos_unittest.cc
index d740b2f..9234cb0 100644
--- a/device/geolocation/wifi_data_provider_chromeos_unittest.cc
+++ b/device/geolocation/wifi_data_provider_chromeos_unittest.cc
@@ -52,7 +52,8 @@
                                                  channel);
         properties.SetStringWithoutPathExpansion(
             shill::kGeoSignalStrengthProperty, strength);
-        manager_test_->AddGeoNetwork(shill::kTypeWifi, properties);
+        manager_test_->AddGeoNetwork(shill::kGeoWifiAccessPointsProperty,
+                                     properties);
       }
     }
     base::RunLoop().RunUntilIdle();
diff --git a/device/usb/BUILD.gn b/device/usb/BUILD.gn
index f87aef46..4e22715 100644
--- a/device/usb/BUILD.gn
+++ b/device/usb/BUILD.gn
@@ -44,6 +44,8 @@
     "usb_service.h",
     "usb_service_android.cc",
     "usb_service_android.h",
+    "usb_service_win.cc",
+    "usb_service_win.h",
     "webusb_descriptors.cc",
     "webusb_descriptors.h",
     generated_ids,
diff --git a/device/usb/mock_usb_service.cc b/device/usb/mock_usb_service.cc
index ff78d42..48ff601 100644
--- a/device/usb/mock_usb_service.cc
+++ b/device/usb/mock_usb_service.cc
@@ -12,11 +12,7 @@
 
 namespace device {
 
-MockUsbService::MockUsbService()
-    : UsbService(base::ThreadTaskRunnerHandle::IsSet()
-                     ? base::ThreadTaskRunnerHandle::Get()
-                     : nullptr,
-                 nullptr) {}
+MockUsbService::MockUsbService() : UsbService(nullptr) {}
 
 MockUsbService::~MockUsbService() {
   // Shutdown() must be called before the base class destructor.
diff --git a/device/usb/usb_service.cc b/device/usb/usb_service.cc
index 223a523..80873c0 100644
--- a/device/usb/usb_service.cc
+++ b/device/usb/usb_service.cc
@@ -5,11 +5,13 @@
 #include "device/usb/usb_service.h"
 
 #include "base/bind.h"
+#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "components/device_event_log/device_event_log.h"
+#include "device/base/features.h"
 #include "device/usb/usb_device.h"
 
 #if defined(OS_ANDROID)
@@ -17,6 +19,9 @@
 #elif defined(USE_UDEV)
 #include "device/usb/usb_service_linux.h"
 #else
+#if defined(OS_WIN)
+#include "device/usb/usb_service_win.h"
+#endif
 #include "device/usb/usb_service_impl.h"
 #endif
 
@@ -43,7 +48,12 @@
   return base::WrapUnique(new UsbServiceAndroid(blocking_task_runner));
 #elif defined(USE_UDEV)
   return base::WrapUnique(new UsbServiceLinux(blocking_task_runner));
-#elif defined(OS_WIN) || defined(OS_MACOSX)
+#elif defined(OS_WIN)
+  if (base::FeatureList::IsEnabled(kNewUsbBackend))
+    return base::WrapUnique(new UsbServiceWin(blocking_task_runner));
+  else
+    return base::WrapUnique(new UsbServiceImpl(blocking_task_runner));
+#elif defined(OS_MACOSX)
   return base::WrapUnique(new UsbServiceImpl(blocking_task_runner));
 #else
   return nullptr;
@@ -61,9 +71,11 @@
 }
 
 UsbService::UsbService(
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
-    : task_runner_(task_runner), blocking_task_runner_(blocking_task_runner) {}
+    : blocking_task_runner_(std::move(blocking_task_runner)) {
+  if (base::ThreadTaskRunnerHandle::IsSet())
+    task_runner_ = base::ThreadTaskRunnerHandle::Get();
+}
 
 scoped_refptr<UsbDevice> UsbService::GetDevice(const std::string& guid) {
   DCHECK(CalledOnValidThread());
diff --git a/device/usb/usb_service.h b/device/usb/usb_service.h
index 99b626d..15977dd 100644
--- a/device/usb/usb_service.h
+++ b/device/usb/usb_service.h
@@ -76,17 +76,16 @@
   void GetTestDevices(std::vector<scoped_refptr<UsbDevice>>* devices);
 
  protected:
-  UsbService(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
-             scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
+  UsbService(scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
 
   void NotifyDeviceAdded(scoped_refptr<UsbDevice> device);
   void NotifyDeviceRemoved(scoped_refptr<UsbDevice> device);
 
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner() {
+  const scoped_refptr<base::SingleThreadTaskRunner>& task_runner() const {
     return task_runner_;
   }
 
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner() {
+  const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner() const {
     return blocking_task_runner_;
   }
 
diff --git a/device/usb/usb_service_android.cc b/device/usb/usb_service_android.cc
index a1d1a89..102b33c 100644
--- a/device/usb/usb_service_android.cc
+++ b/device/usb/usb_service_android.cc
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/sequenced_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "components/device_event_log/device_event_log.h"
 #include "device/usb/usb_device_android.h"
 #include "jni/ChromeUsbService_jni.h"
@@ -29,8 +28,7 @@
 
 UsbServiceAndroid::UsbServiceAndroid(
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
-    : UsbService(base::ThreadTaskRunnerHandle::Get(), blocking_task_runner),
-      weak_factory_(this) {
+    : UsbService(blocking_task_runner), weak_factory_(this) {
   JNIEnv* env = AttachCurrentThread();
   j_object_.Reset(
       Java_ChromeUsbService_create(env, base::android::GetApplicationContext(),
diff --git a/device/usb/usb_service_impl.cc b/device/usb/usb_service_impl.cc
index 2f5883b0..6c1922d3 100644
--- a/device/usb/usb_service_impl.cc
+++ b/device/usb/usb_service_impl.cc
@@ -19,7 +19,6 @@
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "components/device_event_log/device_event_log.h"
 #include "device/usb/usb_device_handle.h"
@@ -215,17 +214,17 @@
 }  // namespace
 
 UsbServiceImpl::UsbServiceImpl(
-    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
-    : UsbService(base::ThreadTaskRunnerHandle::Get(), blocking_task_runner),
+    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_in)
+    : UsbService(std::move(blocking_task_runner_in)),
 #if defined(OS_WIN)
       device_observer_(this),
 #endif
       weak_factory_(this) {
-  blocking_task_runner->PostTask(
-      FROM_HERE, base::Bind(&InitializeUsbContextOnBlockingThread,
-                            base::ThreadTaskRunnerHandle::Get(),
-                            base::Bind(&UsbServiceImpl::OnUsbContext,
-                                       weak_factory_.GetWeakPtr())));
+  blocking_task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&InitializeUsbContextOnBlockingThread, task_runner(),
+                 base::Bind(&UsbServiceImpl::OnUsbContext,
+                            weak_factory_.GetWeakPtr())));
 }
 
 UsbServiceImpl::~UsbServiceImpl() {
diff --git a/device/usb/usb_service_linux.cc b/device/usb/usb_service_linux.cc
index c94bb276..394da74 100644
--- a/device/usb/usb_service_linux.cc
+++ b/device/usb/usb_service_linux.cc
@@ -22,7 +22,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "components/device_event_log/device_event_log.h"
 #include "device/base/device_monitor_linux.h"
@@ -185,9 +184,7 @@
 
 UsbServiceLinux::UsbServiceLinux(
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_in)
-    : UsbService(base::ThreadTaskRunnerHandle::Get(),
-                 std::move(blocking_task_runner_in)),
-      weak_factory_(this) {
+    : UsbService(std::move(blocking_task_runner_in)), weak_factory_(this) {
   helper_ = base::MakeUnique<FileThreadHelper>(weak_factory_.GetWeakPtr(),
                                                task_runner());
   blocking_task_runner()->PostTask(
diff --git a/device/usb/usb_service_win.cc b/device/usb/usb_service_win.cc
new file mode 100644
index 0000000..6feea89
--- /dev/null
+++ b/device/usb/usb_service_win.cc
@@ -0,0 +1,15 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/usb/usb_service_win.h"
+
+namespace device {
+
+UsbServiceWin::UsbServiceWin(
+    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
+    : UsbService(blocking_task_runner) {}
+
+UsbServiceWin::~UsbServiceWin() {}
+
+}  // namespace device
diff --git a/device/usb/usb_service_win.h b/device/usb/usb_service_win.h
new file mode 100644
index 0000000..a6feb81
--- /dev/null
+++ b/device/usb/usb_service_win.h
@@ -0,0 +1,21 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/usb/usb_service.h"
+
+#include "base/macros.h"
+
+namespace device {
+
+class UsbServiceWin : public UsbService {
+ public:
+  explicit UsbServiceWin(
+      scoped_refptr<base::SequencedTaskRunner> blocking_task_runner);
+  ~UsbServiceWin() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UsbServiceWin);
+};
+
+}  // namespace device
diff --git a/device/vibration/android/java/src/org/chromium/device/vibration/VibrationManagerImpl.java b/device/vibration/android/java/src/org/chromium/device/vibration/VibrationManagerImpl.java
index 31a619e..98c24ec 100644
--- a/device/vibration/android/java/src/org/chromium/device/vibration/VibrationManagerImpl.java
+++ b/device/vibration/android/java/src/org/chromium/device/vibration/VibrationManagerImpl.java
@@ -11,7 +11,7 @@
 import android.util.Log;
 
 import org.chromium.base.VisibleForTesting;
-import org.chromium.device.VibrationManager;
+import org.chromium.device.mojom.VibrationManager;
 import org.chromium.mojo.system.MojoException;
 import org.chromium.services.service_manager.InterfaceFactory;
 
diff --git a/device/vibration/vibration_manager.mojom b/device/vibration/vibration_manager.mojom
index c6179bf..a9333011 100644
--- a/device/vibration/vibration_manager.mojom
+++ b/device/vibration/vibration_manager.mojom
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module device;
+module device.mojom;
 
 interface VibrationManager {
   // TODO(mvanouwerkerk): Add something like StructTraits to validate arguments.
   Vibrate(int64 milliseconds) => ();
   Cancel() => ();
-};
\ No newline at end of file
+};
diff --git a/device/vibration/vibration_manager_impl.h b/device/vibration/vibration_manager_impl.h
index 668772f7..de9a0617 100644
--- a/device/vibration/vibration_manager_impl.h
+++ b/device/vibration/vibration_manager_impl.h
@@ -13,7 +13,7 @@
 class VibrationManagerImpl {
  public:
   DEVICE_VIBRATION_EXPORT static void Create(
-      mojo::InterfaceRequest<VibrationManager> request);
+      mojo::InterfaceRequest<mojom::VibrationManager> request);
 };
 
 }  // namespace device
diff --git a/device/vibration/vibration_manager_impl_default.cc b/device/vibration/vibration_manager_impl_default.cc
index df59a122..642ddbb7 100644
--- a/device/vibration/vibration_manager_impl_default.cc
+++ b/device/vibration/vibration_manager_impl_default.cc
@@ -13,7 +13,7 @@
 
 namespace {
 
-class VibrationManagerEmptyImpl : public VibrationManager {
+class VibrationManagerEmptyImpl : public mojom::VibrationManager {
  public:
   VibrationManagerEmptyImpl() {}
   ~VibrationManagerEmptyImpl() override {}
@@ -28,7 +28,7 @@
 }  // namespace
 
 // static
-void VibrationManagerImpl::Create(VibrationManagerRequest request) {
+void VibrationManagerImpl::Create(mojom::VibrationManagerRequest request) {
   mojo::MakeStrongBinding(base::MakeUnique<VibrationManagerEmptyImpl>(),
                           std::move(request));
 }
diff --git a/docs/android_build_instructions.md b/docs/android_build_instructions.md
index 2e2cf1bf..be30dfa 100644
--- a/docs/android_build_instructions.md
+++ b/docs/android_build_instructions.md
@@ -134,7 +134,7 @@
 run:
 
 ```shell
-$ gn gen '--args="target_os="android"' out/Default
+$ gn gen --args='target_os="android"' out/Default
 ```
 
 * You only have to run this once for each new build directory, Ninja will
diff --git a/docs/documentation_guidelines.md b/docs/documentation_guidelines.md
new file mode 100644
index 0000000..14f2d4d
--- /dev/null
+++ b/docs/documentation_guidelines.md
@@ -0,0 +1,90 @@
+# **Chromium Documentation Guidelines**
+
+Chromium's code base is large. Very large. Like most large places, it can be hard to find your way around if you don't already know the way. It also changes a lot. Lots of people work on Chromium and refactoring, componentization, addition
+or removal of layers, etc. means that knowledge one does have can quickly get out of date.
+
+As a result, it can be hard to figure out how things are supposed to fit together. Documentation on [dev.chromium.org](http://dev.chromium.org/developers) can be hard to navigate and harder to keep up to date. The [starter guide](https://sites.google.com/a/chromium.org/dev/developers/how-tos/getting-around-the-chrome-source-code) is helpful, but stops at a very high-level overview. Ultimately [codesearch.chromium.org](http://codesearch.chromium.org) is the way most people explore.
+
+This guide attempts to lay out some practices that will make it easier for newcomers to find their way around Chromium's code and for old hands to keep up with a constantly evolving code base. It works from the principle that all documentation is wrong and out of date, but in-code documentation is less so and valuable.
+
+## Guidelines
+
+In-code documentation can be categorized into three tiers:
+
+*   **Module / component documentation**: This is documentation that tends to be found in README.md files at the root level directory of a component. The purpose of this type of documentation is to explain what a given set of related classes are for, roughly how they are structured and *what* the component is expected to be used for.
+*   **Interface / class documentation**: This is documentation most often found in header files near class definitions. This may describe what a class or small set of classes are for and *how* they are intended to be used. It may also provide examples of usage of the class where this isn't obvious.
+*   **Implementation documentation**: This type of documentation is found next to implementations. In C++, this will tend to be embedded in .cc files. It is meant to help a reader understand *how the code works* or explain an implementation path that might not be obvious from the code itself.
+
+Let's dig in a bit to how to use these types of documentation in Chromium.
+
+### Module / component documentation
+
+Ok, so you're working on something big and important. Maybe it's a chunk of code that merits living in its own component in [src/components/](https://codesearch.chromium.org/chromium/src/components/) or even directly under [src/](https://codesearch.chromium.org/chromium/src/) itself. One day someone's going to come along and wonder what it's for and they'll discover that awesome-directory-name (breakpad, courgette, mojo, rutabaga, quick: which one of those was made up?) doesn't by itself shed a lot of light on what the code does.
+
+***Any self contained unit of code that merits a container directory should have a README.md file that describes what that component is, how it is expected to be used and provides rough outline of the code's structure.***
+
+The README.md file should be located at the root of the component directory and should be in [markdown format](https://www.chromium.org/developers/markdown-documentation) according to the markdown [style guide](https://github.com/google/styleguide/blob/gh-pages/docguide/style.md).
+
+The first thing in the README.md file should be a description of the component in sufficient detail that someone unfamiliar with the code will understand why it exists. It should answer the questions "what does this component do?" and "is there any in particular I should know about it?". Some larger components (e.g. v8, mojo, etc.) may have additional up-to-date documentation on [dev.chromium.org](http://dev.chromium.org) or elsewhere makes sense too.
+
+The second thing in the README.md file should be an outline of how it is expected to be used. For components of small to moderate size (e.g. under [src/components/](https://codesearch.chromium.org/chromium/src/components/)), this can mean what are the main classes to care about. For larger components this can describe how to go about using the component, possibly in the form of links to external documentation (e.g.: [src/v8/](https://codesearch.chromium.org/chromium/src/v8/README.md)).
+
+The third thing should be a lay of the land of the component, sufficient breadcrumbs for a newcomer to be able to orient themselves. This usually means at least an explanation of the subdirectories of the component and possibly a description of the major interfaces a consumer of the component will need to care about. Again for larger components this can live in external kept-up-to-date documentation where needed.
+
+The fourth thing should be historical links to design docs for the component, including early ones. These are super handy for people looking to understand why the component exists in its current form.
+
+A great example of a README.md file is [src/native_client/README.md](https://codesearch.chromium.org/chromium/src/native_client/README.md). There are many more examples that are waiting to be made great.
+
+### Interface / class documentation
+
+Class and function declarations in header files describe to the world how a piece of code should be used. The public interface of a class or a header file containing function declarations describe the API to the code but don't necessarily say much about how it is expected to be used. As such:
+
+***Non-trivial classes or sets of function declarations in header files should include comments with a brief description of the purpose of the class or set of functions as well as examples of expected usage.  ***
+
+(Good) examples:
+
+https://codesearch.chromium.org/chromium/src/base/callback_list.h
+
+https://codesearch.chromium.org/chromium/src/base/feature_list.h
+
+### Implementation documentation
+
+Code should be as self documenting as possible, but sometimes that isn't enough. Maybe there's a tricky bit of implementation that isn't obvious. Maybe there's a clever algorithm that has a good reason it needs to be clever. A good rule of thumb is that if a code reviewer had a clarifying question about something during review and the code couldn't be simplified to answer the question then a comment is probably appropriate. Don't go nuts here though, often if code is so complicated that it needs lots of comments, then it could probably be simplified first.
+
+## Language
+
+Be concise.
+
+Use correct grammar as much as possible.
+
+Avoid fancy or confusing language.
+
+Don't assume that readers know everything you currently know.
+
+## Working with existing code
+
+If you got this far and have some experience with Chromium's code, you'll have figured out that these guidelines are aspirational more than what the world looks like today. So what do we do when working with existing code.
+
+First off: ***[Documentation changes can be TBRed](https://chromium.googlesource.com/chromium/src/+/master/docs/code_reviews.md#TBR_ing-documentation-updates)***. Even in-code changes. If you have discovered something that isn't documented, have figured out how it works and would like to pay it forward, feel free to write something down and check it in.
+
+At the component level, if you are the owner of a component that isn't documented, please add a README.md with content as per the above.
+
+If you don't own a component and figure out how it works, consider adding some notes to the component's README.md file. You don't need to be an expert to share what you do know with those who come afterwards.
+
+The same applies to class level comments and implementation comments. If you find yourself modifying code and realizing that it is… under-documented.. feel free to add some notes nearby.
+
+In general, use your judgment. Changes will NOT be blocked on requiring people to add missing documentation, but adding missing docs is a great way to make our code base healthier.
+
+## FAQ
+
+#### Are these hard rules?
+
+[Well, no](https://www.youtube.com/watch?v=jl0hMfqNQ-g). This said, following these guidelines will make our code base healthier, more consistent and much easier to understand. Over time improving in-code documentation will make the whole team faster. But if a small fix is genuinely needed (it almost always isn't), then don't block on writing detailed documentation. As always: use your judgment.
+
+#### I'm not an expert on this undocumented code, should I still add documentation?
+
+Yes! Partial documentation is much better than no documentation.
+
+#### I hate writing documentation, it will slow me down!
+
+Chromium is big enough and complicated enough that a newcomer has to read a lot of code to figure out how things fit together. Documentation provides breadcrumbs to speed up understanding, which over time will make the whole team work more quickly. Short term execution speed is far less important than long term team velocity.
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 963ab0b9..4e43601 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -5,7 +5,41 @@
 import("//build/config/features.gni")
 import("//extensions/features/features.gni")
 
-source_set("browser") {
+group("browser") {
+  public_deps = [
+    "//extensions/browser:browser_context_keyed_service_factories",
+    "//extensions/browser:browser_sources",
+    "//extensions/browser/api:api_registration",
+  ]
+
+  if (enable_extensions) {
+    # Includes all API implementations and the ExtensionsApiClient
+    # interface. Moving an API from src/chrome to src/extensions implies
+    # it can be cleanly disabled with enable_extensions=false.
+    # TODO: Eventually the entire extensions module should not be built
+    # when enable_extensions=false.
+    public_deps += [ "//extensions/browser/api" ]
+  }
+}
+
+# Isolate the instantiation of BrowserContextKeyedServiceFactories.
+source_set("browser_context_keyed_service_factories") {
+  visibility = [ ":*" ]
+
+  sources = [
+    "browser_context_keyed_service_factories.cc",
+    "browser_context_keyed_service_factories.h",
+  ]
+
+  deps = [
+    "//extensions/browser:browser_sources",
+    "//extensions/browser/api",
+  ]
+}
+
+source_set("browser_sources") {
+  visibility = [ "./*" ]
+
   sources = []
 
   deps = [
@@ -22,8 +56,8 @@
     "//components/web_modal",
     "//components/zoom",
     "//content/public/browser",
+    "//content/public/common",
     "//crypto:platform",
-    "//extensions/browser/api:api_registration",
     "//extensions/common",
     "//extensions/common/api",
     "//extensions/features",
@@ -40,14 +74,7 @@
   ]
 
   if (enable_extensions) {
-    # Includes all API implementations and the ExtensionsApiClient
-    # interface. Moving an API from src/chrome to src/extensions implies
-    # it can be cleanly disabled with enable_extensions=false.
-    # TODO: Eventually the entire extensions module should not be built
-    # when enable_extensions=false.
     sources = [
-      # NOTE: When moving an API out of Chrome be sure to verify that the
-      # Android build still compiles. See conditions below.
       "api_activity_monitor.cc",
       "api_activity_monitor.h",
       "app_sorting.h",
@@ -58,8 +85,6 @@
       "blob_holder.h",
       "blocked_action_type.h",
       "browser_context_keyed_api_factory.h",
-      "browser_context_keyed_service_factories.cc",
-      "browser_context_keyed_service_factories.h",
       "component_extension_resource_manager.h",
       "computed_hashes.cc",
       "computed_hashes.h",
@@ -254,7 +279,6 @@
     ]
 
     public_deps = [
-      "//extensions/browser/api",
       "//extensions/browser/app_window",
       "//extensions/browser/guest_view",
       "//extensions/browser/install",
@@ -264,26 +288,16 @@
     ]
 
     deps += [
-      "//components/browsing_data/content",
-      "//components/onc",
-      "//components/storage_monitor",
+      "//components/crx_file",
+      "//components/prefs",
+      "//components/sync",
       "//components/update_client",
       "//components/variations",
       "//crypto:platform",
-      "//device/base",
-      "//device/bluetooth",
-      "//device/hid",
-      "//device/power_save_blocker",
-      "//device/serial",
-      "//device/usb",
       "//extensions:extensions_browser_resources",
       "//extensions/common:mojo",
       "//services/service_manager/public/cpp",
     ]
-
-    if (is_chromeos) {
-      deps += [ "//chromeos" ]
-    }
   }
 }
 
@@ -367,6 +381,9 @@
     "api/document_scan/document_scan_api_unittest.cc",
     "api/document_scan/document_scan_interface_chromeos_unittest.cc",
     "api/document_scan/mock_document_scan_interface.cc",
+    "api/file_handlers/app_file_handler_util_unittest.cc",
+    "api/file_handlers/directory_util_unittest.cc",
+    "api/file_handlers/mime_util_unittest.cc",
     "api/idle/idle_api_unittest.cc",
     "api/mime_handler_private/mime_handler_private_unittest.cc",
     "api/networking_config/networking_config_service_chromeos_unittest.cc",
diff --git a/extensions/browser/DEPS b/extensions/browser/DEPS
index b6a825c..99095ce4 100644
--- a/extensions/browser/DEPS
+++ b/extensions/browser/DEPS
@@ -25,7 +25,6 @@
   "+ppapi/features",
   "+services/service_manager/public/cpp",
   "+skia/ext/image_operations.h",
-  "+storage/browser/fileapi",
   "+third_party/leveldatabase",
   "+third_party/re2",
   "+third_party/WebKit/public/platform",
diff --git a/extensions/browser/api/BUILD.gn b/extensions/browser/api/BUILD.gn
index 210a2ffc..b5b8fb82 100644
--- a/extensions/browser/api/BUILD.gn
+++ b/extensions/browser/api/BUILD.gn
@@ -41,6 +41,7 @@
     "//extensions/browser/api/display_source",
     "//extensions/browser/api/dns",
     "//extensions/browser/api/document_scan",
+    "//extensions/browser/api/file_handlers",
     "//extensions/browser/api/guest_view",
     "//extensions/browser/api/guest_view/app_view",
     "//extensions/browser/api/guest_view/extension_view",
@@ -76,10 +77,28 @@
 
   deps = [
     "//base:i18n",
+    "//components/keyed_service/content:content",
     "//content/public/browser",
+    "//content/public/common",
+    "//extensions/browser:browser_sources",
+    "//extensions/browser/guest_view",
+    "//extensions/common",
+    "//extensions/common/api",
     "//extensions/strings",
   ]
 
+  # TODO(michaelpg): Move these deps to the individual APIs that require them.
+  deps += [
+    "//components/onc",
+    "//components/storage_monitor",
+    "//device/base",
+    "//device/bluetooth",
+    "//device/hid",
+    "//device/power_save_blocker",
+    "//device/serial",
+    "//device/usb",
+  ]
+
   if (is_chromeos) {
     public_deps += [
       "//extensions/browser/api/clipboard",
@@ -88,6 +107,8 @@
       "//extensions/browser/api/vpn_provider",
       "//extensions/browser/api/webcam_private",
     ]
+
+    deps += [ "//chromeos" ]
   }
 }
 
diff --git a/extensions/browser/api/DEPS b/extensions/browser/api/DEPS
index d1dcf78e..f3a07563 100644
--- a/extensions/browser/api/DEPS
+++ b/extensions/browser/api/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
   "+device/base",
   "+device/hid",
+  "+storage/browser/fileapi",
+  "+storage/common/fileapi",
 ]
diff --git a/extensions/browser/api/cast_channel/BUILD.gn b/extensions/browser/api/cast_channel/BUILD.gn
index 67a5b2b..4de03db 100644
--- a/extensions/browser/api/cast_channel/BUILD.gn
+++ b/extensions/browser/api/cast_channel/BUILD.gn
@@ -20,8 +20,6 @@
     "keep_alive_delegate.h",
     "logger.cc",
     "logger.h",
-    "logger_util.cc",
-    "logger_util.h",
   ]
 
   deps = [
@@ -29,6 +27,5 @@
     "//extensions/common/api",
     "//extensions/common/api/cast_channel:cast_channel_proto",
     "//net",
-    "//third_party/zlib",
   ]
 }
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc
index b8fd3b2b..29e111c 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -16,7 +16,6 @@
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/time/default_clock.h"
 #include "base/values.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/api/cast_channel/cast_message_util.h"
@@ -109,9 +108,7 @@
 }  // namespace
 
 CastChannelAPI::CastChannelAPI(content::BrowserContext* context)
-    : browser_context_(context),
-      logger_(new Logger(base::WrapUnique<base::Clock>(new base::DefaultClock),
-                         base::Time::UnixEpoch())) {
+    : browser_context_(context), logger_(new Logger()) {
   DCHECK(browser_context_);
 }
 
@@ -320,7 +317,6 @@
                                         : CastDeviceCapability::NONE);
   }
   new_channel_id_ = AddSocket(socket);
-  api_->GetLogger()->LogNewSocketEvent(*socket);
 
   // Construct read delegates.
   std::unique_ptr<api::cast_channel::CastTransport::Delegate> delegate(
@@ -342,7 +338,6 @@
     delegate.reset(keep_alive);
   }
 
-  api_->GetLogger()->LogNewSocketEvent(*socket);
   socket->Connect(std::move(delegate),
                   base::Bind(&CastChannelOpenFunction::OnOpen, this));
 }
@@ -425,6 +420,11 @@
 
 CastChannelCloseFunction::~CastChannelCloseFunction() { }
 
+bool CastChannelCloseFunction::PrePrepare() {
+  api_ = CastChannelAPI::Get(browser_context());
+  return CastChannelAsyncApiFunction::PrePrepare();
+}
+
 bool CastChannelCloseFunction::Prepare() {
   params_ = Close::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params_.get());
@@ -454,41 +454,11 @@
     SetResultFromSocket(*socket);
     // This will delete |socket|.
     RemoveSocket(channel_id);
+    api_->GetLogger()->ClearLastErrors(channel_id);
   }
   AsyncWorkCompleted();
 }
 
-CastChannelGetLogsFunction::CastChannelGetLogsFunction() {
-}
-
-CastChannelGetLogsFunction::~CastChannelGetLogsFunction() {
-}
-
-bool CastChannelGetLogsFunction::PrePrepare() {
-  api_ = CastChannelAPI::Get(browser_context());
-  return CastChannelAsyncApiFunction::PrePrepare();
-}
-
-bool CastChannelGetLogsFunction::Prepare() {
-  return true;
-}
-
-void CastChannelGetLogsFunction::AsyncWorkStart() {
-  DCHECK(api_);
-
-  size_t length = 0;
-  std::unique_ptr<char[]> out = api_->GetLogger()->GetLogs(&length);
-  if (out.get()) {
-    SetResult(base::MakeUnique<base::BinaryValue>(std::move(out), length));
-  } else {
-    SetError("Unable to get logs.");
-  }
-
-  api_->GetLogger()->Reset();
-
-  AsyncWorkCompleted();
-}
-
 CastChannelOpenFunction::CastMessageHandler::CastMessageHandler(
     const EventDispatchCallback& ui_dispatch_cb,
     cast_channel::CastSocket* socket,
@@ -547,20 +517,4 @@
 void CastChannelOpenFunction::CastMessageHandler::Start() {
 }
 
-CastChannelSetAuthorityKeysFunction::CastChannelSetAuthorityKeysFunction() {
-}
-
-CastChannelSetAuthorityKeysFunction::~CastChannelSetAuthorityKeysFunction() {
-}
-
-bool CastChannelSetAuthorityKeysFunction::Prepare() {
-  return true;
-}
-
-void CastChannelSetAuthorityKeysFunction::AsyncWorkStart() {
-  // TODO(eroman): crbug.com/601171: Delete this once the API is
-  // removed. It is currently a no-op.
-  AsyncWorkCompleted();
-}
-
 }  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.h b/extensions/browser/api/cast_channel/cast_channel_api.h
index b526e73..c257599 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.h
+++ b/extensions/browser/api/cast_channel/cast_channel_api.h
@@ -241,6 +241,7 @@
   ~CastChannelCloseFunction() override;
 
   // AsyncApiFunction:
+  bool PrePrepare() override;
   bool Prepare() override;
   void AsyncWorkStart() override;
 
@@ -250,48 +251,9 @@
   void OnClose(int result);
 
   std::unique_ptr<cast_channel::Close::Params> params_;
-
-  DISALLOW_COPY_AND_ASSIGN(CastChannelCloseFunction);
-};
-
-class CastChannelGetLogsFunction : public CastChannelAsyncApiFunction {
- public:
-  CastChannelGetLogsFunction();
-
- protected:
-  ~CastChannelGetLogsFunction() override;
-
-  // AsyncApiFunction:
-  bool PrePrepare() override;
-  bool Prepare() override;
-  void AsyncWorkStart() override;
-
- private:
-  DECLARE_EXTENSION_FUNCTION("cast.channel.getLogs", CAST_CHANNEL_GETLOGS)
-
   CastChannelAPI* api_;
 
-  DISALLOW_COPY_AND_ASSIGN(CastChannelGetLogsFunction);
-};
-
-// TODO(eroman): crbug.com/601171: Delete this entire extension API. It
-// is currently deprecated and calling the function has no effect.
-class CastChannelSetAuthorityKeysFunction : public CastChannelAsyncApiFunction {
- public:
-  CastChannelSetAuthorityKeysFunction();
-
- protected:
-  ~CastChannelSetAuthorityKeysFunction() override;
-
-  // AsyncApiFunction:
-  bool Prepare() override;
-  void AsyncWorkStart() override;
-
- private:
-  DECLARE_EXTENSION_FUNCTION("cast.channel.setAuthorityKeys",
-                             CAST_CHANNEL_SETAUTHORITYKEYS)
-
-  DISALLOW_COPY_AND_ASSIGN(CastChannelSetAuthorityKeysFunction);
+  DISALLOW_COPY_AND_ASSIGN(CastChannelCloseFunction);
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/cast_channel_apitest.cc b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
index 565f616a..0c5a886 100644
--- a/extensions/browser/api/cast_channel/cast_channel_apitest.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
@@ -214,15 +214,6 @@
     return cast_channel_send_function;
   }
 
-  extensions::CastChannelSetAuthorityKeysFunction*
-  CreateSetAuthorityKeysFunction(scoped_refptr<Extension> extension) {
-    extensions::CastChannelSetAuthorityKeysFunction*
-        cast_channel_set_authority_keys_function =
-            new extensions::CastChannelSetAuthorityKeysFunction;
-    cast_channel_set_authority_keys_function->set_extension(extension.get());
-    return cast_channel_set_authority_keys_function;
-  }
-
   MockCastSocket* mock_cast_socket_;
   base::MockTimer* timeout_timer_;
   net::IPEndPoint ip_endpoint_;
@@ -338,20 +329,6 @@
   EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
 }
 
-// TODO(imcheng): Win Dbg has a workaround that makes RunExtensionSubtest
-// always return true without actually running the test. Remove when fixed.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_TestGetLogs DISABLED_TestGetLogs
-#else
-#define MAYBE_TestGetLogs TestGetLogs
-#endif
-// Test loading extension, execute a open-send-close sequence, then get logs.
-IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestGetLogs) {
-  SetUpOpenSendClose();
-
-  EXPECT_TRUE(RunExtensionSubtest("cast_channel/api", "test_get_logs.html"));
-}
-
 // TODO(kmarshall): Win Dbg has a workaround that makes RunExtensionSubtest
 // always return true without actually running the test. Remove when fixed.
 #if defined(OS_WIN) && !defined(NDEBUG)
@@ -468,104 +445,3 @@
       browser());
   EXPECT_EQ(error, "message_info.destination_id is required");
 }
-
-IN_PROC_BROWSER_TEST_F(CastChannelAPITest, TestSetAuthorityKeysInvalid) {
-  scoped_refptr<Extension> empty_extension(
-      extensions::test_util::CreateEmptyExtension());
-  scoped_refptr<extensions::CastChannelSetAuthorityKeysFunction>
-      cast_channel_set_authority_keys_function;
-  // TODO(eroman): crbug.com/601171: Delete this test once the API has
-  // been removed. The API is deprecated and will trivially return
-  // success. So this is just testing that it succeeds for all inputs
-  // (even invalid ones).
-  cast_channel_set_authority_keys_function =
-      CreateSetAuthorityKeysFunction(empty_extension);
-  EXPECT_TRUE(utils::RunFunction(cast_channel_set_authority_keys_function.get(),
-                                 "[\"\", \"signature\"]", browser(),
-                                 utils::NONE));
-
-  cast_channel_set_authority_keys_function =
-      CreateSetAuthorityKeysFunction(empty_extension);
-  EXPECT_TRUE(utils::RunFunction(cast_channel_set_authority_keys_function.get(),
-                                 "[\"keys\", \"\"]", browser(), utils::NONE));
-
-  std::string keys =
-      "CrMCCiBSnZzWf+XraY5w3SbX2PEmWfHm5SNIv2pc9xbhP0EOcxKOAjCCAQoCggEBALwigL"
-      "2A9johADuudl41fz3DZFxVlIY0LwWHKM33aYwXs1CnuIL638dDLdZ+q6BvtxNygKRHFcEg"
-      "mVDN7BRiCVukmM3SQbY2Tv/oLjIwSoGoQqNsmzNuyrL1U2bgJ1OGGoUepzk/SneO+1RmZv"
-      "tYVMBeOcf1UAYL4IrUzuFqVR+LFwDmaaMn5gglaTwSnY0FLNYuojHetFJQ1iBJ3nGg+a0g"
-      "QBLx3SXr1ea4NvTWj3/KQ9zXEFvmP1GKhbPz//YDLcsjT5ytGOeTBYysUpr3TOmZer5ufk"
-      "0K48YcqZP6OqWRXRy9ZuvMYNyGdMrP+JIcmH1X+mFHnquAt+RIgCqSxRsCAwEAAQ==";
-  std::string signature =
-      "chCUHZKkykcwU8HzU+hm027fUTBL0dqPMtrzppwExQwK9+"
-      "XlmCjJswfce2sUUfhR1OL1tyW4hWFwu4JnuQCJ+CvmSmAh2bzRpnuSKzBfgvIDjNOAGUs7"
-      "ADaNSSWPLxp+6ko++2Dn4S9HpOt8N1v6gMWqj3Ru5IqFSQPZSvGH2ois6uE50CFayPcjQE"
-      "OVZt41noQdFd15RmKTvocoCC5tHNlaikeQ52yi0IScOlad1B1lMhoplW3rWophQaqxMumr"
-      "OcHIZ+Y+p858x5f8Pny/kuqUClmFh9B/vF07NsUHwoSL9tA5t5jCY3L5iUc/v7o3oFcW/T"
-      "gojKkX2Kg7KQ86QA==";
-
-  cast_channel_set_authority_keys_function =
-      CreateSetAuthorityKeysFunction(empty_extension);
-  EXPECT_TRUE(utils::RunFunction(cast_channel_set_authority_keys_function.get(),
-                                 "[\"" + keys + "\", \"signature\"]", browser(),
-                                 utils::NONE));
-
-  cast_channel_set_authority_keys_function =
-      CreateSetAuthorityKeysFunction(empty_extension);
-  EXPECT_TRUE(utils::RunFunction(cast_channel_set_authority_keys_function.get(),
-                                 "[\"keys\", \"" + signature + "\"]", browser(),
-                                 utils::NONE));
-
-  cast_channel_set_authority_keys_function =
-      CreateSetAuthorityKeysFunction(empty_extension);
-  EXPECT_TRUE(utils::RunFunction(cast_channel_set_authority_keys_function.get(),
-                                 "[\"" + keys + "\", \"" + signature + "\"]",
-                                 browser(), utils::NONE));
-}
-
-IN_PROC_BROWSER_TEST_F(CastChannelAPITest, TestSetAuthorityKeysValid) {
-  scoped_refptr<Extension> empty_extension(
-      extensions::test_util::CreateEmptyExtension());
-  scoped_refptr<extensions::CastChannelSetAuthorityKeysFunction>
-      cast_channel_set_authority_keys_function;
-
-  cast_channel_set_authority_keys_function =
-      CreateSetAuthorityKeysFunction(empty_extension);
-  std::string keys =
-      "CrMCCiBSnZzWf+XraY5w3SbX2PEmWfHm5SNIv2pc9xbhP0EOcxKOAjCCAQoCggEBALwigL"
-      "2A9johADuudl41fz3DZFxVlIY0LwWHKM33aYwXs1CnuIL638dDLdZ+q6BvtxNygKRHFcEg"
-      "mVDN7BRiCVukmM3SQbY2Tv/oLjIwSoGoQqNsmzNuyrL1U2bgJ1OGGoUepzk/SneO+1RmZv"
-      "tYVMBeOcf1UAYL4IrUzuFqVR+LFwDmaaMn5gglaTwSnY0FLNYuojHetFJQ1iBJ3nGg+a0g"
-      "QBLx3SXr1ea4NvTWj3/KQ9zXEFvmP1GKhbPz//YDLcsjT5ytGOeTBYysUpr3TOmZer5ufk"
-      "0K48YcqZP6OqWRXRy9ZuvMYNyGdMrP+JIcmH1X+mFHnquAt+RIgCqSxRsCAwEAAQqzAgog"
-      "okjC6FTmVqVt6CMfHuF1b9vkB/n+1GUNYMxay2URxyASjgIwggEKAoIBAQCwDl4HOt+kX2"
-      "j3Icdk27Z27+6Lk/j2G4jhk7cX8BUeflJVdzwCjXtKbNO91sGccsizFc8RwfVGxNUgR/sw"
-      "9ORhDGjwXqs3jpvhvIHDcIp41oM0MpwZYuvknO3jZGxBHZzSi0hMI5CVs+dS6gVXzGCzuh"
-      "TkugA55EZVdM5ajnpnI9poCvrEhB60xaGianMfbsguL5qeqLEO/Yemj009SwXVNVp0TbyO"
-      "gkSW9LWVYE6l3yc9QVwHo7Q1WrOe8gUkys0xWg0mTNTT/VDhNOlMgVgwssd63YGJptQ6OI"
-      "QDtzSedz//eAdbmcGyHzVWbjo8DCXhV/aKfknAzIMRNeeRbS5lAgMBAAE=";
-  std::string signature =
-      "o83oku3jP+xjTysNBalqp/ZfJRPLt8R+IUhZMepbARFSRVizLoeFW5XyUwe6lQaC+PFFQH"
-      "SZeGZyeeGRpwCJ/lef0xh6SWJlVMWNTk5+z0U84GQdizJP/CTCeHpIwMobN+kyDajgOyfD"
-      "DLhktc6LHmSlFGG6J7B8W67oziS8ZFEdrcT9WSXFrjLVyURHjvidZD5iFtuImI6k9R9OoX"
-      "LR6SyAwpjdrL+vlHMk3Gol6KQ98YpF0ghHnN3/FFW4ibvIwjmRbp+tUV3h8TRcCOjlXVGp"
-      "bzPtNRRlTqfv7Rxm5YXkZMLmJJMZiTs5+o8FMRMTQZT4hRR3DQ+A/jofViyTGA==";
-
-  std::string args = "[\"" + keys + "\", \"" + signature + "\"]";
-  EXPECT_TRUE(utils::RunFunction(cast_channel_set_authority_keys_function.get(),
-                                 args, browser(), utils::NONE));
-}
-
-// TODO(vadimgo): Win Dbg has a workaround that makes RunExtensionSubtest
-// always return true without actually running the test. Remove when fixed.
-#if defined(OS_WIN) && !defined(NDEBUG)
-#define MAYBE_TestSetAuthorityKeys DISABLED_TestSetAuthorityKeys
-#else
-#define MAYBE_TestSetAuthorityKeys TestSetAuthorityKeys
-#endif
-// Test loading extension, opening a channel with ConnectInfo, adding a
-// listener, writing, reading, and closing.
-IN_PROC_BROWSER_TEST_F(CastChannelAPITest, MAYBE_TestSetAuthorityKeys) {
-  EXPECT_TRUE(
-      RunExtensionSubtest("cast_channel/api", "test_authority_keys.html"));
-}
diff --git a/extensions/browser/api/cast_channel/cast_socket.cc b/extensions/browser/api/cast_channel/cast_socket.cc
index 3bb675c..483b4f9 100644
--- a/extensions/browser/api/cast_channel/cast_socket.cc
+++ b/extensions/browser/api/cast_channel/cast_socket.cc
@@ -27,7 +27,6 @@
 #include "extensions/browser/api/cast_channel/cast_message_util.h"
 #include "extensions/browser/api/cast_channel/cast_transport.h"
 #include "extensions/browser/api/cast_channel/logger.h"
-#include "extensions/browser/api/cast_channel/logger_util.h"
 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
 #include "net/base/address_list.h"
 #include "net/base/host_port_pair.h"
@@ -210,11 +209,8 @@
 
 scoped_refptr<net::X509Certificate> CastSocketImpl::ExtractPeerCert() {
   net::SSLInfo ssl_info;
-  if (!socket_->GetSSLInfo(&ssl_info) || !ssl_info.cert.get()) {
+  if (!socket_->GetSSLInfo(&ssl_info) || !ssl_info.cert.get())
     return nullptr;
-  }
-
-  logger_->LogSocketEvent(channel_id_, proto::SSL_INFO_OBTAINED);
 
   return ssl_info.cert;
 }
@@ -225,8 +221,6 @@
       (device_capabilities_ & CastDeviceCapability::VIDEO_OUT) != 0) {
     LOG_WITH_CONNECTION(ERROR)
         << "Audio only channel policy enforced for video out capable device";
-    logger_->LogSocketEventWithDetails(
-        channel_id_, proto::CHANNEL_POLICY_ENFORCED, std::string());
     return false;
   }
   return true;
@@ -260,8 +254,6 @@
   delegate_ = std::move(delegate);
 
   if (ready_state_ != READY_STATE_NONE) {
-    logger_->LogSocketEventWithDetails(
-        channel_id_, proto::CONNECT_FAILED, "ReadyState not NONE");
     callback.Run(CHANNEL_ERROR_CONNECT_ERROR);
     return;
   }
@@ -291,7 +283,6 @@
   DCHECK(CalledOnValidThread());
   // Stop all pending connection setup tasks and report back to the client.
   is_canceled_ = true;
-  logger_->LogSocketEvent(channel_id_, proto::CONNECT_TIMED_OUT);
   VLOG_WITH_CONNECTION(1) << "Timeout while establishing a connection.";
   SetErrorState(CHANNEL_ERROR_CONNECT_TIMEOUT);
   DoConnectCallback();
@@ -362,7 +353,6 @@
 
   if (IsTerminalState(connect_state_)) {
     DCHECK_NE(rv, net::ERR_IO_PENDING);
-    logger_->LogSocketConnectState(channel_id_, connect_state_);
     GetTimer()->Stop();
     DoConnectCallback();
   } else {
@@ -499,13 +489,9 @@
     const CastMessage& message) {
   if (!IsAuthMessage(message)) {
     error_state_ = CHANNEL_ERROR_TRANSPORT_ERROR;
-    socket_->logger_->LogSocketEvent(socket_->channel_id_,
-                                     proto::AUTH_CHALLENGE_REPLY_INVALID);
     socket_->PostTaskToStartConnectLoop(net::ERR_INVALID_RESPONSE);
   } else {
     socket_->challenge_reply_.reset(new CastMessage(message));
-    socket_->logger_->LogSocketEvent(socket_->channel_id_,
-                                     proto::RECEIVED_CHALLENGE_REPLY);
     socket_->PostTaskToStartConnectLoop(net::OK);
   }
 }
@@ -586,7 +572,6 @@
   send_auth_challenge_callback_.Cancel();
   connect_timeout_callback_.Cancel();
   SetReadyState(READY_STATE_CLOSED);
-  logger_->LogSocketEvent(channel_id_, proto::SOCKET_CLOSED);
 }
 
 bool CastSocketImpl::CalledOnValidThread() const {
@@ -600,22 +585,18 @@
 void CastSocketImpl::SetConnectState(proto::ConnectionState connect_state) {
   if (connect_state_ != connect_state) {
     connect_state_ = connect_state;
-    logger_->LogSocketConnectState(channel_id_, connect_state_);
   }
 }
 
 void CastSocketImpl::SetReadyState(ReadyState ready_state) {
-  if (ready_state_ != ready_state) {
+  if (ready_state_ != ready_state)
     ready_state_ = ready_state;
-    logger_->LogSocketReadyState(channel_id_, ReadyStateToProto(ready_state_));
-  }
 }
 
 void CastSocketImpl::SetErrorState(ChannelError error_state) {
   VLOG_WITH_CONNECTION(1) << "SetErrorState " << error_state;
   DCHECK_EQ(CHANNEL_ERROR_NONE, error_state_);
   error_state_ = error_state;
-  logger_->LogSocketErrorState(channel_id_, ErrorStateToProto(error_state_));
   delegate_->OnError(error_state_);
 }
 }  // namespace cast_channel
diff --git a/extensions/browser/api/cast_channel/cast_socket.h b/extensions/browser/api/cast_channel/cast_socket.h
index 2fa1821..08a69b4 100644
--- a/extensions/browser/api/cast_channel/cast_socket.h
+++ b/extensions/browser/api/cast_channel/cast_socket.h
@@ -20,7 +20,6 @@
 #include "extensions/browser/api/api_resource_manager.h"
 #include "extensions/browser/api/cast_channel/cast_socket.h"
 #include "extensions/browser/api/cast_channel/cast_transport.h"
-#include "extensions/browser/api/cast_channel/logger_util.h"
 #include "extensions/common/api/cast_channel.h"
 #include "extensions/common/api/cast_channel/logging.pb.h"
 #include "net/base/completion_callback.h"
diff --git a/extensions/browser/api/cast_channel/cast_socket_unittest.cc b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
index 48e60c8..2f99de0 100644
--- a/extensions/browser/api/cast_channel/cast_socket_unittest.cc
+++ b/extensions/browser/api/cast_channel/cast_socket_unittest.cc
@@ -18,7 +18,6 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_byteorder.h"
-#include "base/test/simple_test_clock.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/timer/mock_timer.h"
 #include "extensions/browser/api/cast_channel/cast_auth_util.h"
@@ -348,11 +347,7 @@
 
 class CastSocketTest : public testing::Test {
  public:
-  CastSocketTest()
-      : logger_(
-            new Logger(base::WrapUnique<base::Clock>(new base::SimpleTestClock),
-                       base::Time())),
-        delegate_(new MockDelegate) {}
+  CastSocketTest() : logger_(new Logger()), delegate_(new MockDelegate) {}
   ~CastSocketTest() override {}
 
   void SetUp() override { EXPECT_CALL(*delegate_, OnMessage(_)).Times(0); }
diff --git a/extensions/browser/api/cast_channel/cast_transport.cc b/extensions/browser/api/cast_channel/cast_transport.cc
index 04ab8f2..1bfbb336 100644
--- a/extensions/browser/api/cast_channel/cast_transport.cc
+++ b/extensions/browser/api/cast_channel/cast_transport.cc
@@ -20,7 +20,6 @@
 #include "extensions/browser/api/cast_channel/cast_framer.h"
 #include "extensions/browser/api/cast_channel/cast_message_util.h"
 #include "extensions/browser/api/cast_channel/logger.h"
-#include "extensions/browser/api/cast_channel/logger_util.h"
 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
 #include "net/base/net_errors.h"
 #include "net/socket/socket.h"
@@ -169,9 +168,6 @@
   DCHECK(CalledOnValidThread());
   std::string serialized_message;
   if (!MessageFramer::Serialize(message, &serialized_message)) {
-    logger_->LogSocketEventForMessage(channel_id_, proto::SEND_MESSAGE_FAILED,
-                                      message.namespace_(),
-                                      "Error when serializing message.");
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, net::ERR_FAILED));
     return;
@@ -180,9 +176,6 @@
       message.namespace_(), serialized_message, callback);
 
   write_queue_.push(write_request);
-  logger_->LogSocketEventForMessage(
-      channel_id_, proto::MESSAGE_ENQUEUED, message.namespace_(),
-      base::StringPrintf("Queue size: %" PRIuS, write_queue_.size()));
   if (write_state_ == WRITE_STATE_IDLE) {
     SetWriteState(WRITE_STATE_WRITE);
     OnWriteResult(net::OK);
@@ -206,17 +199,13 @@
 }
 
 void CastTransportImpl::SetReadState(ReadState read_state) {
-  if (read_state_ != read_state) {
+  if (read_state_ != read_state)
     read_state_ = read_state;
-    logger_->LogSocketReadState(channel_id_, ReadStateToProto(read_state_));
-  }
 }
 
 void CastTransportImpl::SetWriteState(WriteState write_state) {
-  if (write_state_ != write_state) {
+  if (write_state_ != write_state)
     write_state_ = write_state;
-    logger_->LogSocketWriteState(channel_id_, WriteStateToProto(write_state_));
-  }
 }
 
 void CastTransportImpl::SetErrorState(ChannelError error_state) {
@@ -267,15 +256,11 @@
     }
   } while (rv != net::ERR_IO_PENDING && !IsTerminalWriteState(write_state_));
 
-  if (IsTerminalWriteState(write_state_)) {
-    logger_->LogSocketWriteState(channel_id_, WriteStateToProto(write_state_));
-
-    if (write_state_ == WRITE_STATE_ERROR) {
-      FlushWriteQueue();
-      DCHECK_NE(CHANNEL_ERROR_NONE, error_state_);
-      VLOG_WITH_CONNECTION(2) << "Sending OnError().";
-      delegate_->OnError(error_state_);
-    }
+  if (write_state_ == WRITE_STATE_ERROR) {
+    FlushWriteQueue();
+    DCHECK_NE(CHANNEL_ERROR_NONE, error_state_);
+    VLOG_WITH_CONNECTION(2) << "Sending OnError().";
+    delegate_->OnError(error_state_);
   }
 }
 
@@ -298,8 +283,8 @@
 int CastTransportImpl::DoWriteComplete(int result) {
   VLOG_WITH_CONNECTION(2) << "DoWriteComplete result=" << result;
   DCHECK(!write_queue_.empty());
-  logger_->LogSocketEventWithRv(channel_id_, proto::SOCKET_WRITE, result);
   if (result <= 0) {  // NOTE that 0 also indicates an error
+    logger_->LogSocketEventWithRv(channel_id_, proto::SOCKET_WRITE, result);
     SetErrorState(CHANNEL_ERROR_SOCKET_ERROR);
     SetWriteState(WRITE_STATE_HANDLE_ERROR);
     return result == 0 ? net::ERR_FAILED : result;
@@ -323,10 +308,6 @@
   DCHECK(!write_queue_.empty());
 
   WriteRequest& request = write_queue_.front();
-  int bytes_consumed = request.io_buffer->BytesConsumed();
-  logger_->LogSocketEventForMessage(
-      channel_id_, proto::MESSAGE_WRITTEN, request.message_namespace,
-      base::StringPrintf("Bytes: %d", bytes_consumed));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(request.callback, net::OK));
 
@@ -399,7 +380,6 @@
 
   if (IsTerminalReadState(read_state_)) {
     DCHECK_EQ(READ_STATE_ERROR, read_state_);
-    logger_->LogSocketReadState(channel_id_, ReadStateToProto(read_state_));
     VLOG_WITH_CONNECTION(2) << "Sending OnError().";
     delegate_->OnError(error_state_);
   }
@@ -421,8 +401,8 @@
 
 int CastTransportImpl::DoReadComplete(int result) {
   VLOG_WITH_CONNECTION(2) << "DoReadComplete result = " << result;
-  logger_->LogSocketEventWithRv(channel_id_, proto::SOCKET_READ, result);
   if (result <= 0) {
+    logger_->LogSocketEventWithRv(channel_id_, proto::SOCKET_READ, result);
     VLOG_WITH_CONNECTION(1) << "Read error, peer closed the socket.";
     SetErrorState(CHANNEL_ERROR_SOCKET_ERROR);
     SetReadState(READ_STATE_HANDLE_ERROR);
@@ -435,10 +415,6 @@
   current_message_ = framer_->Ingest(result, &message_size, &framing_error);
   if (current_message_.get() && (framing_error == CHANNEL_ERROR_NONE)) {
     DCHECK_GT(message_size, static_cast<size_t>(0));
-    logger_->LogSocketEventForMessage(
-        channel_id_, proto::MESSAGE_READ, current_message_->namespace_(),
-        base::StringPrintf("Message size: %u",
-                           static_cast<uint32_t>(message_size)));
     SetReadState(READ_STATE_DO_CALLBACK);
   } else if (framing_error != CHANNEL_ERROR_NONE) {
     DCHECK(!current_message_);
diff --git a/extensions/browser/api/cast_channel/cast_transport.h b/extensions/browser/api/cast_channel/cast_transport.h
index de9d294..d4e5805 100644
--- a/extensions/browser/api/cast_channel/cast_transport.h
+++ b/extensions/browser/api/cast_channel/cast_transport.h
@@ -16,10 +16,10 @@
 #include "extensions/common/api/cast_channel.h"
 #include "extensions/common/api/cast_channel/logging.pb.h"
 #include "net/base/completion_callback.h"
+#include "net/base/ip_endpoint.h"
 
 namespace net {
 class DrainableIOBuffer;
-class IPEndPoint;
 class DrainableIOBuffer;
 class GrowableIOBuffer;
 class Socket;
@@ -29,7 +29,6 @@
 namespace api {
 namespace cast_channel {
 class CastMessage;
-class Logger;
 class MessageFramer;
 
 class CastTransport {
diff --git a/extensions/browser/api/cast_channel/cast_transport_unittest.cc b/extensions/browser/api/cast_channel/cast_transport_unittest.cc
index 3884d61..aad1a9c1 100644
--- a/extensions/browser/api/cast_channel/cast_transport_unittest.cc
+++ b/extensions/browser/api/cast_channel/cast_transport_unittest.cc
@@ -18,7 +18,6 @@
 #include "extensions/browser/api/cast_channel/cast_socket.h"
 #include "extensions/browser/api/cast_channel/cast_test_util.h"
 #include "extensions/browser/api/cast_channel/logger.h"
-#include "extensions/browser/api/cast_channel/logger_util.h"
 #include "extensions/common/api/cast_channel/cast_channel.pb.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
@@ -147,10 +146,7 @@
 
 class CastTransportTest : public testing::Test {
  public:
-  CastTransportTest()
-      : logger_(
-            new Logger(base::WrapUnique<base::Clock>(new base::SimpleTestClock),
-                       base::Time())) {
+  CastTransportTest() : logger_(new Logger()) {
     delegate_ = new MockCastTransportDelegate;
     transport_.reset(new CastTransportImpl(&mock_socket_, kChannelId,
                                            CreateIPEndPointForTest(),
diff --git a/extensions/browser/api/cast_channel/keep_alive_delegate_unittest.cc b/extensions/browser/api/cast_channel/keep_alive_delegate_unittest.cc
index 061ba4d..d9e946b 100644
--- a/extensions/browser/api/cast_channel/keep_alive_delegate_unittest.cc
+++ b/extensions/browser/api/cast_channel/keep_alive_delegate_unittest.cc
@@ -10,7 +10,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/test/simple_test_clock.h"
 #include "base/timer/mock_timer.h"
 #include "extensions/browser/api/cast_channel/cast_test_util.h"
 #include "net/base/net_errors.h"
@@ -56,8 +55,7 @@
  protected:
   void SetUp() override {
     inner_delegate_ = new MockCastTransportDelegate;
-    logger_ = new Logger(
-        std::unique_ptr<base::Clock>(new base::SimpleTestClock), base::Time());
+    logger_ = new Logger();
     keep_alive_.reset(new KeepAliveDelegate(
         &socket_, logger_, base::WrapUnique(inner_delegate_),
         base::TimeDelta::FromMilliseconds(kTestPingTimeoutMillis),
diff --git a/extensions/browser/api/cast_channel/logger.cc b/extensions/browser/api/cast_channel/logger.cc
index 0c2453f4..f31a8496 100644
--- a/extensions/browser/api/cast_channel/logger.cc
+++ b/extensions/browser/api/cast_channel/logger.cc
@@ -11,27 +11,21 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
-#include "base/time/clock.h"
 #include "extensions/browser/api/cast_channel/cast_auth_util.h"
 #include "extensions/browser/api/cast_channel/cast_socket.h"
-#include "extensions/browser/api/cast_channel/logger_util.h"
 #include "net/base/net_errors.h"
-#include "third_party/zlib/zlib.h"
 
 namespace extensions {
 namespace api {
 namespace cast_channel {
 
 using net::IPEndPoint;
-using proto::AggregatedSocketEvent;
 using proto::EventType;
 using proto::Log;
 using proto::SocketEvent;
 
 namespace {
 
-const char kInternalNamespacePrefix[] = "com.google.cast";
-
 proto::ChallengeReplyErrorType ChallegeReplyErrorToProto(
     AuthResult::ErrorType error_type) {
   switch (error_type) {
@@ -75,44 +69,6 @@
   }
 }
 
-std::unique_ptr<char[]> Compress(const std::string& input, size_t* length) {
-  *length = 0;
-  z_stream stream = {0};
-  int result = deflateInit2(&stream,
-                            Z_DEFAULT_COMPRESSION,
-                            Z_DEFLATED,
-                            // 16 is added to produce a gzip header + trailer.
-                            MAX_WBITS + 16,
-                            8,  // memLevel = 8 is default.
-                            Z_DEFAULT_STRATEGY);
-  DCHECK_EQ(Z_OK, result);
-
-  size_t out_size = deflateBound(&stream, input.size());
-  std::unique_ptr<char[]> out(new char[out_size]);
-
-  stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(input.data()));
-  stream.avail_in = input.size();
-  stream.next_out = reinterpret_cast<uint8_t*>(out.get());
-  stream.avail_out = out_size;
-
-  // Do a one-shot compression. This will return Z_STREAM_END only if |output|
-  // is large enough to hold all compressed data.
-  result = deflate(&stream, Z_FINISH);
-
-  bool success = (result == Z_STREAM_END);
-
-  if (!success)
-    VLOG(2) << "deflate() failed. Result: " << result;
-
-  result = deflateEnd(&stream);
-  DCHECK(result == Z_OK || result == Z_DATA_ERROR);
-
-  if (success)
-    *length = out_size - stream.avail_out;
-
-  return out;
-}
-
 // Propagate any error fields set in |event| to |last_errors|.  If any error
 // field in |event| is set, then also set |last_errors->event_type|.
 void MaybeSetLastErrors(const SocketEvent& event, LastErrors* last_errors) {
@@ -130,16 +86,14 @@
 
 }  // namespace
 
-Logger::AggregatedSocketEventLog::AggregatedSocketEventLog() {
-}
+LastErrors::LastErrors()
+    : event_type(proto::EVENT_TYPE_UNKNOWN),
+      challenge_reply_error_type(proto::CHALLENGE_REPLY_ERROR_NONE),
+      net_return_value(net::OK) {}
 
-Logger::AggregatedSocketEventLog::~AggregatedSocketEventLog() {
-}
+LastErrors::~LastErrors() {}
 
-Logger::Logger(std::unique_ptr<base::Clock> clock, base::Time unix_epoch_time)
-    : clock_(std::move(clock)), unix_epoch_time_(unix_epoch_time) {
-  DCHECK(clock_);
-
+Logger::Logger() {
   // Logger may not be necessarily be created on the IO thread, but logging
   // happens exclusively there.
   thread_checker_.DetachFromThread();
@@ -148,37 +102,6 @@
 Logger::~Logger() {
 }
 
-void Logger::LogNewSocketEvent(const CastSocket& cast_socket) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  SocketEvent event = CreateEvent(proto::CAST_SOCKET_CREATED);
-  AggregatedSocketEvent& aggregated_socket_event =
-      LogSocketEvent(cast_socket.id(), event);
-
-  const net::IPAddress& ip = cast_socket.ip_endpoint().address();
-  DCHECK(ip.IsValid());
-  aggregated_socket_event.set_endpoint_id(ip.bytes().back());
-  aggregated_socket_event.set_channel_auth_type(proto::SSL_VERIFIED);
-}
-
-void Logger::LogSocketEvent(int channel_id, EventType event_type) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  LogSocketEventWithDetails(channel_id, event_type, std::string());
-}
-
-void Logger::LogSocketEventWithDetails(int channel_id,
-                                       EventType event_type,
-                                       const std::string& details) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  SocketEvent event = CreateEvent(event_type);
-  if (!details.empty())
-    event.set_details(details);
-
-  LogSocketEvent(channel_id, event);
-}
-
 void Logger::LogSocketEventWithRv(int channel_id,
                                   EventType event_type,
                                   int rv) {
@@ -187,79 +110,6 @@
   SocketEvent event = CreateEvent(event_type);
   event.set_net_return_value(rv);
 
-  AggregatedSocketEvent& aggregated_socket_event =
-      LogSocketEvent(channel_id, event);
-
-  if ((event_type == proto::SOCKET_READ || event_type == proto::SOCKET_WRITE) &&
-      rv > 0) {
-    if (event_type == proto::SOCKET_READ) {
-      aggregated_socket_event.set_bytes_read(
-          aggregated_socket_event.bytes_read() + rv);
-    } else {
-      aggregated_socket_event.set_bytes_written(
-          aggregated_socket_event.bytes_written() + rv);
-    }
-  }
-}
-
-void Logger::LogSocketReadyState(int channel_id, proto::ReadyState new_state) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  SocketEvent event = CreateEvent(proto::READY_STATE_CHANGED);
-  event.set_ready_state(new_state);
-
-  LogSocketEvent(channel_id, event);
-}
-
-void Logger::LogSocketConnectState(int channel_id,
-                                   proto::ConnectionState new_state) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  SocketEvent event = CreateEvent(proto::CONNECTION_STATE_CHANGED);
-  event.set_connection_state(new_state);
-
-  LogSocketEvent(channel_id, event);
-}
-
-void Logger::LogSocketReadState(int channel_id, proto::ReadState new_state) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  SocketEvent event = CreateEvent(proto::READ_STATE_CHANGED);
-  event.set_read_state(new_state);
-
-  LogSocketEvent(channel_id, event);
-}
-
-void Logger::LogSocketWriteState(int channel_id, proto::WriteState new_state) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  SocketEvent event = CreateEvent(proto::WRITE_STATE_CHANGED);
-  event.set_write_state(new_state);
-
-  LogSocketEvent(channel_id, event);
-}
-
-void Logger::LogSocketErrorState(int channel_id, proto::ErrorState new_state) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  SocketEvent event = CreateEvent(proto::ERROR_STATE_CHANGED);
-  event.set_error_state(new_state);
-
-  LogSocketEvent(channel_id, event);
-}
-
-void Logger::LogSocketEventForMessage(int channel_id,
-                                      EventType event_type,
-                                      const std::string& message_namespace,
-                                      const std::string& details) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  SocketEvent event = CreateEvent(event_type);
-  if (base::StartsWith(message_namespace, kInternalNamespacePrefix,
-                       base::CompareCase::INSENSITIVE_ASCII))
-    event.set_message_namespace(message_namespace);
-  event.set_details(details);
-
   LogSocketEvent(channel_id, event);
 }
 
@@ -274,102 +124,33 @@
   LogSocketEvent(channel_id, event);
 }
 
-SocketEvent Logger::CreateEvent(EventType event_type) {
-  SocketEvent event;
-  event.set_type(event_type);
-  event.set_timestamp_micros(
-      (clock_->Now() - unix_epoch_time_).InMicroseconds());
-  return event;
-}
-
-AggregatedSocketEvent& Logger::LogSocketEvent(int channel_id,
-                                              const SocketEvent& socket_event) {
-  AggregatedSocketEventLogMap::iterator it =
-      aggregated_socket_events_.find(channel_id);
-  if (it == aggregated_socket_events_.end()) {
-    if (aggregated_socket_events_.size() >= kMaxSocketsToLog) {
-      AggregatedSocketEventLogMap::iterator erase_it =
-          aggregated_socket_events_.begin();
-
-      log_.set_num_evicted_aggregated_socket_events(
-          log_.num_evicted_aggregated_socket_events() + 1);
-      log_.set_num_evicted_socket_events(
-          log_.num_evicted_socket_events() +
-          erase_it->second->socket_events.size());
-
-      aggregated_socket_events_.erase(erase_it);
-    }
-
-    it = aggregated_socket_events_
-             .insert(std::make_pair(
-                 channel_id, base::MakeUnique<AggregatedSocketEventLog>()))
-             .first;
-    it->second->aggregated_socket_event.set_id(channel_id);
-  }
-
-  std::deque<proto::SocketEvent>& socket_events = it->second->socket_events;
-  if (socket_events.size() >= kMaxEventsPerSocket) {
-    socket_events.pop_front();
-    log_.set_num_evicted_socket_events(log_.num_evicted_socket_events() + 1);
-  }
-  socket_events.push_back(socket_event);
-
-  MaybeSetLastErrors(socket_event, &(it->second->last_errors));
-
-  return it->second->aggregated_socket_event;
-}
-
-std::unique_ptr<char[]> Logger::GetLogs(size_t* length) const {
-  *length = 0;
-
-  Log log;
-  // Copy "global" values from |log_|. Don't use |log_| directly since this
-  // function is const.
-  log.CopyFrom(log_);
-
-  for (AggregatedSocketEventLogMap::const_iterator it =
-           aggregated_socket_events_.begin();
-       it != aggregated_socket_events_.end();
-       ++it) {
-    AggregatedSocketEvent* new_aggregated_socket_event =
-        log.add_aggregated_socket_event();
-    new_aggregated_socket_event->CopyFrom(it->second->aggregated_socket_event);
-
-    const std::deque<SocketEvent>& socket_events = it->second->socket_events;
-    for (std::deque<SocketEvent>::const_iterator socket_event_it =
-             socket_events.begin();
-         socket_event_it != socket_events.end();
-         ++socket_event_it) {
-      SocketEvent* socket_event =
-          new_aggregated_socket_event->add_socket_event();
-      socket_event->CopyFrom(*socket_event_it);
-    }
-  }
-
-  std::string serialized;
-  if (!log.SerializeToString(&serialized)) {
-    VLOG(2) << "Failed to serialized proto to string.";
-    return std::unique_ptr<char[]>();
-  }
-
-  return Compress(serialized, length);
-}
-
-void Logger::Reset() {
-  aggregated_socket_events_.clear();
-  log_.Clear();
-}
-
 LastErrors Logger::GetLastErrors(int channel_id) const {
-  AggregatedSocketEventLogMap::const_iterator it =
-      aggregated_socket_events_.find(channel_id);
-  if (it != aggregated_socket_events_.end()) {
-    return it->second->last_errors;
+  LastErrorsMap::const_iterator it = last_errors_.find(channel_id);
+  if (it != last_errors_.end()) {
+    return it->second;
   } else {
     return LastErrors();
   }
 }
 
+void Logger::ClearLastErrors(int channel_id) {
+  last_errors_.erase(channel_id);
+}
+
+SocketEvent Logger::CreateEvent(EventType event_type) {
+  SocketEvent event;
+  event.set_type(event_type);
+  return event;
+}
+
+void Logger::LogSocketEvent(int channel_id, const SocketEvent& socket_event) {
+  LastErrorsMap::iterator it = last_errors_.find(channel_id);
+  if (it == last_errors_.end())
+    last_errors_[channel_id] = LastErrors();
+
+  MaybeSetLastErrors(socket_event, &last_errors_[channel_id]);
+}
+
 }  // namespace cast_channel
 }  // namespace api
 }  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/logger.h b/extensions/browser/api/cast_channel/logger.h
index 905ba8b8..a1f3efe 100644
--- a/extensions/browser/api/cast_channel/logger.h
+++ b/extensions/browser/api/cast_channel/logger.h
@@ -15,125 +15,66 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
-#include "extensions/browser/api/cast_channel/logger_util.h"
 #include "extensions/common/api/cast_channel/logging.pb.h"
-#include "net/base/ip_endpoint.h"
 
-namespace base {
-class Clock;
-}
 
 namespace extensions {
 namespace api {
 namespace cast_channel {
 
 struct AuthResult;
-class CastSocket;
 
-static const int kMaxSocketsToLog = 50;
-static const int kMaxEventsPerSocket = 2000;
+// Holds the most recent errors encountered by a CastSocket.
+struct LastErrors {
+ public:
+  LastErrors();
+  ~LastErrors();
 
-// Logs information of each channel and sockets and exports the log as
-// a blob. Logger is done on the IO thread.
+  // The most recent event that occurred at the time of the error.
+  proto::EventType event_type;
+
+  // The most recent ChallengeReplyErrorType logged for the socket.
+  proto::ChallengeReplyErrorType challenge_reply_error_type;
+
+  // The most recent net_return_value logged for the socket.
+  int net_return_value;
+};
+
+// Called with events that occur on a Cast Channel and remembers any that
+// warrant reporting to the caller in LastErrors.
 class Logger : public base::RefCountedThreadSafe<Logger> {
  public:
-  // |clock|: Clock used for generating timestamps for the events. Owned by
-  // this class.
-  // |unix_epoch_time|: The Time that corresponds to the Unix epoch.
-  // Can be set to other values (e.g. zero) for testing purposes.
-  //
-  // See crbug.com/518951 for information on why base::Clock
-  // is used instead of base::TickClock.
-  Logger(std::unique_ptr<base::Clock> clock, base::Time unix_epoch_time);
-
-  // For newly created sockets. Will create an event and log a
-  // CAST_SOCKET_CREATED event.
-  void LogNewSocketEvent(const CastSocket& cast_socket);
-
-  void LogSocketEvent(int channel_id, proto::EventType event_type);
-  void LogSocketEventWithDetails(int channel_id,
-                                 proto::EventType event_type,
-                                 const std::string& details);
+  Logger();
 
   // For events that involves socket / crypto operations that returns a value.
   void LogSocketEventWithRv(int channel_id,
                             proto::EventType event_type,
                             int rv);
 
-  // For *_STATE_CHANGED events.
-  void LogSocketReadyState(int channel_id, proto::ReadyState new_state);
-  void LogSocketConnectState(int channel_id, proto::ConnectionState new_state);
-  void LogSocketReadState(int channel_id, proto::ReadState new_state);
-  void LogSocketWriteState(int channel_id, proto::WriteState new_state);
-  void LogSocketErrorState(int channel_id, proto::ErrorState new_state);
-
   // For AUTH_CHALLENGE_REPLY event.
   void LogSocketChallengeReplyEvent(int channel_id,
                                     const AuthResult& auth_result);
 
-  void LogSocketEventForMessage(int channel_id,
-                                proto::EventType event_type,
-                                const std::string& message_namespace,
-                                const std::string& details);
-
-  // Assembles logs collected so far and return it as a serialized Log proto,
-  // compressed in gzip format.
-  // If serialization or compression failed, returns nullptr.
-  // |length|: If successful, assigned with size of compressed content.
-  std::unique_ptr<char[]> GetLogs(size_t* length) const;
-
-  // Clears the internal map.
-  void Reset();
-
-  // Returns the last errors logged for |channel_id|.  If the the logs for
-  // |channel_id| are evicted before this is called, returns a LastErrors with
-  // no errors.  This may happen if errors are logged and retrieved in different
-  // tasks.
+  // Returns the last errors logged for |channel_id|.
   LastErrors GetLastErrors(int channel_id) const;
 
+  // Removes a LastErrors entry for |channel_id| if one exists.
+  void ClearLastErrors(int channel_id);
+
  private:
   friend class base::RefCountedThreadSafe<Logger>;
   ~Logger();
 
-  struct AggregatedSocketEventLog {
-   public:
-    AggregatedSocketEventLog();
-    ~AggregatedSocketEventLog();
-
-    // Partially constructed AggregatedSocketEvent proto populated by Logger.
-    // Contains top level info such as channel ID, IP end point and channel
-    // auth type.
-    proto::AggregatedSocketEvent aggregated_socket_event;
-    // Events to be assigned to the AggregatedSocketEvent proto. Contains the
-    // most recent |kMaxEventsPerSocket| entries. The oldest events are
-    // evicted as new events are logged.
-    std::deque<proto::SocketEvent> socket_events;
-
-    // The most recent errors logged for the socket.
-    LastErrors last_errors;
-  };
-
-  using AggregatedSocketEventLogMap =
-      std::map<int, std::unique_ptr<AggregatedSocketEventLog>>;
+  using LastErrorsMap = std::map<int, LastErrors>;
 
   // Returns a SocketEvent proto with common fields (EventType, timestamp)
   // populated.
   proto::SocketEvent CreateEvent(proto::EventType event_type);
 
-  // Records |event| associated with |channel_id|.
-  // If the internal map is already logging maximum number of sockets and this
-  // is a new socket, the socket with the smallest channel id will be discarded.
-  // Returns a reference to the AggregatedSocketEvent proto created/modified.
-  proto::AggregatedSocketEvent& LogSocketEvent(
-      int channel_id,
-      const proto::SocketEvent& socket_event);
+  // Uses |event| associated with |channel_id| to update its LastErrors.
+  void LogSocketEvent(int channel_id, const proto::SocketEvent& socket_event);
 
-  std::unique_ptr<base::Clock> clock_;
-  AggregatedSocketEventLogMap aggregated_socket_events_;
-  base::Time unix_epoch_time_;
-
-  // Log proto holding global statistics.
-  proto::Log log_;
+  LastErrorsMap last_errors_;
 
   base::ThreadChecker thread_checker_;
 
diff --git a/extensions/browser/api/cast_channel/logger_unittest.cc b/extensions/browser/api/cast_channel/logger_unittest.cc
index 6909644..cf99f6a 100644
--- a/extensions/browser/api/cast_channel/logger_unittest.cc
+++ b/extensions/browser/api/cast_channel/logger_unittest.cc
@@ -7,321 +7,65 @@
 
 #include <string>
 
-#include "base/test/simple_test_clock.h"
 #include "extensions/browser/api/cast_channel/cast_auth_util.h"
 #include "extensions/browser/api/cast_channel/logger.h"
-#include "extensions/browser/api/cast_channel/logger_util.h"
 #include "net/base/net_errors.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/zlib/zlib.h"
 
 namespace extensions {
 namespace api {
 namespace cast_channel {
 
-using proto::AggregatedSocketEvent;
 using proto::EventType;
 using proto::Log;
 using proto::SocketEvent;
 
-class CastChannelLoggerTest : public testing::Test {
- public:
-  // |logger_| will take ownership of |clock_|.
-  CastChannelLoggerTest()
-      : clock_(new base::SimpleTestClock),
-        logger_(
-            new Logger(std::unique_ptr<base::Clock>(clock_), base::Time())) {}
-  ~CastChannelLoggerTest() override {}
+TEST(CastChannelLoggerTest, LogLastErrorEvents) {
+  scoped_refptr<Logger> logger(new Logger());
 
-  bool Uncompress(const char* input, int length, std::string* output) {
-    z_stream stream = {0};
-
-    stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(input));
-    stream.avail_in = length;
-    stream.next_out = reinterpret_cast<uint8_t*>(&(*output)[0]);
-    stream.avail_out = output->size();
-
-    bool success = false;
-    while (stream.avail_in > 0 && stream.avail_out > 0) {
-      // 16 is added to read in gzip format.
-      int result = inflateInit2(&stream, MAX_WBITS + 16);
-      DCHECK_EQ(Z_OK, result);
-
-      result = inflate(&stream, Z_FINISH);
-      success = (result == Z_STREAM_END);
-      if (!success) {
-        DVLOG(2) << "inflate() failed. Result: " << result;
-        break;
-      }
-
-      result = inflateEnd(&stream);
-      DCHECK(result == Z_OK);
-    }
-
-    if (stream.avail_in == 0) {
-      success = true;
-      output->resize(output->size() - stream.avail_out);
-    }
-    return success;
-  }
-
-  std::unique_ptr<Log> GetLog() {
-    size_t length = 0;
-    std::unique_ptr<char[]> output = logger_->GetLogs(&length);
-    if (!output.get())
-      return std::unique_ptr<Log>();
-
-    // 20kb should be enough for test purposes.
-    std::string uncompressed(20000, 0);
-    if (!Uncompress(output.get(), length, &uncompressed))
-      return std::unique_ptr<Log>();
-
-    std::unique_ptr<Log> log(new Log);
-    if (!log->ParseFromString(uncompressed))
-      return std::unique_ptr<Log>();
-
-    return log;
-  }
-
- protected:
-  base::SimpleTestClock* clock_;
-  scoped_refptr<Logger> logger_;
-};
-
-TEST_F(CastChannelLoggerTest, BasicLogging) {
-  logger_->LogSocketEvent(1, EventType::CAST_SOCKET_CREATED);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithDetails(
-      1, EventType::TCP_SOCKET_CONNECT, "TCP socket");
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEvent(2, EventType::CAST_SOCKET_CREATED);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithRv(1, EventType::SSL_SOCKET_CONNECT, -1);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventForMessage(
-      2, EventType::MESSAGE_ENQUEUED, "foo_namespace", "details");
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-
-  AuthResult auth_result = AuthResult::CreateWithParseError(
-      "No response", AuthResult::ERROR_NO_RESPONSE);
-
-  logger_->LogSocketChallengeReplyEvent(2, auth_result);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-
-  auth_result =
-      AuthResult("Parsing failed", AuthResult::ERROR_CERT_PARSING_FAILED);
-  logger_->LogSocketChallengeReplyEvent(2, auth_result);
-
-  LastErrors last_errors = logger_->GetLastErrors(2);
-  EXPECT_EQ(last_errors.event_type, proto::AUTH_CHALLENGE_REPLY);
-  EXPECT_EQ(last_errors.net_return_value, net::OK);
-  EXPECT_EQ(last_errors.challenge_reply_error_type,
-            proto::CHALLENGE_REPLY_ERROR_CERT_PARSING_FAILED);
-
-  std::unique_ptr<Log> log = GetLog();
-  ASSERT_TRUE(log);
-
-  ASSERT_EQ(2, log->aggregated_socket_event_size());
-  {
-    const AggregatedSocketEvent& aggregated_socket_event =
-        log->aggregated_socket_event(0);
-    EXPECT_EQ(1, aggregated_socket_event.id());
-    EXPECT_EQ(3, aggregated_socket_event.socket_event_size());
-    {
-      const SocketEvent& event = aggregated_socket_event.socket_event(0);
-      EXPECT_EQ(EventType::CAST_SOCKET_CREATED, event.type());
-      EXPECT_EQ(0, event.timestamp_micros());
-    }
-    {
-      const SocketEvent& event = aggregated_socket_event.socket_event(1);
-      EXPECT_EQ(EventType::TCP_SOCKET_CONNECT, event.type());
-      EXPECT_EQ(1, event.timestamp_micros());
-      EXPECT_EQ("TCP socket", event.details());
-    }
-    {
-      const SocketEvent& event = aggregated_socket_event.socket_event(2);
-      EXPECT_EQ(EventType::SSL_SOCKET_CONNECT, event.type());
-      EXPECT_EQ(3, event.timestamp_micros());
-      EXPECT_EQ(-1, event.net_return_value());
-    }
-  }
-  {
-    const AggregatedSocketEvent& aggregated_socket_event =
-        log->aggregated_socket_event(1);
-    EXPECT_EQ(2, aggregated_socket_event.id());
-    EXPECT_EQ(4, aggregated_socket_event.socket_event_size());
-    {
-      const SocketEvent& event = aggregated_socket_event.socket_event(0);
-      EXPECT_EQ(EventType::CAST_SOCKET_CREATED, event.type());
-      EXPECT_EQ(2, event.timestamp_micros());
-    }
-    {
-      const SocketEvent& event = aggregated_socket_event.socket_event(1);
-      EXPECT_EQ(EventType::MESSAGE_ENQUEUED, event.type());
-      EXPECT_EQ(4, event.timestamp_micros());
-      EXPECT_FALSE(event.has_message_namespace());
-      EXPECT_EQ("details", event.details());
-    }
-    {
-      const SocketEvent& event = aggregated_socket_event.socket_event(2);
-      EXPECT_EQ(EventType::AUTH_CHALLENGE_REPLY, event.type());
-      EXPECT_EQ(5, event.timestamp_micros());
-      EXPECT_EQ(proto::CHALLENGE_REPLY_ERROR_NO_RESPONSE,
-                event.challenge_reply_error_type());
-      EXPECT_FALSE(event.has_net_return_value());
-      EXPECT_FALSE(event.has_nss_error_code());
-    }
-    {
-      const SocketEvent& event = aggregated_socket_event.socket_event(3);
-      EXPECT_EQ(EventType::AUTH_CHALLENGE_REPLY, event.type());
-      EXPECT_EQ(6, event.timestamp_micros());
-      EXPECT_EQ(proto::CHALLENGE_REPLY_ERROR_CERT_PARSING_FAILED,
-                event.challenge_reply_error_type());
-      EXPECT_FALSE(event.has_net_return_value());
-      EXPECT_FALSE(event.has_nss_error_code());
-    }
-  }
-}
-
-TEST_F(CastChannelLoggerTest, LogLastErrorEvents) {
   // Net return value is set to an error
-  logger_->LogSocketEventWithRv(
-      1, EventType::TCP_SOCKET_CONNECT, net::ERR_CONNECTION_FAILED);
+  logger->LogSocketEventWithRv(1, EventType::TCP_SOCKET_CONNECT,
+                               net::ERR_CONNECTION_FAILED);
 
-  LastErrors last_errors = logger_->GetLastErrors(1);
+  LastErrors last_errors = logger->GetLastErrors(1);
   EXPECT_EQ(last_errors.event_type, proto::TCP_SOCKET_CONNECT);
   EXPECT_EQ(last_errors.net_return_value, net::ERR_CONNECTION_FAILED);
 
   // Challenge reply error set
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
   AuthResult auth_result = AuthResult::CreateWithParseError(
       "Some error", AuthResult::ErrorType::ERROR_PEER_CERT_EMPTY);
 
-  logger_->LogSocketChallengeReplyEvent(2, auth_result);
-  last_errors = logger_->GetLastErrors(2);
+  logger->LogSocketChallengeReplyEvent(2, auth_result);
+  last_errors = logger->GetLastErrors(2);
   EXPECT_EQ(last_errors.event_type, proto::AUTH_CHALLENGE_REPLY);
   EXPECT_EQ(last_errors.challenge_reply_error_type,
             proto::CHALLENGE_REPLY_ERROR_PEER_CERT_EMPTY);
 
   // Logging a non-error event does not set the LastErrors for the channel.
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithRv(3, EventType::TCP_SOCKET_CONNECT, net::OK);
-  last_errors = logger_->GetLastErrors(3);
+  logger->LogSocketEventWithRv(3, EventType::TCP_SOCKET_CONNECT, net::OK);
+  last_errors = logger->GetLastErrors(3);
   EXPECT_EQ(last_errors.event_type, proto::EVENT_TYPE_UNKNOWN);
   EXPECT_EQ(last_errors.net_return_value, net::OK);
   EXPECT_EQ(last_errors.challenge_reply_error_type,
             proto::CHALLENGE_REPLY_ERROR_NONE);
 
   // Now log a challenge reply error.  LastErrors will be set.
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
   auth_result =
       AuthResult("Some error failed", AuthResult::ERROR_WRONG_PAYLOAD_TYPE);
-  logger_->LogSocketChallengeReplyEvent(3, auth_result);
-  last_errors = logger_->GetLastErrors(3);
+  logger->LogSocketChallengeReplyEvent(3, auth_result);
+  last_errors = logger->GetLastErrors(3);
   EXPECT_EQ(last_errors.event_type, proto::AUTH_CHALLENGE_REPLY);
   EXPECT_EQ(last_errors.challenge_reply_error_type,
             proto::CHALLENGE_REPLY_ERROR_WRONG_PAYLOAD_TYPE);
 
   // Logging a non-error event does not change the LastErrors for the channel.
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithRv(3, EventType::TCP_SOCKET_CONNECT, net::OK);
-  last_errors = logger_->GetLastErrors(3);
+  logger->LogSocketEventWithRv(3, EventType::TCP_SOCKET_CONNECT, net::OK);
+  last_errors = logger->GetLastErrors(3);
   EXPECT_EQ(last_errors.event_type, proto::AUTH_CHALLENGE_REPLY);
   EXPECT_EQ(last_errors.challenge_reply_error_type,
             proto::CHALLENGE_REPLY_ERROR_WRONG_PAYLOAD_TYPE);
 }
 
-TEST_F(CastChannelLoggerTest, LogSocketReadWrite) {
-  logger_->LogSocketEventWithRv(1, EventType::SOCKET_READ, 50);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithRv(1, EventType::SOCKET_READ, 30);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithRv(1, EventType::SOCKET_READ, -1);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithRv(1, EventType::SOCKET_WRITE, 20);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-
-  logger_->LogSocketEventWithRv(2, EventType::SOCKET_READ, 100);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithRv(2, EventType::SOCKET_WRITE, 100);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  logger_->LogSocketEventWithRv(2, EventType::SOCKET_WRITE, -5);
-  clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-
-  std::unique_ptr<Log> log = GetLog();
-  ASSERT_TRUE(log);
-
-  ASSERT_EQ(2, log->aggregated_socket_event_size());
-  {
-    const AggregatedSocketEvent& aggregated_socket_event =
-        log->aggregated_socket_event(0);
-    EXPECT_EQ(1, aggregated_socket_event.id());
-    EXPECT_EQ(4, aggregated_socket_event.socket_event_size());
-    EXPECT_EQ(80, aggregated_socket_event.bytes_read());
-    EXPECT_EQ(20, aggregated_socket_event.bytes_written());
-  }
-  {
-    const AggregatedSocketEvent& aggregated_socket_event =
-        log->aggregated_socket_event(1);
-    EXPECT_EQ(2, aggregated_socket_event.id());
-    EXPECT_EQ(3, aggregated_socket_event.socket_event_size());
-    EXPECT_EQ(100, aggregated_socket_event.bytes_read());
-    EXPECT_EQ(100, aggregated_socket_event.bytes_written());
-  }
-}
-
-TEST_F(CastChannelLoggerTest, TooManySockets) {
-  for (int i = 0; i < kMaxSocketsToLog + 5; i++) {
-    logger_->LogSocketEvent(i, EventType::CAST_SOCKET_CREATED);
-  }
-
-  std::unique_ptr<Log> log = GetLog();
-  ASSERT_TRUE(log);
-
-  ASSERT_EQ(kMaxSocketsToLog, log->aggregated_socket_event_size());
-  EXPECT_EQ(5, log->num_evicted_aggregated_socket_events());
-  EXPECT_EQ(5, log->num_evicted_socket_events());
-
-  const AggregatedSocketEvent& aggregated_socket_event =
-      log->aggregated_socket_event(0);
-  EXPECT_EQ(5, aggregated_socket_event.id());
-}
-
-TEST_F(CastChannelLoggerTest, TooManyEvents) {
-  for (int i = 0; i < kMaxEventsPerSocket + 5; i++) {
-    logger_->LogSocketEvent(1, EventType::CAST_SOCKET_CREATED);
-    clock_->Advance(base::TimeDelta::FromMicroseconds(1));
-  }
-
-  std::unique_ptr<Log> log = GetLog();
-  ASSERT_TRUE(log);
-
-  ASSERT_EQ(1, log->aggregated_socket_event_size());
-  EXPECT_EQ(0, log->num_evicted_aggregated_socket_events());
-  EXPECT_EQ(5, log->num_evicted_socket_events());
-
-  const AggregatedSocketEvent& aggregated_socket_event =
-      log->aggregated_socket_event(0);
-  ASSERT_EQ(kMaxEventsPerSocket, aggregated_socket_event.socket_event_size());
-  EXPECT_EQ(5, aggregated_socket_event.socket_event(0).timestamp_micros());
-}
-
-TEST_F(CastChannelLoggerTest, Reset) {
-  logger_->LogSocketEvent(1, EventType::CAST_SOCKET_CREATED);
-
-  std::unique_ptr<Log> log = GetLog();
-  ASSERT_TRUE(log);
-
-  EXPECT_EQ(1, log->aggregated_socket_event_size());
-
-  logger_->Reset();
-
-  log = GetLog();
-  ASSERT_TRUE(log);
-
-  EXPECT_EQ(0, log->aggregated_socket_event_size());
-}
-
 }  // namespace cast_channel
 }  // namespace api
 }  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/logger_util.cc b/extensions/browser/api/cast_channel/logger_util.cc
deleted file mode 100644
index 35e2c10..0000000
--- a/extensions/browser/api/cast_channel/logger_util.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/browser/api/cast_channel/logger_util.h"
-#include "extensions/common/api/cast_channel/logging.pb.h"
-#include "net/base/net_errors.h"
-
-namespace extensions {
-namespace api {
-namespace cast_channel {
-LastErrors::LastErrors()
-    : event_type(proto::EVENT_TYPE_UNKNOWN),
-      challenge_reply_error_type(proto::CHALLENGE_REPLY_ERROR_NONE),
-      net_return_value(net::OK) {}
-
-LastErrors::~LastErrors() {
-}
-
-proto::ErrorState ErrorStateToProto(ChannelError state) {
-  switch (state) {
-    case CHANNEL_ERROR_NONE:
-      return proto::CHANNEL_ERROR_NONE;
-    case CHANNEL_ERROR_CHANNEL_NOT_OPEN:
-      return proto::CHANNEL_ERROR_CHANNEL_NOT_OPEN;
-    case CHANNEL_ERROR_AUTHENTICATION_ERROR:
-      return proto::CHANNEL_ERROR_AUTHENTICATION_ERROR;
-    case CHANNEL_ERROR_CONNECT_ERROR:
-      return proto::CHANNEL_ERROR_CONNECT_ERROR;
-    case CHANNEL_ERROR_SOCKET_ERROR:
-      return proto::CHANNEL_ERROR_SOCKET_ERROR;
-    case CHANNEL_ERROR_TRANSPORT_ERROR:
-      return proto::CHANNEL_ERROR_TRANSPORT_ERROR;
-    case CHANNEL_ERROR_INVALID_MESSAGE:
-      return proto::CHANNEL_ERROR_INVALID_MESSAGE;
-    case CHANNEL_ERROR_INVALID_CHANNEL_ID:
-      return proto::CHANNEL_ERROR_INVALID_CHANNEL_ID;
-    case CHANNEL_ERROR_CONNECT_TIMEOUT:
-      return proto::CHANNEL_ERROR_CONNECT_TIMEOUT;
-    case CHANNEL_ERROR_UNKNOWN:
-      return proto::CHANNEL_ERROR_UNKNOWN;
-    default:
-      NOTREACHED();
-      return proto::CHANNEL_ERROR_NONE;
-  }
-}
-
-proto::ReadyState ReadyStateToProto(ReadyState state) {
-  switch (state) {
-    case READY_STATE_NONE:
-      return proto::READY_STATE_NONE;
-    case READY_STATE_CONNECTING:
-      return proto::READY_STATE_CONNECTING;
-    case READY_STATE_OPEN:
-      return proto::READY_STATE_OPEN;
-    case READY_STATE_CLOSING:
-      return proto::READY_STATE_CLOSING;
-    case READY_STATE_CLOSED:
-      return proto::READY_STATE_CLOSED;
-    default:
-      NOTREACHED();
-      return proto::READY_STATE_NONE;
-  }
-}
-}  // namespace cast_channel
-}  // namespace api
-}  // namespace extensions
diff --git a/extensions/browser/api/cast_channel/logger_util.h b/extensions/browser/api/cast_channel/logger_util.h
deleted file mode 100644
index 2b5de5b..0000000
--- a/extensions/browser/api/cast_channel/logger_util.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_BROWSER_API_CAST_CHANNEL_LOGGER_UTIL_H_
-#define EXTENSIONS_BROWSER_API_CAST_CHANNEL_LOGGER_UTIL_H_
-
-#include "extensions/common/api/cast_channel.h"
-#include "extensions/common/api/cast_channel/logging.pb.h"
-
-namespace extensions {
-namespace api {
-namespace cast_channel {
-// Converts an IDL "ChannelError" to a proto enum "ErrorState".
-proto::ErrorState ErrorStateToProto(ChannelError state);
-
-// Converts an IDL "ReadyState" to a proto enum "ReadyState".
-proto::ReadyState ReadyStateToProto(ReadyState state);
-
-// Holds the most recent errors encountered by a CastSocket.
-struct LastErrors {
- public:
-  LastErrors();
-  ~LastErrors();
-
-  // The most recent event that occurred at the time of the error.
-  proto::EventType event_type;
-
-  // The most recent ChallengeReplyErrorType logged for the socket.
-  proto::ChallengeReplyErrorType challenge_reply_error_type;
-
-  // The most recent net_return_value logged for the socket.
-  int net_return_value;
-};
-
-}  // namespace cast_channel
-}  // namespace api
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_API_CAST_CHANNEL_LOGGER_UTIL_H_
diff --git a/extensions/browser/api/file_handlers/BUILD.gn b/extensions/browser/api/file_handlers/BUILD.gn
new file mode 100644
index 0000000..012f6fc
--- /dev/null
+++ b/extensions/browser/api/file_handlers/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("file_handlers") {
+  sources = [
+    "app_file_handler_util.cc",
+    "app_file_handler_util.h",
+    "directory_util.cc",
+    "directory_util.h",
+    "mime_util.cc",
+    "mime_util.h",
+  ]
+
+  if (is_chromeos) {
+    sources += [ "non_native_file_system_delegate.h" ]
+  }
+
+  deps = [
+    "//base:base",
+    "//content/public/browser",
+    "//content/public/common",
+    "//extensions/common",
+    "//extensions/common/api",
+    "//net",
+    "//storage/browser",
+  ]
+}
diff --git a/extensions/browser/api/file_handlers/OWNERS b/extensions/browser/api/file_handlers/OWNERS
new file mode 100644
index 0000000..64f6677
--- /dev/null
+++ b/extensions/browser/api/file_handlers/OWNERS
@@ -0,0 +1,2 @@
+benwells@chromium.org
+sammc@chromium.org
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc b/extensions/browser/api/file_handlers/app_file_handler_util.cc
similarity index 95%
rename from chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
rename to extensions/browser/api/file_handlers/app_file_handler_util.cc
index 20dbf13..1e7daae 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
+++ b/extensions/browser/api/file_handlers/app_file_handler_util.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 "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "build/build_config.h"
-#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "extensions/browser/api/extensions_api_client.h"
@@ -102,7 +102,7 @@
  public:
   WritableFileChecker(
       const std::vector<base::FilePath>& paths,
-      Profile* profile,
+      content::BrowserContext* context,
       const std::set<base::FilePath>& directory_paths,
       const base::Closure& on_success,
       const base::Callback<void(const base::FilePath&)>& on_failure);
@@ -128,9 +128,9 @@
   void OnPrepareFileDone(const base::FilePath& path, bool success);
 
   const std::vector<base::FilePath> paths_;
-  Profile* profile_;
+  content::BrowserContext* context_;
   const std::set<base::FilePath> directory_paths_;
-  int outstanding_tasks_;
+  size_t outstanding_tasks_;
   base::FilePath error_path_;
   base::Closure on_success_;
   base::Callback<void(const base::FilePath&)> on_failure_;
@@ -138,12 +138,12 @@
 
 WritableFileChecker::WritableFileChecker(
     const std::vector<base::FilePath>& paths,
-    Profile* profile,
+    content::BrowserContext* context,
     const std::set<base::FilePath>& directory_paths,
     const base::Closure& on_success,
     const base::Callback<void(const base::FilePath&)>& on_failure)
     : paths_(paths),
-      profile_(profile),
+      context_(context),
       directory_paths_(directory_paths),
       outstanding_tasks_(1),
       on_success_(on_success),
@@ -156,16 +156,14 @@
 #if defined(OS_CHROMEOS)
     NonNativeFileSystemDelegate* delegate =
         ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate();
-    if (delegate && delegate->IsUnderNonNativeLocalPath(profile_, path)) {
+    if (delegate && delegate->IsUnderNonNativeLocalPath(context_, path)) {
       if (is_directory) {
         delegate->IsNonNativeLocalPathDirectory(
-            profile_,
-            path,
+            context_, path,
             base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
       } else {
         delegate->PrepareNonNativeLocalFileForWritableApp(
-            profile_,
-            path,
+            context_, path,
             base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
       }
       continue;
@@ -259,7 +257,7 @@
          FileHandlerCanHandleFileWithExtension(handler, entry.path);
 }
 
-GrantedFileEntry CreateFileEntry(Profile* profile,
+GrantedFileEntry CreateFileEntry(content::BrowserContext* context,
                                  const Extension* extension,
                                  int renderer_id,
                                  const base::FilePath& path,
@@ -291,12 +289,12 @@
 
 void PrepareFilesForWritableApp(
     const std::vector<base::FilePath>& paths,
-    Profile* profile,
+    content::BrowserContext* context,
     const std::set<base::FilePath>& directory_paths,
     const base::Closure& on_success,
     const base::Callback<void(const base::FilePath&)>& on_failure) {
   scoped_refptr<WritableFileChecker> checker(new WritableFileChecker(
-      paths, profile, directory_paths, on_success, on_failure));
+      paths, context, directory_paths, on_success, on_failure));
   checker->Check();
 }
 
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h b/extensions/browser/api/file_handlers/app_file_handler_util.h
similarity index 85%
rename from chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
rename to extensions/browser/api/file_handlers/app_file_handler_util.h
index 28d19db1..1951f11 100644
--- a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.h
+++ b/extensions/browser/api/file_handlers/app_file_handler_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_APP_FILE_HANDLER_UTIL_H_
-#define CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_APP_FILE_HANDLER_UTIL_H_
+#ifndef EXTENSIONS_BROWSER_API_FILE_HANDLERS_APP_FILE_HANDLER_UTIL_H_
+#define EXTENSIONS_BROWSER_API_FILE_HANDLERS_APP_FILE_HANDLER_UTIL_H_
 
 #include <set>
 #include <string>
@@ -14,7 +14,9 @@
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_handlers/file_handler_info.h"
 
-class Profile;
+namespace content {
+class BrowserContext;
+}
 
 namespace extensions {
 
@@ -22,7 +24,8 @@
 struct FileHandlerInfo;
 struct GrantedFileEntry;
 
-// TODO(benwells): move this to platform_apps namespace.
+// TODO(michaelpg,benwells): move this to an app-specific namespace and
+// directory.
 namespace app_file_handler_util {
 
 extern const char kInvalidParameters[];
@@ -43,7 +46,7 @@
 
 // Creates a new file entry and allows |renderer_id| to access |path|. This
 // registers a new file system for |path|.
-GrantedFileEntry CreateFileEntry(Profile* profile,
+GrantedFileEntry CreateFileEntry(content::BrowserContext* context,
                                  const Extension* extension,
                                  int renderer_id,
                                  const base::FilePath& path,
@@ -56,7 +59,7 @@
 // otherwise calls |on_failure|.
 void PrepareFilesForWritableApp(
     const std::vector<base::FilePath>& paths,
-    Profile* profile,
+    content::BrowserContext* context,
     const std::set<base::FilePath>& directory_paths,
     const base::Closure& on_success,
     const base::Callback<void(const base::FilePath&)>& on_failure);
@@ -76,4 +79,4 @@
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_APP_FILE_HANDLER_UTIL_H_
+#endif  // EXTENSIONS_BROWSER_API_FILE_HANDLERS_APP_FILE_HANDLER_UTIL_H_
diff --git a/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc b/extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc
similarity index 96%
rename from chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc
rename to extensions/browser/api/file_handlers/app_file_handler_util_unittest.cc
index 6454656f..dffb7ab 100644
--- a/chrome/browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc
+++ b/extensions/browser/api/file_handlers/app_file_handler_util_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 "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+#include "extensions/browser/api/file_handlers/app_file_handler_util.h"
 
 #include "extensions/browser/entry_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util.cc b/extensions/browser/api/file_handlers/directory_util.cc
similarity index 87%
rename from chrome/browser/extensions/api/file_handlers/directory_util.cc
rename to extensions/browser/api/file_handlers/directory_util.cc
index c01951e..516be8f 100644
--- a/chrome/browser/extensions/api/file_handlers/directory_util.cc
+++ b/extensions/browser/api/file_handlers/directory_util.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/file_handlers/directory_util.h"
+#include "extensions/browser/api/file_handlers/directory_util.h"
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/filename_util.h"
 #include "storage/browser/fileapi/file_system_url.h"
@@ -37,14 +37,14 @@
 // The callback parameter contains the result and is required to support
 // both native local directories to avoid UI thread and non native local
 // path directories for the IsNonNativeLocalPathDirectory API.
-void EntryIsDirectory(Profile* profile,
+void EntryIsDirectory(content::BrowserContext* context,
                       const base::FilePath& path,
                       const base::Callback<void(bool)>& callback) {
 #if defined(OS_CHROMEOS)
   NonNativeFileSystemDelegate* delegate =
       ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate();
-  if (delegate && delegate->IsUnderNonNativeLocalPath(profile, path)) {
-    delegate->IsNonNativeLocalPathDirectory(profile, path, callback);
+  if (delegate && delegate->IsUnderNonNativeLocalPath(context, path)) {
+    delegate->IsNonNativeLocalPathDirectory(context, path, callback);
     return;
   }
 #endif
@@ -61,8 +61,8 @@
 
 }  // namespace
 
-IsDirectoryCollector::IsDirectoryCollector(Profile* profile)
-    : profile_(profile), left_(0), weak_ptr_factory_(this) {}
+IsDirectoryCollector::IsDirectoryCollector(content::BrowserContext* context)
+    : context_(context), left_(0), weak_ptr_factory_(this) {}
 
 IsDirectoryCollector::~IsDirectoryCollector() {}
 
@@ -86,7 +86,7 @@
   }
 
   for (size_t i = 0; i < paths.size(); ++i) {
-    EntryIsDirectory(profile_, paths[i],
+    EntryIsDirectory(context_, paths[i],
                      base::Bind(&IsDirectoryCollector::OnIsDirectoryCollected,
                                 weak_ptr_factory_.GetWeakPtr(), i));
   }
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util.h b/extensions/browser/api/file_handlers/directory_util.h
similarity index 78%
rename from chrome/browser/extensions/api/file_handlers/directory_util.h
rename to extensions/browser/api/file_handlers/directory_util.h
index 2de5b471..7e76de5 100644
--- a/chrome/browser/extensions/api/file_handlers/directory_util.h
+++ b/extensions/browser/api/file_handlers/directory_util.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
-#define CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
+#ifndef EXTENSIONS_BROWSER_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
+#define EXTENSIONS_BROWSER_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
 
 #include <memory>
 #include <set>
@@ -14,7 +14,9 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 
-class Profile;
+namespace content {
+class BrowserContext;
+}
 
 namespace base {
 class FilePath;
@@ -28,7 +30,7 @@
   typedef base::Callback<void(std::unique_ptr<std::set<base::FilePath>>)>
       CompletionCallback;
 
-  explicit IsDirectoryCollector(Profile* profile);
+  explicit IsDirectoryCollector(content::BrowserContext* context);
   virtual ~IsDirectoryCollector();
 
   // For the given paths obtains a set with which of them are directories.
@@ -39,7 +41,7 @@
  private:
   void OnIsDirectoryCollected(size_t index, bool directory);
 
-  Profile* profile_;
+  content::BrowserContext* context_;
   std::vector<base::FilePath> paths_;
   std::unique_ptr<std::set<base::FilePath>> result_;
   size_t left_;
@@ -52,4 +54,4 @@
 }  // namespace app_file_handler_util
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
+#endif  // EXTENSIONS_BROWSER_API_FILE_HANDLERS_DIRECTORY_UTIL_H_
diff --git a/chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc b/extensions/browser/api/file_handlers/directory_util_unittest.cc
similarity index 85%
rename from chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc
rename to extensions/browser/api/file_handlers/directory_util_unittest.cc
index c9549c1..ff221a2 100644
--- a/chrome/browser/extensions/api/file_handlers/directory_util_unittest.cc
+++ b/extensions/browser/api/file_handlers/directory_util_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 "chrome/browser/extensions/api/file_handlers/directory_util.h"
+#include "extensions/browser/api/file_handlers/directory_util.h"
 
 #include <memory>
 #include <set>
@@ -12,10 +12,11 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/run_loop.h"
-#include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/api/extensions_api_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -44,7 +45,8 @@
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
+  ExtensionsAPIClient extensions_api_client_;
+  content::TestBrowserContext context_;
   base::FilePath dir_path_;
   base::FilePath file_path_;
 };
@@ -55,7 +57,7 @@
   paths.push_back(file_path_);
   paths.push_back(base::FilePath::FromUTF8Unsafe(kRandomPath));
 
-  IsDirectoryCollector collector(&profile_);
+  IsDirectoryCollector collector(&context_);
   std::set<base::FilePath> result;
   collector.CollectForEntriesPaths(
       paths, base::Bind(&OnCollectForEntriesPath, &result));
diff --git a/chrome/browser/extensions/api/file_handlers/mime_util.cc b/extensions/browser/api/file_handlers/mime_util.cc
similarity index 82%
rename from chrome/browser/extensions/api/file_handlers/mime_util.cc
rename to extensions/browser/api/file_handlers/mime_util.cc
index 82e3cf9..90a8841 100644
--- a/chrome/browser/extensions/api/file_handlers/mime_util.cc
+++ b/extensions/browser/api/file_handlers/mime_util.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 "chrome/browser/extensions/api/file_handlers/mime_util.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/filename_util.h"
 #include "net/base/mime_sniffer.h"
@@ -38,11 +38,10 @@
   std::vector<char> content(net::kMaxBytesToSniff);
 
   const int bytes_read =
-      base::ReadFile(local_path, &content[0], content.size());
+      base::ReadFile(local_path, &content[0], static_cast<int>(content.size()));
 
   if (bytes_read >= 0) {
-    net::SniffMimeType(&content[0],
-                       bytes_read,
+    net::SniffMimeType(&content[0], bytes_read,
                        net::FilePathToFileURL(local_path),
                        std::string(),  // type_hint (passes no hint)
                        result);
@@ -77,13 +76,10 @@
   std::string* const mime_type_from_extension_ptr =
       mime_type_from_extension.get();
   BrowserThread::PostBlockingPoolTaskAndReply(
-      FROM_HERE,
-      base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile),
-                 local_path,
-                 mime_type_from_extension_ptr),
+      FROM_HERE, base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile),
+                            local_path, mime_type_from_extension_ptr),
       base::Bind(&OnGetMimeTypeFromFileForNonNativeLocalPathCompleted,
-                 base::Passed(&mime_type_from_extension),
-                 callback));
+                 base::Passed(&mime_type_from_extension), callback));
 }
 #endif
 
@@ -121,31 +117,27 @@
       new std::string(kMimeTypeApplicationOctetStream));
   std::string* const sniffed_mime_type_ptr = sniffed_mime_type.get();
   BrowserThread::PostBlockingPoolTaskAndReply(
-      FROM_HERE,
-      base::Bind(&SniffMimeType, local_path, sniffed_mime_type_ptr),
+      FROM_HERE, base::Bind(&SniffMimeType, local_path, sniffed_mime_type_ptr),
       base::Bind(&OnSniffMimeTypeForNativeLocalPathCompleted,
-                 base::Passed(&sniffed_mime_type),
-                 callback));
+                 base::Passed(&sniffed_mime_type), callback));
 }
 
 // Fetches MIME type for a local path and returns it with a |callback|.
 void GetMimeTypeForLocalPath(
-    Profile* profile,
+    content::BrowserContext* context,
     const base::FilePath& local_path,
     const base::Callback<void(const std::string&)>& callback) {
 #if defined(OS_CHROMEOS)
   NonNativeFileSystemDelegate* delegate =
       ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate();
-  if (delegate && delegate->IsUnderNonNativeLocalPath(profile, local_path)) {
+  if (delegate && delegate->IsUnderNonNativeLocalPath(context, local_path)) {
     // For non-native files, try to get the MIME type from metadata. If not
     // available, then try to guess from the extension. Never sniff (because
     // it can be very slow).
     delegate->GetNonNativeLocalPathMimeType(
-        profile,
-        local_path,
+        context, local_path,
         base::Bind(&OnGetMimeTypeFromMetadataForNonNativeLocalPathCompleted,
-                   local_path,
-                   callback));
+                   local_path, callback));
     return;
   }
 #endif
@@ -156,22 +148,16 @@
   std::string* const mime_type_from_extension_ptr =
       mime_type_from_extension.get();
   BrowserThread::PostBlockingPoolTaskAndReply(
-      FROM_HERE,
-      base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile),
-                 local_path,
-                 mime_type_from_extension_ptr),
-      base::Bind(&OnGetMimeTypeFromFileForNativeLocalPathCompleted,
-                 local_path,
-                 base::Passed(&mime_type_from_extension),
-                 callback));
+      FROM_HERE, base::Bind(base::IgnoreResult(&net::GetMimeTypeFromFile),
+                            local_path, mime_type_from_extension_ptr),
+      base::Bind(&OnGetMimeTypeFromFileForNativeLocalPathCompleted, local_path,
+                 base::Passed(&mime_type_from_extension), callback));
 }
 
-MimeTypeCollector::MimeTypeCollector(Profile* profile)
-    : profile_(profile), left_(0), weak_ptr_factory_(this) {
-}
+MimeTypeCollector::MimeTypeCollector(content::BrowserContext* context)
+    : context_(context), left_(0), weak_ptr_factory_(this) {}
 
-MimeTypeCollector::~MimeTypeCollector() {
-}
+MimeTypeCollector::~MimeTypeCollector() {}
 
 void MimeTypeCollector::CollectForURLs(
     const std::vector<storage::FileSystemURL>& urls,
@@ -203,11 +189,9 @@
   }
 
   for (size_t i = 0; i < local_paths.size(); ++i) {
-    GetMimeTypeForLocalPath(profile_,
-                            local_paths[i],
+    GetMimeTypeForLocalPath(context_, local_paths[i],
                             base::Bind(&MimeTypeCollector::OnMimeTypeCollected,
-                                       weak_ptr_factory_.GetWeakPtr(),
-                                       i));
+                                       weak_ptr_factory_.GetWeakPtr(), i));
   }
 }
 
diff --git a/chrome/browser/extensions/api/file_handlers/mime_util.h b/extensions/browser/api/file_handlers/mime_util.h
similarity index 86%
rename from chrome/browser/extensions/api/file_handlers/mime_util.h
rename to extensions/browser/api/file_handlers/mime_util.h
index e192664..c276070 100644
--- a/chrome/browser/extensions/api/file_handlers/mime_util.h
+++ b/extensions/browser/api/file_handlers/mime_util.h
@@ -4,8 +4,8 @@
 //
 // This file provides MIME related utilities.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_MIME_UTIL_H_
-#define CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_MIME_UTIL_H_
+#ifndef EXTENSIONS_BROWSER_API_FILE_HANDLERS_MIME_UTIL_H_
+#define EXTENSIONS_BROWSER_API_FILE_HANDLERS_MIME_UTIL_H_
 
 #include <stddef.h>
 
@@ -17,7 +17,9 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 
-class Profile;
+namespace content {
+class BrowserContext;
+}
 
 namespace base {
 class FilePath;
@@ -33,7 +35,7 @@
 // Gets a MIME type for a local path and returns it with |callback|. If not
 // found, then the MIME type is an empty string.
 void GetMimeTypeForLocalPath(
-    Profile* profile,
+    content::BrowserContext* context,
     const base::FilePath& local_path,
     const base::Callback<void(const std::string&)>& callback);
 
@@ -46,7 +48,7 @@
   typedef base::Callback<void(std::unique_ptr<std::vector<std::string>>)>
       CompletionCallback;
 
-  explicit MimeTypeCollector(Profile* profile);
+  explicit MimeTypeCollector(content::BrowserContext* context);
   virtual ~MimeTypeCollector();
 
   // Collects all mime types asynchronously for a vector of URLs and upon
@@ -63,7 +65,7 @@
   // Called, when the |index|-th input file (or URL) got processed.
   void OnMimeTypeCollected(size_t index, const std::string& mime_type);
 
-  Profile* profile_;
+  content::BrowserContext* context_;
   std::unique_ptr<std::vector<std::string>> result_;
   size_t left_;
   CompletionCallback callback_;
@@ -75,4 +77,4 @@
 }  // namespace app_file_handler_util
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_FILE_HANDLERS_MIME_UTIL_H_
+#endif  // EXTENSIONS_BROWSER_API_FILE_HANDLERS_MIME_UTIL_H_
diff --git a/chrome/browser/extensions/api/file_handlers/mime_util_unittest.cc b/extensions/browser/api/file_handlers/mime_util_unittest.cc
similarity index 80%
rename from chrome/browser/extensions/api/file_handlers/mime_util_unittest.cc
rename to extensions/browser/api/file_handlers/mime_util_unittest.cc
index d7aefe9..758134e 100644
--- a/chrome/browser/extensions/api/file_handlers/mime_util_unittest.cc
+++ b/extensions/browser/api/file_handlers/mime_util_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 "chrome/browser/extensions/api/file_handlers/mime_util.h"
+#include "extensions/browser/api/file_handlers/mime_util.h"
 
 #include <memory>
 #include <string>
@@ -11,11 +11,12 @@
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/run_loop.h"
-#include "chrome/test/base/testing_profile.h"
-#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_file_system_context.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/extensions_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -48,36 +49,33 @@
 
 }  // namespace
 
-class FileHandlersMimeUtilTest : public testing::Test {
+class FileHandlersMimeUtilTest : public ExtensionsTest {
  protected:
   FileHandlersMimeUtilTest() {}
   ~FileHandlersMimeUtilTest() override {}
 
   void SetUp() override {
-    ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
-    file_system_context_ =
-        content::CreateFileSystemContextForTesting(NULL, data_dir_.GetPath());
+    file_system_context_ = content::CreateFileSystemContextForTesting(
+        NULL, browser_context()->GetPath());
 
     EXPECT_TRUE(base::CreateTemporaryFile(&html_mime_file_path_));
     const std::string kSampleContent = "<html><body></body></html>";
-    EXPECT_TRUE(base::WriteFile(
-        html_mime_file_path_, kSampleContent.c_str(), kSampleContent.size()));
+    EXPECT_TRUE(base::WriteFile(html_mime_file_path_, kSampleContent.c_str(),
+                                kSampleContent.size()));
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
+  ExtensionsAPIClient extensions_api_client_;
   scoped_refptr<storage::FileSystemContext> file_system_context_;
-  base::ScopedTempDir data_dir_;
   base::FilePath html_mime_file_path_;
 };
 
 TEST_F(FileHandlersMimeUtilTest, GetMimeTypeForLocalPath) {
   {
     std::string result;
-    GetMimeTypeForLocalPath(
-        &profile_,
-        base::FilePath::FromUTF8Unsafe(kJPEGExtensionFilePath),
-        base::Bind(&OnMimeTypeResult, &result));
+    GetMimeTypeForLocalPath(browser_context(), base::FilePath::FromUTF8Unsafe(
+                                                   kJPEGExtensionFilePath),
+                            base::Bind(&OnMimeTypeResult, &result));
     content::RunAllBlockingPoolTasksUntilIdle();
     EXPECT_EQ("image/jpeg", result);
   }
@@ -85,7 +83,7 @@
   {
     std::string result;
     GetMimeTypeForLocalPath(
-        &profile_,
+        browser_context(),
         base::FilePath::FromUTF8Unsafe(kJPEGExtensionUpperCaseFilePath),
         base::Bind(&OnMimeTypeResult, &result));
     content::RunAllBlockingPoolTasksUntilIdle();
@@ -94,8 +92,7 @@
 
   {
     std::string result;
-    GetMimeTypeForLocalPath(&profile_,
-                            html_mime_file_path_,
+    GetMimeTypeForLocalPath(browser_context(), html_mime_file_path_,
                             base::Bind(&OnMimeTypeResult, &result));
     content::RunAllBlockingPoolTasksUntilIdle();
     EXPECT_EQ("text/html", result);
@@ -103,7 +100,7 @@
 }
 
 TEST_F(FileHandlersMimeUtilTest, MimeTypeCollector_ForURLs) {
-  MimeTypeCollector collector(&profile_);
+  MimeTypeCollector collector(browser_context());
 
   std::vector<storage::FileSystemURL> urls;
   urls.push_back(CreateNativeLocalFileSystemURL(
@@ -126,7 +123,7 @@
 }
 
 TEST_F(FileHandlersMimeUtilTest, MimeTypeCollector_ForLocalPaths) {
-  MimeTypeCollector collector(&profile_);
+  MimeTypeCollector collector(browser_context());
 
   std::vector<base::FilePath> local_paths;
   local_paths.push_back(base::FilePath::FromUTF8Unsafe(kJPEGExtensionFilePath));
diff --git a/extensions/browser/guest_view/BUILD.gn b/extensions/browser/guest_view/BUILD.gn
index 7b41169e..2b81c0d1 100644
--- a/extensions/browser/guest_view/BUILD.gn
+++ b/extensions/browser/guest_view/BUILD.gn
@@ -23,6 +23,7 @@
   ]
 
   deps = [
+    "//components/browsing_data/content",
     "//components/guest_view/browser",
     "//content/public/common",
   ]
diff --git a/extensions/common/api/cast_channel.idl b/extensions/common/api/cast_channel.idl
index 0d695b6..6fd3035b 100644
--- a/extensions/common/api/cast_channel.idl
+++ b/extensions/common/api/cast_channel.idl
@@ -168,16 +168,6 @@
   // Callback holding the result of a channel operation.
   callback ChannelInfoCallback = void (ChannelInfo result);
 
-  // Callback from <code>getLogs</code> method.
-  // |log|: compressed serialized raw bytes containing the logs.
-  // The log is formatted using protocol buffer.
-  // See extensions/browser/api/cast_channel/logging.proto for definition.
-  // Compression is in gzip format.
-  callback GetLogsCallback = void (ArrayBuffer log);
-
-  // Callback from <code>setAuthorityKeys</code> method.
-  callback SetAuthorityKeysCallback = void ();
-
   interface Functions {
     // Opens a new channel to the Cast receiver specified by connectInfo.  Only
     // one channel may be connected to same receiver from the same extension at
@@ -205,19 +195,6 @@
     // and channel.errorState will be set to the error condition.
     static void close(ChannelInfo channel,
                       ChannelInfoCallback callback);
-
-    // Get logs in compressed serialized format. See GetLogsCallback for
-    // details.
-    // |callback|: If successful, |callback| is invoked with data. Otherwise,
-    // an error will be raised.
-    static void getLogs(GetLogsCallback callback);
-
-    // Sets trusted certificate authorities where |signature| is a base64
-    // encoded RSA-PSS signature and |keys| is base64 encoded AuthorityKeys
-    // protobuf.
-    static void setAuthorityKeys(DOMString keys,
-                                 DOMString signature,
-                                 SetAuthorityKeysCallback callback);
   };
 
   // Events on the channel.
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index 34cfe50..9cbc4ee 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -30,6 +30,8 @@
     "api_definitions_natives.h",
     "api_event_handler.cc",
     "api_event_handler.h",
+    "api_last_error.cc",
+    "api_last_error.h",
     "api_request_handler.cc",
     "api_request_handler.h",
     "api_signature.cc",
@@ -286,6 +288,7 @@
     "api_binding_unittest.cc",
     "api_bindings_system_unittest.cc",
     "api_event_handler_unittest.cc",
+    "api_last_error_unittest.cc",
     "api_request_handler_unittest.cc",
     "api_test_base.cc",
     "api_test_base.h",
diff --git a/extensions/renderer/api_binding_test_util.cc b/extensions/renderer/api_binding_test_util.cc
index 66cd2c35..262ae6a7c 100644
--- a/extensions/renderer/api_binding_test_util.cc
+++ b/extensions/renderer/api_binding_test_util.cc
@@ -74,6 +74,22 @@
   return json;
 }
 
+std::string V8ToString(v8::Local<v8::Value> value,
+                       v8::Local<v8::Context> context) {
+  if (value.IsEmpty())
+    return "empty";
+  if (value->IsNull())
+    return "null";
+  if (value->IsUndefined())
+    return "undefined";
+  if (value->IsFunction())
+    return "function";
+  std::unique_ptr<base::Value> json = V8ToBaseValue(value, context);
+  if (!json)
+    return "unserializable";
+  return ValueToString(*json);
+}
+
 v8::Local<v8::Value> V8ValueFromScriptSource(v8::Local<v8::Context> context,
                                              base::StringPiece source) {
   v8::MaybeLocal<v8::Script> maybe_script = v8::Script::Compile(
@@ -188,18 +204,7 @@
 std::string GetStringPropertyFromObject(v8::Local<v8::Object> object,
                                         v8::Local<v8::Context> context,
                                         base::StringPiece key) {
-  v8::Local<v8::Value> v8_val = GetPropertyFromObject(object, context, key);
-  if (v8_val.IsEmpty())
-    return "empty";
-  if (v8_val->IsNull())
-    return "null";
-  if (v8_val->IsUndefined())
-    return "undefined";
-  if (v8_val->IsFunction())
-    return "function";
-  std::unique_ptr<base::Value> json_prop = V8ToBaseValue(v8_val, context);
-  DCHECK(json_prop) << key;
-  return ValueToString(*json_prop);
+  return V8ToString(GetPropertyFromObject(object, context, key), context);
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/api_binding_test_util.h b/extensions/renderer/api_binding_test_util.h
index cc306e6..949049d 100644
--- a/extensions/renderer/api_binding_test_util.h
+++ b/extensions/renderer/api_binding_test_util.h
@@ -37,6 +37,12 @@
 // succeed.
 std::string ValueToString(const base::Value& value);
 
+// Converts the given |value| to a string. Returns "empty", "undefined", "null",
+// or "function" for unserializable values. Note this differs from
+// gin::V8ToString, which only accepts v8::String values.
+std::string V8ToString(v8::Local<v8::Value> value,
+                       v8::Local<v8::Context> context);
+
 // Returns a v8::Value result from compiling and running |source|, or an empty
 // local on failure.
 v8::Local<v8::Value> V8ValueFromScriptSource(v8::Local<v8::Context> context,
diff --git a/extensions/renderer/api_binding_unittest.cc b/extensions/renderer/api_binding_unittest.cc
index e56e93d9..e21ece24 100644
--- a/extensions/renderer/api_binding_unittest.cc
+++ b/extensions/renderer/api_binding_unittest.cc
@@ -137,7 +137,8 @@
   void SetUp() override {
     APIBindingTest::SetUp();
     request_handler_ = base::MakeUnique<APIRequestHandler>(
-        base::Bind(&RunFunctionOnGlobalAndIgnoreResult));
+        base::Bind(&RunFunctionOnGlobalAndIgnoreResult),
+        APILastError(APILastError::GetParent()));
   }
 
   void TearDown() override {
diff --git a/extensions/renderer/api_bindings_system.cc b/extensions/renderer/api_bindings_system.cc
index 868c465d..4436757a 100644
--- a/extensions/renderer/api_bindings_system.cc
+++ b/extensions/renderer/api_bindings_system.cc
@@ -16,10 +16,11 @@
     const binding::RunJSFunctionSync& call_js_sync,
     const GetAPISchemaMethod& get_api_schema,
     const APIBinding::SendRequestMethod& send_request,
-    const APIEventHandler::EventListenersChangedMethod& event_listeners_changed)
+    const APIEventHandler::EventListenersChangedMethod& event_listeners_changed,
+    APILastError last_error)
     : type_reference_map_(base::Bind(&APIBindingsSystem::InitializeType,
                                      base::Unretained(this))),
-      request_handler_(call_js),
+      request_handler_(call_js, std::move(last_error)),
       event_handler_(call_js, event_listeners_changed),
       call_js_(call_js),
       call_js_sync_(call_js_sync),
@@ -92,8 +93,9 @@
 }
 
 void APIBindingsSystem::CompleteRequest(int request_id,
-                                        const base::ListValue& response) {
-  request_handler_.CompleteRequest(request_id, response);
+                                        const base::ListValue& response,
+                                        const std::string& error) {
+  request_handler_.CompleteRequest(request_id, response, error);
 }
 
 void APIBindingsSystem::FireEventInContext(const std::string& event_name,
diff --git a/extensions/renderer/api_bindings_system.h b/extensions/renderer/api_bindings_system.h
index ae7442d5..ecea8e904 100644
--- a/extensions/renderer/api_bindings_system.h
+++ b/extensions/renderer/api_bindings_system.h
@@ -14,6 +14,7 @@
 #include "extensions/renderer/api_binding.h"
 #include "extensions/renderer/api_binding_types.h"
 #include "extensions/renderer/api_event_handler.h"
+#include "extensions/renderer/api_last_error.h"
 #include "extensions/renderer/api_request_handler.h"
 #include "extensions/renderer/api_type_reference_map.h"
 
@@ -38,7 +39,8 @@
                     const GetAPISchemaMethod& get_api_schema,
                     const APIBinding::SendRequestMethod& send_request,
                     const APIEventHandler::EventListenersChangedMethod&
-                        event_listeners_changed);
+                        event_listeners_changed,
+                    APILastError last_error);
   ~APIBindingsSystem();
 
   // Returns a new v8::Object representing the api specified by |api_name|.
@@ -50,8 +52,10 @@
       v8::Local<v8::Object>* hooks_interface_out);
 
   // Responds to the request with the given |request_id|, calling the callback
-  // with |response|.
-  void CompleteRequest(int request_id, const base::ListValue& response);
+  // with |response|. If |error| is non-empty, sets the last error.
+  void CompleteRequest(int request_id,
+                       const base::ListValue& response,
+                       const std::string& error);
 
   // Notifies the APIEventHandler to fire the corresponding event, notifying
   // listeners.
diff --git a/extensions/renderer/api_bindings_system_unittest.cc b/extensions/renderer/api_bindings_system_unittest.cc
index e5df38d..0b9c441 100644
--- a/extensions/renderer/api_bindings_system_unittest.cc
+++ b/extensions/renderer/api_bindings_system_unittest.cc
@@ -117,7 +117,8 @@
         base::Bind(&APIBindingsSystemTestBase::OnAPIRequest,
                    base::Unretained(this)),
         base::Bind(&APIBindingsSystemTestBase::OnEventListenersChanged,
-                   base::Unretained(this)));
+                   base::Unretained(this)),
+        APILastError(APILastError::GetParent()));
   }
 
   void TearDown() override {
@@ -248,7 +249,7 @@
     std::unique_ptr<base::ListValue> expected_args =
         ListValueFromString(kResponseArgsJson);
     bindings_system()->CompleteRequest(last_request()->request_id,
-                                       *expected_args);
+                                       *expected_args, std::string());
 
     EXPECT_EQ(ReplaceSingleQuotes(kResponseArgsJson),
               GetStringPropertyFromObject(context->Global(), context,
@@ -270,7 +271,7 @@
                         "[{'prop1':'alpha','prop2':42}]");
 
     bindings_system()->CompleteRequest(last_request()->request_id,
-                                       base::ListValue());
+                                       base::ListValue(), std::string());
 
     EXPECT_EQ("[]", GetStringPropertyFromObject(context->Global(), context,
                                                 "callbackArguments"));
@@ -402,7 +403,8 @@
 
     std::unique_ptr<base::ListValue> response =
         ListValueFromString("['alpha','beta']");
-    bindings_system()->CompleteRequest(last_request()->request_id, *response);
+    bindings_system()->CompleteRequest(last_request()->request_id, *response,
+                                       std::string());
 
     EXPECT_EQ(
         "\"alpha.functionWithCallback\"",
diff --git a/extensions/renderer/api_last_error.cc b/extensions/renderer/api_last_error.cc
new file mode 100644
index 0000000..2dafc5e1
--- /dev/null
+++ b/extensions/renderer/api_last_error.cc
@@ -0,0 +1,149 @@
+// 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 "extensions/renderer/api_last_error.h"
+
+#include "gin/converter.h"
+#include "gin/handle.h"
+#include "gin/object_template_builder.h"
+#include "gin/wrappable.h"
+
+namespace extensions {
+
+namespace {
+
+const char kLastErrorProperty[] = "lastError";
+
+class LastErrorObject final : public gin::Wrappable<LastErrorObject> {
+ public:
+  explicit LastErrorObject(const std::string& error) : error_(error) {}
+
+  static gin::WrapperInfo kWrapperInfo;
+
+  // gin::Wrappable:
+  gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) override {
+    DCHECK(isolate);
+    return Wrappable<LastErrorObject>::GetObjectTemplateBuilder(isolate)
+        .SetProperty("message", &LastErrorObject::GetLastError);
+  }
+
+  void Reset(const std::string& error) {
+    error_ = error;
+    accessed_ = false;
+  }
+
+  const std::string& error() const { return error_; }
+  bool accessed() const { return accessed_; }
+
+ private:
+  std::string GetLastError() {
+    accessed_ = true;
+    return error_;
+  }
+
+  std::string error_;
+  bool accessed_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(LastErrorObject);
+};
+
+gin::WrapperInfo LastErrorObject::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+}  // namespace
+
+APILastError::APILastError(const GetParent& get_parent)
+    : get_parent_(get_parent) {}
+APILastError::APILastError(APILastError&& other) = default;
+APILastError::~APILastError() = default;
+
+void APILastError::SetError(v8::Local<v8::Context> context,
+                            const std::string& error) {
+  v8::Isolate* isolate = context->GetIsolate();
+  DCHECK(isolate);
+  v8::HandleScope handle_scope(isolate);
+
+  // The various accesses/sets on an object could potentially fail if script has
+  // set any crazy interceptors. For the most part, we don't care about behaving
+  // perfectly in these circumstances, but we eat the exception so callers don't
+  // have to worry about it. We also SetVerbose() so that developers will have a
+  // clue what happened if this does arise.
+  // TODO(devlin): Whether or not this needs to be verbose is debatable.
+  v8::TryCatch try_catch(isolate);
+  try_catch.SetVerbose(true);
+
+  v8::Local<v8::Object> parent = get_parent_.Run(context);
+  if (parent.IsEmpty())
+    return;
+  v8::Local<v8::String> key = gin::StringToSymbol(isolate, kLastErrorProperty);
+  v8::Local<v8::Value> v8_error;
+  if (!parent->Get(context, key).ToLocal(&v8_error))
+    return;
+
+  if (!v8_error->IsUndefined()) {
+    // There may be an existing last error to overwrite.
+    LastErrorObject* last_error = nullptr;
+    if (!gin::Converter<LastErrorObject*>::FromV8(context->GetIsolate(),
+                                                  v8_error, &last_error)) {
+      // If it's not a real lastError (e.g. if a script manually set it), don't
+      // do anything. We shouldn't mangle a property set by other script.
+      // TODO(devlin): Or should we? If someone sets chrome.runtime.lastError,
+      // it might be the right course of action to overwrite it.
+      return;
+    }
+    last_error->Reset(error);
+  } else {
+    DCHECK(context->GetIsolate());
+    v8::Local<v8::Value> last_error =
+        gin::CreateHandle(context->GetIsolate(), new LastErrorObject(error))
+            .ToV8();
+    DCHECK(!last_error.IsEmpty());
+    // This Set() can fail, but there's nothing to do if it does (the exception
+    // will be caught by the TryCatch above).
+    ignore_result(parent->Set(
+        context, gin::StringToSymbol(isolate, kLastErrorProperty), last_error));
+  }
+}
+
+void APILastError::ClearError(v8::Local<v8::Context> context,
+                              bool report_if_unchecked) {
+  v8::Isolate* isolate = context->GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  v8::Local<v8::Object> parent;
+  LastErrorObject* last_error = nullptr;
+  v8::Local<v8::String> key;
+  {
+    // See comment in SetError().
+    v8::TryCatch try_catch(isolate);
+    try_catch.SetVerbose(true);
+
+    parent = get_parent_.Run(context);
+    if (parent.IsEmpty())
+      return;
+    key = gin::StringToSymbol(isolate, kLastErrorProperty);
+    v8::Local<v8::Value> error;
+    if (!parent->Get(context, key).ToLocal(&error))
+      return;
+    if (!gin::Converter<LastErrorObject*>::FromV8(context->GetIsolate(), error,
+                                                  &last_error)) {
+      return;
+    }
+  }
+
+  if (report_if_unchecked && !last_error->accessed()) {
+    isolate->ThrowException(
+        v8::Exception::Error(gin::StringToV8(isolate, last_error->error())));
+  }
+
+  // See comment in SetError().
+  v8::TryCatch try_catch(isolate);
+  try_catch.SetVerbose(true);
+
+  // This Delete() can fail, but there's nothing to do if it does (the exception
+  // will be caught by the TryCatch above).
+  parent->Delete(context, key);
+}
+
+}  // namespace extensions
diff --git a/extensions/renderer/api_last_error.h b/extensions/renderer/api_last_error.h
new file mode 100644
index 0000000..68ed4dd
--- /dev/null
+++ b/extensions/renderer/api_last_error.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_RENDERER_API_LAST_ERROR_H_
+#define EXTENSIONS_RENDERER_API_LAST_ERROR_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "v8/include/v8.h"
+
+namespace extensions {
+
+// Handles creating and clearing a 'lastError' property to hold the last error
+// set by an extension API function.
+class APILastError {
+ public:
+  // Returns the object the 'lastError' property should be exposed on for the
+  // given context.
+  using GetParent =
+      base::Callback<v8::Local<v8::Object>(v8::Local<v8::Context>)>;
+
+  explicit APILastError(const GetParent& get_parent);
+  APILastError(APILastError&& other);
+  ~APILastError();
+
+  // Sets the last error for the given |context| to |error|.
+  void SetError(v8::Local<v8::Context> context, const std::string& error);
+
+  // Clears the last error in the given |context|. If |report_if_unchecked| is
+  // true and the developer didn't check the error, this throws an exception.
+  void ClearError(v8::Local<v8::Context> context, bool report_if_unchecked);
+
+ private:
+  GetParent get_parent_;
+
+  DISALLOW_COPY_AND_ASSIGN(APILastError);
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_RENDERER_API_LAST_ERROR_H_
diff --git a/extensions/renderer/api_last_error_unittest.cc b/extensions/renderer/api_last_error_unittest.cc
new file mode 100644
index 0000000..fd4a9643
--- /dev/null
+++ b/extensions/renderer/api_last_error_unittest.cc
@@ -0,0 +1,167 @@
+// 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 "extensions/renderer/api_last_error.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "extensions/renderer/api_binding_test.h"
+#include "extensions/renderer/api_binding_test_util.h"
+#include "gin/converter.h"
+#include "gin/public/context_holder.h"
+
+namespace extensions {
+
+namespace {
+
+std::string GetLastError(v8::Local<v8::Object> parent,
+                         v8::Local<v8::Context> context) {
+  v8::Local<v8::Value> last_error =
+      GetPropertyFromObject(parent, context, "lastError");
+  if (last_error.IsEmpty() || !last_error->IsObject())
+    return V8ToString(last_error, context);
+  v8::Local<v8::Value> message =
+      GetPropertyFromObject(last_error.As<v8::Object>(), context, "message");
+  return V8ToString(message, context);
+}
+
+using ParentList =
+    std::vector<std::pair<v8::Local<v8::Context>, v8::Local<v8::Object>>>;
+v8::Local<v8::Object> GetParent(const ParentList& parents,
+                                v8::Local<v8::Context> context) {
+  // This would be simpler with a map<context, object>, but Local<> doesn't
+  // define an operator<.
+  for (const auto& parent : parents) {
+    if (parent.first == context)
+      return parent.second;
+  }
+  return v8::Local<v8::Object>();
+}
+
+}  // namespace
+
+using APILastErrorTest = APIBindingTest;
+
+// Test basic functionality of the lastError object.
+TEST_F(APILastErrorTest, TestLastError) {
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = ContextLocal();
+  v8::Local<v8::Object> parent_object = v8::Object::New(isolate());
+
+  ParentList parents = {{context, parent_object}};
+  APILastError last_error(base::Bind(&GetParent, parents));
+
+  EXPECT_EQ("undefined", GetLastError(parent_object, context));
+  // Check that the key isn't present on the object (as opposed to simply being
+  // undefined).
+  EXPECT_FALSE(
+      parent_object->Has(context, gin::StringToV8(isolate(), "lastError"))
+          .ToChecked());
+
+  last_error.SetError(context, "Some last error");
+  EXPECT_EQ("\"Some last error\"", GetLastError(parent_object, context));
+
+  last_error.ClearError(context, false);
+  EXPECT_EQ("undefined", GetLastError(parent_object, context));
+  EXPECT_FALSE(
+      parent_object->Has(context, gin::StringToV8(isolate(), "lastError"))
+          .ToChecked());
+}
+
+// Test throwing an error if the last error wasn't checked.
+TEST_F(APILastErrorTest, ReportIfUnchecked) {
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = ContextLocal();
+  v8::Local<v8::Object> parent_object = v8::Object::New(isolate());
+
+  ParentList parents = {{context, parent_object}};
+  APILastError last_error(base::Bind(&GetParent, parents));
+
+  {
+    v8::TryCatch try_catch(isolate());
+    last_error.SetError(context, "foo");
+    // GetLastError() will count as accessing the error property, so we
+    // shouldn't throw an exception.
+    EXPECT_EQ("\"foo\"", GetLastError(parent_object, context));
+    last_error.ClearError(context, true);
+    EXPECT_FALSE(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch(isolate());
+    // This time, we should throw an exception.
+    last_error.SetError(context, "A last error");
+    last_error.ClearError(context, true);
+    ASSERT_TRUE(try_catch.HasCaught());
+    EXPECT_EQ("Uncaught Error: A last error",
+              gin::V8ToString(try_catch.Message()->Get()));
+  }
+}
+
+// Test behavior when something else sets a lastError property on the parent
+// object.
+TEST_F(APILastErrorTest, NonLastErrorObject) {
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = ContextLocal();
+  v8::Local<v8::Object> parent_object = v8::Object::New(isolate());
+
+  ParentList parents = {{context, parent_object}};
+  APILastError last_error(base::Bind(&GetParent, parents));
+
+  auto checked_set = [context](v8::Local<v8::Object> object,
+                               base::StringPiece key,
+                               v8::Local<v8::Value> value) {
+    v8::Maybe<bool> success = object->Set(
+        context, gin::StringToSymbol(context->GetIsolate(), key), value);
+    ASSERT_TRUE(success.IsJust());
+    ASSERT_TRUE(success.FromJust());
+  };
+
+  // Set a "fake" lastError property on the parent.
+  v8::Local<v8::Object> fake_last_error = v8::Object::New(isolate());
+  checked_set(fake_last_error, "message",
+              gin::StringToV8(isolate(), "fake error"));
+  checked_set(parent_object, "lastError", fake_last_error);
+
+  EXPECT_EQ("\"fake error\"", GetLastError(parent_object, context));
+
+  // The bindings shouldn't mangle an existing property (or maybe we should -
+  // see the TODO in api_last_error.cc).
+  last_error.SetError(context, "Real last error");
+  EXPECT_EQ("\"fake error\"", GetLastError(parent_object, context));
+  last_error.ClearError(context, false);
+  EXPECT_EQ("\"fake error\"", GetLastError(parent_object, context));
+}
+
+// Test lastError in multiple different contexts.
+TEST_F(APILastErrorTest, MultipleContexts) {
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context_a = ContextLocal();
+  v8::Local<v8::Context> context_b = v8::Context::New(isolate());
+  gin::ContextHolder holder_b(isolate());
+  holder_b.SetContext(context_b);
+
+  v8::Local<v8::Object> parent_a = v8::Object::New(isolate());
+  v8::Local<v8::Object> parent_b = v8::Object::New(isolate());
+  ParentList parents = {{context_a, parent_a}, {context_b, parent_b}};
+  APILastError last_error(base::Bind(&GetParent, parents));
+
+  last_error.SetError(context_a, "Last error a");
+  EXPECT_EQ("\"Last error a\"", GetLastError(parent_a, context_a));
+  EXPECT_EQ("undefined", GetLastError(parent_b, context_b));
+
+  last_error.SetError(context_b, "Last error b");
+  EXPECT_EQ("\"Last error a\"", GetLastError(parent_a, context_a));
+  EXPECT_EQ("\"Last error b\"", GetLastError(parent_b, context_b));
+
+  last_error.ClearError(context_b, false);
+  EXPECT_EQ("\"Last error a\"", GetLastError(parent_a, context_a));
+  EXPECT_EQ("undefined", GetLastError(parent_b, context_b));
+
+  last_error.ClearError(context_a, false);
+  EXPECT_EQ("undefined", GetLastError(parent_a, context_a));
+  EXPECT_EQ("undefined", GetLastError(parent_b, context_b));
+}
+
+}  // namespace extensions
diff --git a/extensions/renderer/api_request_handler.cc b/extensions/renderer/api_request_handler.cc
index ef360c87..a55d714 100644
--- a/extensions/renderer/api_request_handler.cc
+++ b/extensions/renderer/api_request_handler.cc
@@ -36,8 +36,9 @@
 APIRequestHandler::PendingRequest& APIRequestHandler::PendingRequest::operator=(
     PendingRequest&&) = default;
 
-APIRequestHandler::APIRequestHandler(const CallJSFunction& call_js)
-    : call_js_(call_js) {}
+APIRequestHandler::APIRequestHandler(const CallJSFunction& call_js,
+                                     APILastError last_error)
+    : call_js_(call_js), last_error_(std::move(last_error)) {}
 
 APIRequestHandler::~APIRequestHandler() {}
 
@@ -57,7 +58,8 @@
 }
 
 void APIRequestHandler::CompleteRequest(int request_id,
-                                        const base::ListValue& response_args) {
+                                        const base::ListValue& response_args,
+                                        const std::string& error) {
   auto iter = pending_requests_.find(request_id);
   // The request may have been removed if the context was invalidated before a
   // response is ready.
@@ -70,6 +72,7 @@
   v8::Isolate* isolate = pending_request.isolate;
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context = pending_request.context.Get(isolate);
+  v8::Context::Scope context_scope(context);
   std::unique_ptr<content::V8ValueConverter> converter(
       content::V8ValueConverter::create());
   std::vector<v8::Local<v8::Value>> args;
@@ -81,10 +84,16 @@
     args.push_back(converter->ToV8Value(arg.get(), context));
 
   blink::WebScopedUserGesture user_gesture(pending_request.user_gesture_token);
+  if (!error.empty())
+    last_error_.SetError(context, error);
+
   // args.size() is converted to int, but args is controlled by chrome and is
   // never close to std::numeric_limits<int>::max.
   call_js_.Run(pending_request.callback.Get(isolate), context, args.size(),
                args.data());
+
+  if (!error.empty())
+    last_error_.ClearError(context, true);
 }
 
 void APIRequestHandler::InvalidateContext(v8::Local<v8::Context> context) {
diff --git a/extensions/renderer/api_request_handler.h b/extensions/renderer/api_request_handler.h
index 9d3c8e9..32897120 100644
--- a/extensions/renderer/api_request_handler.h
+++ b/extensions/renderer/api_request_handler.h
@@ -11,6 +11,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "extensions/renderer/api_last_error.h"
 #include "third_party/WebKit/public/web/WebUserGestureToken.h"
 #include "v8/include/v8.h"
 
@@ -30,7 +31,7 @@
                                              int argc,
                                              v8::Local<v8::Value>[])>;
 
-  explicit APIRequestHandler(const CallJSFunction& call_js);
+  APIRequestHandler(const CallJSFunction& call_js, APILastError last_error);
   ~APIRequestHandler();
 
   // Adds a pending request to the map. Returns a unique identifier for that
@@ -43,7 +44,9 @@
   // Responds to the request with the given |request_id|, calling the callback
   // with the given |response| arguments.
   // Invalid ids are ignored.
-  void CompleteRequest(int request_id, const base::ListValue& response);
+  void CompleteRequest(int request_id,
+                       const base::ListValue& response,
+                       const std::string& error);
 
   // Invalidates any requests that are associated with |context|.
   void InvalidateContext(v8::Local<v8::Context> context);
@@ -79,6 +82,8 @@
   // (where we have to deal with e.g. blocking javascript).
   CallJSFunction call_js_;
 
+  APILastError last_error_;
+
   DISALLOW_COPY_AND_ASSIGN(APIRequestHandler);
 };
 
diff --git a/extensions/renderer/api_request_handler_unittest.cc b/extensions/renderer/api_request_handler_unittest.cc
index 164edea..915c197 100644
--- a/extensions/renderer/api_request_handler_unittest.cc
+++ b/extensions/renderer/api_request_handler_unittest.cc
@@ -58,7 +58,8 @@
   v8::Local<v8::Context> context = ContextLocal();
 
   APIRequestHandler request_handler(
-      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)));
+      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)),
+      APILastError(APILastError::GetParent()));
 
   EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty());
 
@@ -74,7 +75,8 @@
   std::unique_ptr<base::ListValue> response_arguments =
       ListValueFromString(kArguments);
   ASSERT_TRUE(response_arguments);
-  request_handler.CompleteRequest(request_id, *response_arguments);
+  request_handler.CompleteRequest(request_id, *response_arguments,
+                                  std::string());
 
   EXPECT_TRUE(did_run_js());
   EXPECT_EQ(ReplaceSingleQuotes(kArguments),
@@ -89,7 +91,8 @@
   v8::Local<v8::Context> context = ContextLocal();
 
   APIRequestHandler request_handler(
-      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)));
+      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)),
+      APILastError(APILastError::GetParent()));
 
   v8::Local<v8::Function> function = FunctionFromString(context, kEchoArgs);
   ASSERT_FALSE(function.IsEmpty());
@@ -105,12 +108,14 @@
 
   // Try running with a non-existent request id.
   int fake_request_id = 42;
-  request_handler.CompleteRequest(fake_request_id, *response_arguments);
+  request_handler.CompleteRequest(fake_request_id, *response_arguments,
+                                  std::string());
   EXPECT_FALSE(did_run_js());
 
   // Try running with a request from an invalidated context.
   request_handler.InvalidateContext(context);
-  request_handler.CompleteRequest(request_id, *response_arguments);
+  request_handler.CompleteRequest(request_id, *response_arguments,
+                                  std::string());
   EXPECT_FALSE(did_run_js());
 }
 
@@ -122,7 +127,8 @@
   holder_b.SetContext(context_b);
 
   APIRequestHandler request_handler(
-      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)));
+      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)),
+      APILastError(APILastError::GetParent()));
 
   // By having both different arguments and different behaviors in the
   // callbacks, we can easily verify that the right function is called in the
@@ -144,7 +150,7 @@
       ListValueFromString("['response_a:']");
   ASSERT_TRUE(response_a);
 
-  request_handler.CompleteRequest(request_a, *response_a);
+  request_handler.CompleteRequest(request_a, *response_a, std::string());
   EXPECT_TRUE(did_run_js());
   EXPECT_THAT(request_handler.GetPendingRequestIdsForTesting(),
               testing::UnorderedElementsAre(request_b));
@@ -157,7 +163,7 @@
       ListValueFromString("['response_b:']");
   ASSERT_TRUE(response_b);
 
-  request_handler.CompleteRequest(request_b, *response_b);
+  request_handler.CompleteRequest(request_b, *response_b, std::string());
   EXPECT_TRUE(request_handler.GetPendingRequestIdsForTesting().empty());
 
   EXPECT_EQ(
@@ -170,7 +176,8 @@
   v8::Local<v8::Context> context = ContextLocal();
 
   APIRequestHandler request_handler(
-      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)));
+      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)),
+      APILastError(APILastError::GetParent()));
 
   ArgumentList custom_callback_args = {
       gin::StringToV8(isolate(), "to"), gin::StringToV8(isolate(), "be"),
@@ -187,7 +194,8 @@
   std::unique_ptr<base::ListValue> response_arguments =
       ListValueFromString("['or','not','to','be']");
   ASSERT_TRUE(response_arguments);
-  request_handler.CompleteRequest(request_id, *response_arguments);
+  request_handler.CompleteRequest(request_id, *response_arguments,
+                                  std::string());
 
   EXPECT_TRUE(did_run_js());
   EXPECT_EQ(ReplaceSingleQuotes("['to','be','or','not','to','be']"),
@@ -202,7 +210,8 @@
   v8::Local<v8::Context> context = ContextLocal();
 
   APIRequestHandler request_handler(
-      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)));
+      base::Bind(&APIRequestHandlerTest::RunJS, base::Unretained(this)),
+      APILastError(APILastError::GetParent()));
 
   auto callback = [](base::Optional<bool>* ran_with_user_gesture) {
     *ran_with_user_gesture =
@@ -221,7 +230,8 @@
   // Try first without a user gesture.
   int request_id = request_handler.AddPendingRequest(isolate(), v8_callback,
                                                      context, ArgumentList());
-  request_handler.CompleteRequest(request_id, *ListValueFromString("[]"));
+  request_handler.CompleteRequest(request_id, *ListValueFromString("[]"),
+                                  std::string());
 
   ASSERT_TRUE(ran_with_user_gesture);
   EXPECT_FALSE(*ran_with_user_gesture);
@@ -239,7 +249,8 @@
   EXPECT_FALSE(
       blink::WebUserGestureIndicator::isProcessingUserGestureThreadSafe());
 
-  request_handler.CompleteRequest(request_id, *ListValueFromString("[]"));
+  request_handler.CompleteRequest(request_id, *ListValueFromString("[]"),
+                                  std::string());
   ASSERT_TRUE(ran_with_user_gesture);
   EXPECT_TRUE(*ran_with_user_gesture);
   // Sanity check - after the callback ran, there shouldn't be an active
diff --git a/extensions/renderer/argument_spec.cc b/extensions/renderer/argument_spec.cc
index cd8da0f..a4def1d 100644
--- a/extensions/renderer/argument_spec.cc
+++ b/extensions/renderer/argument_spec.cc
@@ -89,12 +89,19 @@
   if (dict->GetInteger("minimum", &min))
     minimum_ = min;
 
-  const base::DictionaryValue* properties_value = nullptr;
-  if (type_ == ArgumentType::OBJECT &&
-      dict->GetDictionary("properties", &properties_value)) {
-    for (base::DictionaryValue::Iterator iter(*properties_value);
-         !iter.IsAtEnd(); iter.Advance()) {
-      properties_[iter.key()] = base::MakeUnique<ArgumentSpec>(iter.value());
+  if (type_ == ArgumentType::OBJECT) {
+    const base::DictionaryValue* properties_value = nullptr;
+    if (dict->GetDictionary("properties", &properties_value)) {
+      for (base::DictionaryValue::Iterator iter(*properties_value);
+           !iter.IsAtEnd(); iter.Advance()) {
+        properties_[iter.key()] = base::MakeUnique<ArgumentSpec>(iter.value());
+      }
+    }
+    const base::DictionaryValue* additional_properties_value = nullptr;
+    if (dict->GetDictionary("additionalProperties",
+                            &additional_properties_value)) {
+      additional_properties_ =
+          base::MakeUnique<ArgumentSpec>(*additional_properties_value);
     }
   } else if (type_ == ArgumentType::LIST) {
     const base::DictionaryValue* item_value = nullptr;
@@ -253,6 +260,7 @@
   // Only construct the result if we have an |out_value| to populate.
   if (out_value)
     result = base::MakeUnique<base::DictionaryValue>();
+
   gin::Dictionary dictionary(context->GetIsolate(), object);
   for (const auto& kv : properties_) {
     v8::Local<v8::Value> subvalue;
@@ -282,6 +290,51 @@
     if (result)
       result->Set(kv.first, std::move(property));
   }
+
+  // Check for additional properties.
+  if (additional_properties_) {
+    v8::Local<v8::Array> own_property_names;
+    if (!object->GetOwnPropertyNames(context).ToLocal(&own_property_names))
+      return false;
+    uint32_t length = own_property_names->Length();
+    for (uint32_t i = 0; i < length; ++i) {
+      v8::Local<v8::Value> key;
+      if (!own_property_names->Get(context, i).ToLocal(&key))
+        return false;
+      // In JS, all keys are strings or numbers (or symbols, but those are
+      // excluded by GetOwnPropertyNames()). If you try to set anything else
+      // (e.g. an object), it is converted to a string.
+      DCHECK(key->IsString() || key->IsNumber());
+      v8::String::Utf8Value utf8_key(key);
+      // If the key was one of the specified properties, we've already handled
+      // it. Continue.
+      if (properties_.find(*utf8_key) != properties_.end())
+        continue;
+      v8::Local<v8::Value> subvalue;
+      // Fun: It's possible that a previous getter has removed the property from
+      // the object. This isn't that big of a deal, since it would only manifest
+      // in the case of some reasonably-crazy script objects, and it's probably
+      // not worth optimizing for the uncommon case to the detriment of the
+      // common (and either should be totally safe). We can always add a
+      // HasOwnProperty() check here in the future, if we desire.
+      if (!object->Get(context, key).ToLocal(&subvalue))
+        return false;
+
+      // We don't serialize undefined values.
+      // TODO(devlin): This matches current behavior, but it is correct?
+      if (subvalue->IsUndefined())
+        continue;
+
+      std::unique_ptr<base::Value> property;
+      if (!additional_properties_->ParseArgument(
+              context, subvalue, refs, result ? &property : nullptr, error)) {
+        return false;
+      }
+      if (result)
+        result->SetWithoutPathExpansion(*utf8_key, std::move(property));
+    }
+  }
+
   if (out_value)
     *out_value = std::move(result);
   return true;
diff --git a/extensions/renderer/argument_spec.h b/extensions/renderer/argument_spec.h
index 8c30d384..f0d4c16 100644
--- a/extensions/renderer/argument_spec.h
+++ b/extensions/renderer/argument_spec.h
@@ -118,6 +118,11 @@
   // The possible enum values, if defined for this argument.
   std::set<std::string> enum_values_;
 
+  // The specification for 'additional properties'. This is used when we want
+  // to allow the API to pass an object with arbitrary properties. Only
+  // applicable for ArgumentType::OBJECT.
+  std::unique_ptr<ArgumentSpec> additional_properties_;
+
   DISALLOW_COPY_AND_ASSIGN(ArgumentSpec);
 };
 
diff --git a/extensions/renderer/argument_spec_unittest.cc b/extensions/renderer/argument_spec_unittest.cc
index c6afd26..45de50c 100644
--- a/extensions/renderer/argument_spec_unittest.cc
+++ b/extensions/renderer/argument_spec_unittest.cc
@@ -290,6 +290,31 @@
     }
     ExpectFailure(spec, "1");
   }
+  {
+    const char kAnySpec[] = "{ 'type': 'any' }";
+    ArgumentSpec spec(*ValueFromString(kAnySpec));
+    ExpectSuccess(spec, "42", "42");
+    ExpectSuccess(spec, "'foo'", "'foo'");
+    ExpectSuccess(spec, "({prop1:'bar'})", "{'prop1':'bar'}");
+    ExpectSuccess(spec, "[1, 2, 3]", "[1,2,3]");
+    ExpectSuccess(spec, "[1, 'a']", "[1,'a']");
+    ExpectSuccess(spec, "null", base::Value());
+    ExpectSuccess(spec, "({prop1: 'alpha', prop2: null})",
+                  "{'prop1':'alpha','prop2':null}");
+    ExpectSuccess(spec,
+                  "x = {alpha: 'alpha'};\n"
+                  "y = {beta: 'beta', x: x};\n"
+                  "y;",
+                  "{'beta':'beta','x':{'alpha':'alpha'}}");
+    // We don't serialize undefined.
+    // TODO(devlin): This matches current behavior, but should it? Part of the
+    // problem is that base::Values don't differentiate between undefined and
+    // null, which is a potentially important distinction. However, this means
+    // that in serialization of an object {a: 1, foo:undefined}, we lose the
+    // 'foo' property.
+    ExpectFailure(spec, "undefined");
+    ExpectSuccess(spec, "({prop1: 1, prop2: undefined})", "{'prop1':1}");
+  }
 }
 
 TEST_F(ArgumentSpecUnitTest, TypeRefsTest) {
@@ -381,4 +406,101 @@
   }
 }
 
+TEST_F(ArgumentSpecUnitTest, AdditionalPropertiesTest) {
+  {
+    const char kOnlyAnyAdditionalProperties[] =
+        "{"
+        "  'type': 'object',"
+        "  'additionalProperties': {'type': 'any'}"
+        "}";
+    ArgumentSpec spec(*ValueFromString(kOnlyAnyAdditionalProperties));
+    ExpectSuccess(spec, "({prop1: 'alpha', prop2: 42, prop3: {foo: 'bar'}})",
+                  "{'prop1':'alpha','prop2':42,'prop3':{'foo':'bar'}}");
+    ExpectSuccess(spec, "({})", "{}");
+    // Test some crazy keys.
+    ExpectSuccess(spec,
+                  "var x = {};\n"
+                  "var y = {prop1: 'alpha'};\n"
+                  "y[42] = 'beta';\n"
+                  "y[x] = 'gamma';\n"
+                  "y[undefined] = 'delta';\n"
+                  "y;",
+                  "{'42':'beta','[object Object]':'gamma','prop1':'alpha',"
+                  "'undefined':'delta'}");
+    // We (typically*, see "Fun case" below) don't serialize properties on an
+    // object prototype.
+    ExpectSuccess(spec,
+                  "({\n"
+                  "  __proto__: {protoProp: 'proto'},\n"
+                  "  instanceProp: 'instance'\n"
+                  "})",
+                  "{'instanceProp':'instance'}");
+    // Fun case: Remove a property as a result of getting another. Currently,
+    // we don't check each property with HasOwnProperty() during iteration, so
+    // Fun case: Remove a property as a result of getting another. Currently,
+    // we don't check each property with HasOwnProperty() during iteration, so
+    // we still try to serialize it. But we don't serialize undefined, so in the
+    // case of the property not being defined on the prototype, this works as
+    // expected.
+    ExpectSuccess(spec,
+                  "var x = {};\n"
+                  "Object.defineProperty(\n"
+                  "    x, 'alpha',\n"
+                  "    {\n"
+                  "      enumerable: true,\n"
+                  "      get: () => { delete x.omega; return 'alpha'; }\n"
+                  "    });\n"
+                  "x.omega = 'omega';\n"
+                  "x;",
+                  "{'alpha':'alpha'}");
+    // Fun case continued: If an object removes the property, and the property
+    // *is* present on the prototype, then we serialize the value from the
+    // prototype. This is inconsistent, but only manifests scripts are doing
+    // crazy things (and is still safe).
+    // TODO(devlin): We *could* add a HasOwnProperty() check, in which case
+    // the result of this call should be {'alpha':'alpha'}.
+    ExpectSuccess(spec,
+                  "var x = {\n"
+                  "  __proto__: { omega: 'different omega' }\n"
+                  "};\n"
+                  "Object.defineProperty(\n"
+                  "    x, 'alpha',\n"
+                  "    {\n"
+                  "      enumerable: true,\n"
+                  "      get: () => { delete x.omega; return 'alpha'; }\n"
+                  "    });\n"
+                  "x.omega = 'omega';\n"
+                  "x;",
+                  "{'alpha':'alpha','omega':'different omega'}");
+  }
+  {
+    const char kPropertiesAndAnyAdditionalProperties[] =
+        "{"
+        "  'type': 'object',"
+        "  'properties': {"
+        "    'prop1': {'type': 'string'}"
+        "  },"
+        "  'additionalProperties': {'type': 'any'}"
+        "}";
+    ArgumentSpec spec(*ValueFromString(kPropertiesAndAnyAdditionalProperties));
+    ExpectSuccess(spec, "({prop1: 'alpha', prop2: 42, prop3: {foo: 'bar'}})",
+                  "{'prop1':'alpha','prop2':42,'prop3':{'foo':'bar'}}");
+    // Additional properties are optional.
+    ExpectSuccess(spec, "({prop1: 'foo'})", "{'prop1':'foo'}");
+    ExpectFailure(spec, "({prop2: 42, prop3: {foo: 'bar'}})");
+    ExpectFailure(spec, "({prop1: 42})");
+  }
+  {
+    const char kTypedAdditionalProperties[] =
+        "{"
+        "  'type': 'object',"
+        "  'additionalProperties': {'type': 'string'}"
+        "}";
+    ArgumentSpec spec(*ValueFromString(kTypedAdditionalProperties));
+    ExpectSuccess(spec, "({prop1: 'alpha', prop2: 'beta', prop3: 'gamma'})",
+                  "{'prop1':'alpha','prop2':'beta','prop3':'gamma'}");
+    ExpectFailure(spec, "({prop1: 'alpha', prop2: 42})");
+  }
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/native_extension_bindings_system.cc b/extensions/renderer/native_extension_bindings_system.cc
index 1ff3cd5..31758c7 100644
--- a/extensions/renderer/native_extension_bindings_system.cc
+++ b/extensions/renderer/native_extension_bindings_system.cc
@@ -326,7 +326,8 @@
           base::Bind(&NativeExtensionBindingsSystem::SendRequest,
                      base::Unretained(this)),
           base::Bind(&NativeExtensionBindingsSystem::OnEventListenerChanged,
-                     base::Unretained(this))),
+                     base::Unretained(this)),
+          APILastError(base::Bind(&GetRuntime))),
       weak_factory_(this) {}
 
 NativeExtensionBindingsSystem::~NativeExtensionBindingsSystem() {}
@@ -403,7 +404,7 @@
     v8::Local<v8::String> api_name =
         gin::StringToSymbol(v8_context->GetIsolate(), accessor_name);
     v8::Maybe<bool> success = chrome->SetAccessor(
-        v8_context, api_name, &GetAPIHelper, nullptr, api_name);
+        v8_context, api_name, &BindingAccessor, nullptr, api_name);
     if (!success.IsJust() || !success.FromJust()) {
       LOG(ERROR) << "Failed to create API on Chrome object.";
       return;
@@ -428,24 +429,37 @@
     bool success,
     const base::ListValue& response,
     const std::string& error) {
-  api_system_.CompleteRequest(request_id, response);
+  api_system_.CompleteRequest(request_id, response, error);
 }
 
 RequestSender* NativeExtensionBindingsSystem::GetRequestSender() {
   return nullptr;
 }
 
-// static
-void NativeExtensionBindingsSystem::GetAPIHelper(
+void NativeExtensionBindingsSystem::BindingAccessor(
     v8::Local<v8::Name> name,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   v8::Isolate* isolate = info.GetIsolate();
   v8::HandleScope handle_scope(isolate);
   v8::Local<v8::Context> context = info.Holder()->CreationContext();
+
+  // We use info.Data() to store a real name here instead of using the provided
+  // one to handle any weirdness from the caller (non-existent strings, etc).
+  v8::Local<v8::String> api_name = info.Data().As<v8::String>();
+  v8::Local<v8::Object> binding = GetAPIHelper(context, api_name);
+  if (!binding.IsEmpty())
+    info.GetReturnValue().Set(binding);
+}
+
+// static
+v8::Local<v8::Object> NativeExtensionBindingsSystem::GetAPIHelper(
+    v8::Local<v8::Context> context,
+    v8::Local<v8::String> api_name) {
   BindingsSystemPerContextData* data = GetBindingsDataFromContext(context);
   if (!data)
-    return;
+    return v8::Local<v8::Object>();
 
+  v8::Isolate* isolate = context->GetIsolate();
   v8::Local<v8::Object> apis;
   if (data->api_object.IsEmpty()) {
     apis = v8::Object::New(isolate);
@@ -465,38 +479,41 @@
           ->GetFunction(context)
           .ToLocalChecked();
 
-  // We use info.Data() to store a real name here instead of using the provided
-  // one to handle any weirdness from the caller (non-existent strings, etc).
-  v8::Local<v8::String> api_name = info.Data().As<v8::String>();
-  v8::Local<v8::Value> result;
   v8::Maybe<bool> has_property = apis->HasRealNamedProperty(context, api_name);
   if (!has_property.IsJust())
-    return;
+    return v8::Local<v8::Object>();
 
   if (has_property.FromJust()) {
-    result = apis->GetRealNamedProperty(context, api_name).ToLocalChecked();
-  } else {
-    ScriptContext* script_context =
-        ScriptContextSet::GetContextByV8Context(context);
-    std::string api_name_string;
-    CHECK(gin::Converter<std::string>::FromV8(isolate, api_name,
-                                              &api_name_string));
-
-    v8::Local<v8::Object> root_binding = CreateFullBinding(
-        context, script_context, &data->bindings_system->api_system_,
-        FeatureProvider::GetAPIFeatures(), api_name_string, get_internal_api);
-    if (root_binding.IsEmpty())
-      return;
-
-    v8::Maybe<bool> success =
-        apis->CreateDataProperty(context, api_name, root_binding);
-    if (!success.IsJust() || !success.FromJust())
-      return;
-
-    result = root_binding;
+    v8::Local<v8::Value> value =
+        apis->GetRealNamedProperty(context, api_name).ToLocalChecked();
+    DCHECK(value->IsObject());
+    return value.As<v8::Object>();
   }
 
-  info.GetReturnValue().Set(result);
+  ScriptContext* script_context =
+      ScriptContextSet::GetContextByV8Context(context);
+  std::string api_name_string;
+  CHECK(
+      gin::Converter<std::string>::FromV8(isolate, api_name, &api_name_string));
+
+  v8::Local<v8::Object> root_binding = CreateFullBinding(
+      context, script_context, &data->bindings_system->api_system_,
+      FeatureProvider::GetAPIFeatures(), api_name_string, get_internal_api);
+  if (root_binding.IsEmpty())
+    return v8::Local<v8::Object>();
+
+  v8::Maybe<bool> success =
+      apis->CreateDataProperty(context, api_name, root_binding);
+  if (!success.IsJust() || !success.FromJust())
+    return v8::Local<v8::Object>();
+
+  return root_binding;
+}
+
+v8::Local<v8::Object> NativeExtensionBindingsSystem::GetRuntime(
+    v8::Local<v8::Context> context) {
+  return GetAPIHelper(context,
+                      gin::StringToSymbol(context->GetIsolate(), "runtime"));
 }
 
 // static
diff --git a/extensions/renderer/native_extension_bindings_system.h b/extensions/renderer/native_extension_bindings_system.h
index b414fc1..d6d24e39 100644
--- a/extensions/renderer/native_extension_bindings_system.h
+++ b/extensions/renderer/native_extension_bindings_system.h
@@ -68,8 +68,15 @@
                               v8::Local<v8::Context> context);
 
   // Getter callback for an extension API, since APIs are constructed lazily.
-  static void GetAPIHelper(v8::Local<v8::Name> name,
-                           const v8::PropertyCallbackInfo<v8::Value>& info);
+  static void BindingAccessor(v8::Local<v8::Name> name,
+                              const v8::PropertyCallbackInfo<v8::Value>& info);
+
+  // Creates and returns the API binding for the given |name|.
+  static v8::Local<v8::Object> GetAPIHelper(v8::Local<v8::Context> context,
+                                            v8::Local<v8::String> name);
+
+  // Gets the chrome.runtime API binding.
+  static v8::Local<v8::Object> GetRuntime(v8::Local<v8::Context> context);
 
   // Callback to get an API binding for an internal API.
   static void GetInternalAPI(const v8::FunctionCallbackInfo<v8::Value>& info);
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index 78c498c..6bd2788 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -601,4 +601,47 @@
   EXPECT_TRUE(last_params().has_callback);
 }
 
+TEST_F(NativeExtensionBindingsSystemUnittest, TestLastError) {
+  scoped_refptr<Extension> extension =
+      CreateExtension("foo", ItemType::EXTENSION, {"idle", "power"});
+  RegisterExtension(extension->id());
+
+  v8::HandleScope handle_scope(isolate());
+  v8::Local<v8::Context> context = ContextLocal();
+
+  ScriptContext* script_context = CreateScriptContext(
+      context, extension.get(), Feature::BLESSED_EXTENSION_CONTEXT);
+  script_context->set_url(extension->url());
+
+  bindings_system()->UpdateBindingsForContext(script_context);
+
+  {
+    // Try calling the function with an invalid invocation - an error should be
+    // thrown.
+    const char kCallFunction[] =
+        "(function() {\n"
+        "  chrome.idle.queryState(30, function(state) {\n"
+        "    if (chrome.runtime.lastError)\n"
+        "      this.lastErrorMessage = chrome.runtime.lastError.message;\n"
+        "  });\n"
+        "});";
+    v8::Local<v8::Function> function =
+        FunctionFromString(context, kCallFunction);
+    ASSERT_FALSE(function.IsEmpty());
+    RunFunctionOnGlobal(function, context, 0, nullptr);
+  }
+
+  // Validate the params that would be sent to the browser.
+  EXPECT_EQ(extension->id(), last_params().extension_id);
+  EXPECT_EQ("idle.queryState", last_params().name);
+
+  // Respond and validate.
+  bindings_system()->HandleResponse(last_params().request_id, true,
+                                    base::ListValue(), "Some API Error");
+
+  EXPECT_EQ("\"Some API Error\"",
+            GetStringPropertyFromObject(context->Global(), context,
+                                        "lastErrorMessage"));
+}
+
 }  // namespace extensions
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index e8b8385..a4acdd1 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -138,8 +138,9 @@
   feature_flags_.enable_shader_name_hashing =
       !command_line->HasSwitch(switches::kDisableShaderNameHashing);
 
-  feature_flags_.is_swiftshader =
-      (command_line->GetSwitchValueASCII(switches::kUseGL) == "swiftshader");
+  feature_flags_.is_swiftshader_for_webgl =
+      (command_line->GetSwitchValueASCII(switches::kUseGL) ==
+       gl::kGLImplementationSwiftShaderForWebGLName);
 
   // The shader translator is needed to translate from WebGL-conformant GLES SL
   // to normal GLES SL, enforce WebGL conformance, translate from GLES SL 1.0 to
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index 1545e38..981fc05 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -77,7 +77,7 @@
     bool map_buffer_range = false;
     bool ext_discard_framebuffer = false;
     bool angle_depth_texture = false;
-    bool is_swiftshader = false;
+    bool is_swiftshader_for_webgl = false;
     bool angle_texture_usage = false;
     bool ext_texture_storage = false;
     bool chromium_path_rendering = false;
diff --git a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
index fa3f33e3..4b9d7e43 100644
--- a/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
+++ b/gpu/command_buffer/service/gles2_cmd_apply_framebuffer_attachment_cmaa_intel.cc
@@ -274,8 +274,9 @@
         }
         if (!copy_tex_image_format_valid)
           method = DIRECT_DRAW;
-        bool color_renderable = Texture::ColorRenderable(
-            decoder->GetFeatureInfo(), internal_format, false);
+        bool color_renderable =
+            Texture::ColorRenderable(decoder->GetFeatureInfo(), internal_format,
+                                     texture->texture()->IsImmutable());
 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_X86_FAMILY)
         // glDrawArrays is faster than glCopyTexSubImage2D on IA Mesa driver,
         // although opposite in Android.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 6ec95988..059ab5b2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -3115,7 +3115,7 @@
   // If the failIfMajorPerformanceCaveat context creation attribute was true
   // and we are using a software renderer, fail.
   if (attrib_helper.fail_if_major_perf_caveat &&
-      feature_info_->feature_flags().is_swiftshader) {
+      feature_info_->feature_flags().is_swiftshader_for_webgl) {
     group_ = NULL;  // Must not destroy ContextGroup if it is not initialized.
     Destroy(true);
     return false;
@@ -16714,7 +16714,8 @@
   // although opposite in Android.
   // TODO(dshwang): After Mesa fixes this issue, remove this hack.
   // https://bugs.freedesktop.org/show_bug.cgi?id=98478, crbug.com/535198.
-  if (Texture::ColorRenderable(GetFeatureInfo(), dest_internal_format, false) &&
+  if (Texture::ColorRenderable(GetFeatureInfo(), dest_internal_format,
+                               dest_texture->IsImmutable()) &&
       method == DIRECT_COPY) {
     method = DIRECT_DRAW;
   }
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index a12cf38..d13b817 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -252,7 +252,8 @@
     std::string requested_implementation_name =
         base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
             switches::kUseGL);
-    if (requested_implementation_name == "swiftshader") {
+    if (requested_implementation_name ==
+        gl::kGLImplementationSwiftShaderForWebGLName) {
       gpu_info->software_rendering = true;
       gpu_info->context_info_state = kCollectInfoNonFatalFailure;
       return kCollectInfoNonFatalFailure;
diff --git a/gpu/config/software_rendering_list_json.cc b/gpu/config/software_rendering_list_json.cc
index 55bcef1b..b9786b0 100644
--- a/gpu/config/software_rendering_list_json.cc
+++ b/gpu/config/software_rendering_list_json.cc
@@ -18,7 +18,7 @@
 {
   "name": "software rendering list",
   // Please update the version number whenever you change this file.
-  "version": "12.10",
+  "version": "12.12",
   "entries": [
     {
       "id": 1,
@@ -1462,6 +1462,34 @@
       "features": [
         "all"
       ]
+    },
+    {
+      "id": 132,
+      "description": "Mali accelerated 2d canvas is slow on Linux",
+      "cr_bugs": [691601],
+      "os": {
+        "type": "linux"
+      },
+      "gl_renderer": "Mali-4.*",
+      "features": [
+        "accelerated_2d_canvas"
+      ]
+    },
+    {
+      "id": 133,
+      "description": "MediaCodec on VideoCore IV HW crashes on JB",
+      "cr_bugs": [654905],
+      "os": {
+        "type": "android",
+        "version": {
+          "op": "<",
+          "value": "4.4"
+        }
+      },
+      "gl_renderer": ".*VideoCore IV.*",
+      "features": [
+        "accelerated_video_decode"
+      ]
     }
   ]
 }
diff --git a/headless/README.md b/headless/README.md
index 7886871c..062106e 100644
--- a/headless/README.md
+++ b/headless/README.md
@@ -23,6 +23,37 @@
 [DevTools](https://developer.chrome.com/devtools) interface or use a tool such
 as [Selenium](http://www.seleniumhq.org/) to drive the headless browser.
 
+## Usage from Node.js
+
+For example, the [chrome-remote-interface](https://github.com/cyrus-and/chrome-remote-interface)
+Node.js package can be used to extract a page's DOM like this:
+
+```
+const CDP = require('chrome-remote-interface');
+
+CDP((client) => {
+  // Extract used DevTools domains.
+  const {Page, Runtime} = client;
+
+  // Enable events on domains we are interested in.
+  Promise.all([
+    Page.enable()
+  ]).then(() => {
+    return Page.navigate({url: 'https://example.com'});
+  });
+
+  // Evaluate outerHTML after page has loaded.
+  Page.loadEventFired(() => {
+    Runtime.evaluate({expression: 'document.body.outerHTML'}).then((result) => {
+      console.log(result.result.value);
+      client.close();
+    });
+  });
+}).on('error', (err) => {
+  console.error('Cannot connect to browser:', err);
+});
+```
+
 ## Usage as a C++ library
 
 Headless Chromium can be built as a library for embedding into a C++
diff --git a/ios/build/bots/chromium.fyi/EarlGreyiOS.json b/ios/build/bots/chromium.fyi/EarlGreyiOS.json
index 0bbb157..0bea78a 100644
--- a/ios/build/bots/chromium.fyi/EarlGreyiOS.json
+++ b/ios/build/bots/chromium.fyi/EarlGreyiOS.json
@@ -18,84 +18,98 @@
       "app": "ios_chrome_integration_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_settings_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_smoke_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_ui_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_web_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_showcase_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_web_shell_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_integration_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_settings_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_smoke_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_ui_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_web_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_showcase_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_web_shell_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     }
   ]
diff --git a/ios/build/bots/chromium.fyi/ios-simulator-cronet.json b/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
index 23804e5..7dd030a 100644
--- a/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
+++ b/ios/build/bots/chromium.fyi/ios-simulator-cronet.json
@@ -24,12 +24,14 @@
     {
       "app": "cronet_test",
       "device type": "iPhone 5s",
-      "os": "9.3"
+      "os": "9.3",
+      "xcode version": "8.0"
     },
     {
       "app": "cronet_test",
       "device type": "iPad Retina",
-      "os": "9.3"
+      "os": "9.3",
+      "xcode version": "8.0"
     }
   ]
 }
diff --git a/ios/build/bots/chromium.fyi/ios-simulator.json b/ios/build/bots/chromium.fyi/ios-simulator.json
index de6c3e1..872baca2 100644
--- a/ios/build/bots/chromium.fyi/ios-simulator.json
+++ b/ios/build/bots/chromium.fyi/ios-simulator.json
@@ -19,52 +19,62 @@
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s Plus",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 5",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Air 2",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Retina",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s Plus",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 5",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Air 2",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Retina",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     }
   ]
 }
diff --git a/ios/build/bots/chromium.mac/ios-simulator-cronet.json b/ios/build/bots/chromium.mac/ios-simulator-cronet.json
index 23804e5..7dd030a 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-cronet.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-cronet.json
@@ -24,12 +24,14 @@
     {
       "app": "cronet_test",
       "device type": "iPhone 5s",
-      "os": "9.3"
+      "os": "9.3",
+      "xcode version": "8.0"
     },
     {
       "app": "cronet_test",
       "device type": "iPad Retina",
-      "os": "9.3"
+      "os": "9.3",
+      "xcode version": "8.0"
     }
   ]
 }
diff --git a/ios/build/bots/chromium.mac/ios-simulator-eg.json b/ios/build/bots/chromium.mac/ios-simulator-eg.json
index 39b591f..110790c 100644
--- a/ios/build/bots/chromium.mac/ios-simulator-eg.json
+++ b/ios/build/bots/chromium.mac/ios-simulator-eg.json
@@ -18,84 +18,98 @@
       "app": "ios_chrome_integration_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_settings_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_smoke_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_ui_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_web_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_showcase_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_web_shell_egtests",
       "device type": "iPhone 6s",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_integration_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_settings_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_smoke_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_ui_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_chrome_web_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_showcase_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     },
     {
       "app": "ios_web_shell_egtests",
       "device type": "iPad Air 2",
       "os": "10.0",
+      "xcode version": "8.0",
       "xctest": true
     }
   ]
diff --git a/ios/build/bots/chromium.mac/ios-simulator.json b/ios/build/bots/chromium.mac/ios-simulator.json
index b0c0181..95357ffd 100644
--- a/ios/build/bots/chromium.mac/ios-simulator.json
+++ b/ios/build/bots/chromium.mac/ios-simulator.json
@@ -22,52 +22,62 @@
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s Plus",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 5",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Air 2",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Retina",
-      "os": "10.0"
+      "os": "10.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s Plus",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 6s",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPhone 5",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Air 2",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     },
     {
       "include": "common_tests.json",
       "device type": "iPad Retina",
-      "os": "9.0"
+      "os": "9.0",
+      "xcode version": "8.0"
     }
   ]
 }
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index 7dd1d6e..5a4c3f0 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -1796,6 +1796,10 @@
   [parentTabModel_ notifyTabChanged:self];
 }
 
+- (void)webStateDidDismissInterstitial:(web::WebState*)webState {
+  [parentTabModel_ notifyTabChanged:self];
+}
+
 - (void)webLoadCancelled:(const GURL&)url {
   // When a load is cancelled, this is the maximum that a page will ever load.
   [fullScreenController_ enableFullScreen];
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm
index df453b4f..02c6255 100644
--- a/ios/chrome/browser/ui/history/history_ui_egtest.mm
+++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -273,8 +273,7 @@
 }
 
 // Tests that history is not changed after performing back navigation.
-// TODO(crbug.com/688047): Enable this test.
-- (void)DISABLED_testHistoryUpdateAfterBackNavigation {
+- (void)testHistoryUpdateAfterBackNavigation {
   [ChromeEarlGrey loadURL:_URL1];
   [ChromeEarlGrey loadURL:_URL2];
 
diff --git a/ios/chrome/browser/ui/history/tab_history_popup_controller_unittest.mm b/ios/chrome/browser/ui/history/tab_history_popup_controller_unittest.mm
index 0ee4a53..3782087 100644
--- a/ios/chrome/browser/ui/history/tab_history_popup_controller_unittest.mm
+++ b/ios/chrome/browser/ui/history/tab_history_popup_controller_unittest.mm
@@ -13,7 +13,6 @@
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/web/navigation/crw_session_entry.h"
 #include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_item_list.h"
 #include "ios/web/public/referrer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -32,38 +31,37 @@
 
 class TabHistoryPopupControllerTest : public PlatformTest {
  protected:
-  TabHistoryPopupControllerTest() : PlatformTest() {
+  void SetUp() override {
     parent_.reset([[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds]);
-    // Create test items and populate |items_|.
-    web::Referrer referrer(GURL("http://www.example.com"),
-                           web::ReferrerPolicyDefault);
-    items_.push_back(web::NavigationItem::Create());
-    items_.back()->SetURL(GURL("http://www.example.com/0"));
-    items_.back()->SetReferrer(referrer);
-    items_.push_back(web::NavigationItem::Create());
-    items_.back()->SetURL(GURL("http://www.example.com/1"));
-    items_.back()->SetReferrer(referrer);
-    items_.push_back(web::NavigationItem::Create());
-    items_.back()->SetURL(GURL("http://www.example.com/2"));
-    items_.back()->SetReferrer(referrer);
-    // Create the popup controller using CRWSessionEntries created from the
-    // NavigationItems in |items_|.
     popup_.reset([[TabHistoryPopupController alloc]
         initWithOrigin:CGPointZero
             parentView:parent_
-               entries:EntriesListForItems(items_)]);
+               entries:testEntriesArray()]);
   }
-
-  NSArray* EntriesListForItems(const web::ScopedNavigationItemList& items) {
-    NSMutableArray* entries = [NSMutableArray array];
-    for (size_t index = 0; index < items.size(); ++index) {
-      base::scoped_nsobject<CRWSessionEntry> entry(
-          [[CRWSessionEntry alloc] initWithNavigationItem:items[index].get()]);
-      [entries addObject:entry];
-    }
-    return entries;
+  void TearDown() override {
+    parent_.reset();
+    popup_.reset();
   }
-  web::ScopedNavigationItemList items_;
+  NSArray* testEntriesArray() {
+    web::Referrer referrer(GURL("http://www.example.com"),
+                           web::ReferrerPolicyDefault);
+    std::unique_ptr<web::NavigationItem> item0 = web::NavigationItem::Create();
+    item0->SetURL(GURL("http://www.example.com/0"));
+    item0->SetReferrer(referrer);
+    CRWSessionEntry* entry0 =
+        [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item0)];
+    std::unique_ptr<web::NavigationItem> item1 = web::NavigationItem::Create();
+    item1->SetURL(GURL("http://www.example.com/1"));
+    item1->SetReferrer(referrer);
+    CRWSessionEntry* entry1 =
+        [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item1)];
+    std::unique_ptr<web::NavigationItem> item2 = web::NavigationItem::Create();
+    item2->SetURL(GURL("http://www.example.com/2"));
+    item2->SetReferrer(referrer);
+    CRWSessionEntry* entry2 =
+        [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item2)];
+    return [NSArray arrayWithObjects:entry0, entry1, entry2, nil];
+  }
   base::scoped_nsobject<UIView> parent_;
   base::scoped_nsobject<TabHistoryPopupController> popup_;
 };
@@ -83,6 +81,30 @@
 }
 
 TEST_F(TabHistoryPopupControllerTest, TestCalculatePopupWidth) {
+  web::Referrer referrer(GURL("http://www.example.com"),
+                         web::ReferrerPolicyDefault);
+  std::unique_ptr<web::NavigationItem> itemShort =
+      web::NavigationItem::Create();
+  itemShort->SetURL(GURL("http://foo.com/"));
+  itemShort->SetReferrer(referrer);
+  CRWSessionEntry* entryShort =
+      [[CRWSessionEntry alloc] initWithNavigationItem:std::move(itemShort)];
+  std::unique_ptr<web::NavigationItem> itemMedium =
+      web::NavigationItem::Create();
+  itemMedium->SetURL(GURL("http://www.example.com/mediumurl"));
+  itemMedium->SetReferrer(referrer);
+  CRWSessionEntry* entryMedium =
+      [[CRWSessionEntry alloc] initWithNavigationItem:std::move(itemMedium)];
+  std::string longURL =
+      "http://www.example.com/this/is/areally/long/url/that/"
+      "is/larger/than/the/maximum/table/width/so/its/text/will/get/cut/off/and/"
+      "the/max/width/is/used/";
+  std::unique_ptr<web::NavigationItem> itemLong = web::NavigationItem::Create();
+  itemLong->SetURL(GURL(longURL));
+  itemLong->SetReferrer(referrer);
+  CRWSessionEntry* entryLong =
+      [[CRWSessionEntry alloc] initWithNavigationItem:std::move(itemLong)];
+
   CGFloat minWidth = kTabHistoryMinWidth;
   CGFloat maxWidth = kTabHistoryMinWidth;
   if (!IsIPadIdiom()) {
@@ -94,28 +116,20 @@
     maxWidth = ui::AlignValueToUpperPixel(
         [UIApplication sharedApplication].keyWindow.frame.size.width * .85);
   }
-  web::Referrer referrer(GURL("http://www.example.com"),
-                         web::ReferrerPolicyDefault);
-  web::ScopedNavigationItemList items;
-  items.push_back(web::NavigationItem::Create());
-  items.back()->SetURL(GURL("http://foo.com/"));
-  items.back()->SetReferrer(referrer);
-  CGFloat width = [popup_ calculatePopupWidth:EntriesListForItems(items)];
+
+  CGFloat width =
+      [popup_ calculatePopupWidth:[NSArray arrayWithObjects:entryShort, nil]];
   EXPECT_EQ(minWidth, width);
-  items.push_back(web::NavigationItem::Create());
-  items.back()->SetURL(GURL("http://www.example.com/mediumurl"));
-  items.back()->SetReferrer(referrer);
-  width = [popup_ calculatePopupWidth:EntriesListForItems(items)];
+
+  width =
+      [popup_ calculatePopupWidth:[NSArray arrayWithObjects:entryShort,
+                                                            entryMedium, nil]];
   EXPECT_GE(width, minWidth);
   EXPECT_LE(width, maxWidth);
-  std::string long_url =
-      "http://www.example.com/this/is/areally/long/url/that/"
-      "is/larger/than/the/maximum/table/width/so/its/text/will/get/cut/off/and/"
-      "the/max/width/is/used/";
-  items.push_back(web::NavigationItem::Create());
-  items.back()->SetURL(GURL(long_url));
-  items.back()->SetReferrer(referrer);
-  width = [popup_ calculatePopupWidth:EntriesListForItems(items)];
+
+  width = [popup_
+      calculatePopupWidth:[NSArray arrayWithObjects:entryShort, entryLong,
+                                                    entryMedium, nil]];
   EXPECT_EQ(maxWidth, width);
 }
 
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.mm
index c29af39..fcc3318 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_collection_view_controller.mm
@@ -214,9 +214,12 @@
     return _attributesProvider;
   }
 
+  // Accept any favicon even the smallest ones (16x16) as it is better than the
+  // fallback icon.
+  // Pass 1 as minimum size to avoid empty favicons.
   _attributesProvider = [[FaviconAttributesProvider alloc]
       initWithFaviconSize:kFaviconPreferredSize
-           minFaviconSize:kFaviconMinSize
+           minFaviconSize:1
          largeIconService:self.largeIconService];
   return _attributesProvider;
 }
diff --git a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
index a717efd..9039879a 100644
--- a/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
+++ b/ios/chrome/browser/ui/side_swipe/side_swipe_controller.mm
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#import "base/ios/weak_nsobject.h"
 #include "components/reading_list/core/reading_list_switches.h"
 #import "components/reading_list/ios/reading_list_model.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
@@ -50,7 +51,7 @@
                                   UIGestureRecognizerDelegate> {
  @private
 
-  TabModel* model_;
+  base::WeakNSObject<TabModel> model_;
 
   // Side swipe view for tab navigation.
   base::scoped_nsobject<CardSideSwipeView> tabSideSwipeView_;
@@ -117,7 +118,7 @@
   DCHECK(model);
   self = [super init];
   if (self) {
-    model_ = model;
+    model_.reset(model);
     [model_ addObserver:self];
     historySideSwipeProvider_.reset(
         [[HistorySideSwipeProvider alloc] initWithTabModel:model_]);
@@ -254,14 +255,14 @@
     index = index + dx;
   }
   [[SnapshotCache sharedInstance] createGreyCache:sessionIDs];
-  for (Tab* tab in model_) {
+  for (Tab* tab in model_.get()) {
     tab.useGreyImageCache = YES;
   }
 }
 
 - (void)deleteGreyCache {
   [[SnapshotCache sharedInstance] removeGreyCache];
-  for (Tab* tab in model_) {
+  for (Tab* tab in model_.get()) {
     tab.useGreyImageCache = NO;
   }
 }
diff --git a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
index 0cdde28..b3787b4 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
@@ -33,6 +33,10 @@
     "tab_grid_tab_cell.mm",
     "tab_grid_view_controller.h",
     "tab_grid_view_controller.mm",
+    "ui_button+cr_tab_grid.h",
+    "ui_button+cr_tab_grid.mm",
+    "ui_stack_view+cr_tab_grid.h",
+    "ui_stack_view+cr_tab_grid.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index a599f72..e5a8980 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -17,14 +17,17 @@
 #import "ios/clean/chrome/browser/ui/commands/tab_commands.h"
 #import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h"
 #import "ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.h"
+#import "ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
 namespace {
-const CGFloat kSpace = 20;
-const CGFloat kTabSize = 150;
+const CGFloat kSpace = 20.0f;
+const CGFloat kTabSize = 150.0f;
+// Height of toolbar in tab grid.
+const CGFloat kToolbarHeight = 64.0f;
 }
 
 @interface TabGridViewController ()<SettingsActions,
@@ -46,30 +49,15 @@
 @synthesize floatingNewTabButton = _floatingNewTabButton;
 
 - (void)viewDidLoad {
-  // Placeholder dark grey stripe at the top of the view.
-  UIView* stripe = [[UIView alloc] initWithFrame:CGRectZero];
-  stripe.translatesAutoresizingMaskIntoConstraints = NO;
-  stripe.backgroundColor = [UIColor darkGrayColor];
-  [self.view addSubview:stripe];
+  UIView* toolbar = [UIStackView cr_tabGridToolbarStackView];
+  [self.view addSubview:toolbar];
 
-  // Placeholder settings button at in the stripe.
-  UIButton* settings = [UIButton buttonWithType:UIButtonTypeSystem];
-  settings.translatesAutoresizingMaskIntoConstraints = NO;
-  [settings setTitle:@"⚙" forState:UIControlStateNormal];
-  settings.titleLabel.font = [UIFont systemFontOfSize:24.0];
-  [settings addTarget:nil
-                action:@selector(showSettings:)
-      forControlEvents:UIControlEventTouchUpInside];
-  [stripe addSubview:settings];
-
+  toolbar.translatesAutoresizingMaskIntoConstraints = NO;
   [NSLayoutConstraint activateConstraints:@[
-    [stripe.heightAnchor constraintEqualToConstant:64.0],
-    [stripe.widthAnchor constraintEqualToAnchor:self.view.widthAnchor],
-    [stripe.topAnchor constraintEqualToAnchor:self.view.topAnchor],
-    [stripe.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],
-    [settings.leadingAnchor
-        constraintEqualToAnchor:stripe.layoutMarginsGuide.leadingAnchor],
-    [settings.centerYAnchor constraintEqualToAnchor:stripe.centerYAnchor]
+    [toolbar.heightAnchor constraintEqualToConstant:kToolbarHeight],
+    [toolbar.widthAnchor constraintEqualToAnchor:self.view.widthAnchor],
+    [toolbar.topAnchor constraintEqualToAnchor:self.view.topAnchor],
+    [toolbar.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor]
   ]];
 
   TabSwitcherPanelCollectionViewLayout* layout =
@@ -92,7 +80,7 @@
       forCellWithReuseIdentifier:[TabSwitcherLocalSessionCell identifier]];
 
   [NSLayoutConstraint activateConstraints:@[
-    [self.grid.topAnchor constraintEqualToAnchor:stripe.bottomAnchor],
+    [self.grid.topAnchor constraintEqualToAnchor:toolbar.bottomAnchor],
     [self.grid.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
     [self.grid.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
     [self.grid.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
diff --git a/ios/clean/chrome/browser/ui/tab_grid/ui_button+cr_tab_grid.h b/ios/clean/chrome/browser/ui/tab_grid/ui_button+cr_tab_grid.h
new file mode 100644
index 0000000..26aa6fa4
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/tab_grid/ui_button+cr_tab_grid.h
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_UI_BUTTON_CR_TAB_GRID_H_
+#define IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_UI_BUTTON_CR_TAB_GRID_H_
+
+#import <UIKit/UIKit.h>
+
+// This category provides default styling for buttons used in the tab grid.
+@interface UIButton (CRTabGrid)
+
+// Constructs done button in the tab grid toolbar.
++ (instancetype)cr_tabGridToolbarDoneButton;
+
+// Constructs the incognito button in the tab grid toolbar.
++ (instancetype)cr_tabGridToolbarIncognitoButton;
+
+// Constructs the menu button in the tab grid toolbar.
++ (instancetype)cr_tabGridToolbarMenuButton;
+
+@end
+
+#endif  // IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_UI_BUTTON_CR_TAB_GRID_H_
diff --git a/ios/clean/chrome/browser/ui/tab_grid/ui_button+cr_tab_grid.mm b/ios/clean/chrome/browser/ui/tab_grid/ui_button+cr_tab_grid.mm
new file mode 100644
index 0000000..b2c0cc05
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/tab_grid/ui_button+cr_tab_grid.mm
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/clean/chrome/browser/ui/tab_grid/ui_button+cr_tab_grid.h"
+
+#import "ios/clean/chrome/browser/ui/actions/settings_actions.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation UIButton (CRTabGrid)
+
++ (instancetype)cr_tabGridToolbarDoneButton {
+  UIButton* button = [self buttonWithType:UIButtonTypeSystem];
+  [button.titleLabel setFont:[MDCTypography buttonFont]];
+  [button setTitle:@"Done" forState:UIControlStateNormal];
+  [button setTintColor:[UIColor whiteColor]];
+  return button;
+}
+
++ (instancetype)cr_tabGridToolbarIncognitoButton {
+  UIButton* button = [self buttonWithType:UIButtonTypeSystem];
+  UIImage* image = [[UIImage imageNamed:@"tabswitcher_incognito"]
+      imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
+  [button setImage:image forState:UIControlStateNormal];
+  [button setTintColor:[UIColor whiteColor]];
+  return button;
+}
+
++ (instancetype)cr_tabGridToolbarMenuButton {
+  UIButton* button = [self buttonWithType:UIButtonTypeSystem];
+  [button setImage:[UIImage imageNamed:@"tabswitcher_menu"]
+          forState:UIControlStateNormal];
+  [button setTintColor:[UIColor whiteColor]];
+  [button addTarget:nil
+                action:@selector(showSettings:)
+      forControlEvents:UIControlEventTouchUpInside];
+  return button;
+}
+
+@end
diff --git a/ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.h b/ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.h
new file mode 100644
index 0000000..efdda904
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.h
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_UI_STACK_VIEW_CR_TAB_GRID_H_
+#define IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_UI_STACK_VIEW_CR_TAB_GRID_H_
+
+#import <UIKit/UIKit.h>
+
+// This category provides default styling for the toolbar used in the tab grid.
+@interface UIStackView (CRTabGrid)
+
+// Constructs a tab grid toolbar with buttons.
++ (instancetype)cr_tabGridToolbarStackView;
+
+@end
+
+#endif  // IOS_CLEAN_CHROME_BROWSER_UI_TAB_GRID_UI_STACK_VIEW_CR_TAB_GRID_H_
diff --git a/ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.mm b/ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.mm
new file mode 100644
index 0000000..835a3bf0
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.mm
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.h"
+
+#import "ios/chrome/browser/ui/rtl_geometry.h"
+#import "ios/clean/chrome/browser/ui/tab_grid/ui_button+cr_tab_grid.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+const CGFloat kSpacing = 16.0f;
+}
+
+@implementation UIStackView (CRTabGrid)
+
++ (instancetype)cr_tabGridToolbarStackView {
+  UIView* spacerView = [[UIView alloc] init];
+  [spacerView setContentHuggingPriority:UILayoutPriorityDefaultLow
+                                forAxis:UILayoutConstraintAxisHorizontal];
+  NSArray* items = @[
+    [UIButton cr_tabGridToolbarDoneButton],
+    [UIButton cr_tabGridToolbarIncognitoButton], spacerView,
+    [UIButton cr_tabGridToolbarMenuButton]
+  ];
+  UIStackView* toolbar = [[self alloc] initWithArrangedSubviews:items];
+  toolbar.layoutMarginsRelativeArrangement = YES;
+  toolbar.layoutMargins = UIEdgeInsetsMakeDirected(0, kSpacing, 0, kSpacing);
+  toolbar.spacing = kSpacing;
+  toolbar.distribution = UIStackViewDistributionFill;
+  return toolbar;
+}
+
+@end
diff --git a/ios/showcase/common/protocol_alerter.mm b/ios/showcase/common/protocol_alerter.mm
index d7edc06..d1f420e 100644
--- a/ios/showcase/common/protocol_alerter.mm
+++ b/ios/showcase/common/protocol_alerter.mm
@@ -112,6 +112,7 @@
       [UIAlertAction actionWithTitle:@"Done"
                                style:UIAlertActionStyleCancel
                              handler:nil];
+  [action setAccessibilityLabel:@"protocol_alerter_done"];
   [alertController addAction:action];
   [self.baseViewController presentViewController:alertController
                                         animated:YES
diff --git a/ios/showcase/tab_grid/sc_tab_grid_egtest.mm b/ios/showcase/tab_grid/sc_tab_grid_egtest.mm
index 8d790cc7..d85c3f0 100644
--- a/ios/showcase/tab_grid/sc_tab_grid_egtest.mm
+++ b/ios/showcase/tab_grid/sc_tab_grid_egtest.mm
@@ -30,7 +30,8 @@
       performAction:grey_tap()];
   [[EarlGrey selectElementWithMatcher:grey_text(@"TabCommands")]
       assertWithMatcher:grey_notNil()];
-  [[EarlGrey selectElementWithMatcher:grey_text(@"Done")]
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
+                                          @"protocol_alerter_done")]
       performAction:grey_tap()];
 }
 
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 1723dec7..0e9fece 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -119,6 +119,7 @@
     "public/load_committed_details.h",
     "public/navigation_item.h",
     "public/navigation_item_list.h",
+    "public/navigation_item_list.mm",
     "public/navigation_manager.h",
     "public/origin_util.h",
     "public/origin_util.mm",
@@ -529,7 +530,10 @@
     "navigation/crw_navigation_item_storage_unittest.mm",
     "navigation/crw_session_controller_unittest.mm",
     "navigation/crw_session_entry_unittest.mm",
+    "navigation/crw_session_storage_unittest.mm",
     "navigation/navigation_item_impl_unittest.mm",
+    "navigation/navigation_item_storage_test_util.h",
+    "navigation/navigation_item_storage_test_util.mm",
     "navigation/navigation_manager_impl_unittest.mm",
     "navigation/nscoder_util_unittest.mm",
     "net/cert_host_pair_unittest.cc",
diff --git a/ios/web/interstitials/web_interstitial_impl.mm b/ios/web/interstitials/web_interstitial_impl.mm
index 2e83b76..4187248f 100644
--- a/ios/web/interstitials/web_interstitial_impl.mm
+++ b/ios/web/interstitials/web_interstitial_impl.mm
@@ -90,8 +90,11 @@
 
   GetDelegate()->OnDontProceed();
 
-  // Reload last committed entry.
-  nav_manager->Reload(true /* check_for_repost */);
+  NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults];
+  if (![user_defaults boolForKey:@"PendingIndexNavigationDisabled"]) {
+    // Reload last committed entry.
+    nav_manager->Reload(true /* check_for_repost */);
+  }
 
   delete this;
 }
diff --git a/ios/web/navigation/crw_navigation_item_storage_unittest.mm b/ios/web/navigation/crw_navigation_item_storage_unittest.mm
index e89049d8..2daffa64 100644
--- a/ios/web/navigation/crw_navigation_item_storage_unittest.mm
+++ b/ios/web/navigation/crw_navigation_item_storage_unittest.mm
@@ -12,6 +12,7 @@
 #import "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #import "ios/web/navigation/navigation_item_impl.h"
+#import "ios/web/navigation/navigation_item_storage_test_util.h"
 #include "ios/web/public/referrer.h"
 #import "net/base/mac/url_conversions.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -20,25 +21,6 @@
 #include "third_party/ocmock/gtest_support.h"
 #include "ui/base/page_transition_types.h"
 
-namespace {
-
-// Checks equality between item1 and item2.
-BOOL ItemStoragesAreEqual(CRWNavigationItemStorage* item1,
-                          CRWNavigationItemStorage* item2) {
-  return item1.virtualURL == item2.virtualURL &&
-         item1.referrer.url == item2.referrer.url &&
-         item1.referrer.policy == item2.referrer.policy &&
-         item1.timestamp == item2.timestamp && item1.title == item2.title &&
-         item1.displayState == item2.displayState &&
-         item1.shouldSkipRepostFormConfirmation ==
-             item2.shouldSkipRepostFormConfirmation &&
-         item1.overridingUserAgent == item2.overridingUserAgent &&
-         [item1.POSTData isEqualToData:item2.POSTData] &&
-         [item1.HTTPRequestHeaders
-             isEqualToDictionary:item2.HTTPRequestHeaders];
-}
-}  // namespace
-
 class CRWNavigationItemStorageTest : public PlatformTest {
  protected:
   CRWNavigationItemStorageTest()
@@ -104,7 +86,7 @@
   // Create a CRWNavigationItemStorage and verify that it is equivalent.
   base::scoped_nsobject<CRWNavigationItemStorage> new_storage(
       [[CRWNavigationItemStorage alloc] initWithCoder:unarchiver]);
-  EXPECT_TRUE(ItemStoragesAreEqual(item_storage(), new_storage.get()));
+  EXPECT_TRUE(web::ItemStoragesAreEqual(item_storage(), new_storage.get()));
 }
 
 // Tests that unarchiving CRWNavigationItemStorage data results in an equivalent
@@ -112,5 +94,5 @@
 TEST_F(CRWNavigationItemStorageTest, EncodeDecode) {
   NSData* data = [NSKeyedArchiver archivedDataWithRootObject:item_storage()];
   id decoded = [NSKeyedUnarchiver unarchiveObjectWithData:data];
-  EXPECT_TRUE(ItemStoragesAreEqual(item_storage(), decoded));
+  EXPECT_TRUE(web::ItemStoragesAreEqual(item_storage(), decoded));
 }
diff --git a/ios/web/navigation/crw_session_controller.h b/ios/web/navigation/crw_session_controller.h
index 5f9c149a..3859af2a 100644
--- a/ios/web/navigation/crw_session_controller.h
+++ b/ios/web/navigation/crw_session_controller.h
@@ -8,7 +8,7 @@
 #import <Foundation/Foundation.h>
 #include <vector>
 
-#import "ios/web/navigation/navigation_item_impl_list.h"
+#include "ios/web/public/navigation_item_list.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
 
@@ -46,9 +46,8 @@
 @property(nonatomic, readonly, copy) NSString* openerId;
 @property(nonatomic, readonly, assign) NSInteger openerNavigationIndex;
 
-// The ScopedNavigationItemImplList used to store the NavigationItemImpls for
-// this session.
-@property(nonatomic, readonly) const web::ScopedNavigationItemImplList& items;
+// The list of CRWSessionEntries in |_entries|'s NavigationItemImpls.
+@property(nonatomic, readonly) web::NavigationItemList items;
 // The current NavigationItem.  During a pending navigation, returns the
 // NavigationItem for that navigation.  If a transient NavigationItem exists,
 // this NavigationItem will be returned.
@@ -137,7 +136,8 @@
 - (void)discardNonCommittedItems;
 
 // Inserts history state from |otherController| to the front of |items|.  This
-// function will create copies of |otherController|'s NavigationItems.
+// function transfers ownership of |otherController|'s NavigationItems to the
+// receiver.
 - (void)insertStateFromSessionController:(CRWSessionController*)otherController;
 
 // Sets |currentNavigationIndex_| to the |index| if it's in the entries bounds.
diff --git a/ios/web/navigation/crw_session_controller.mm b/ios/web/navigation/crw_session_controller.mm
index 2374036e..9bf772a 100644
--- a/ios/web/navigation/crw_session_controller.mm
+++ b/ios/web/navigation/crw_session_controller.mm
@@ -7,8 +7,8 @@
 #include <stddef.h>
 
 #include <algorithm>
-#include <map>
 #include <utility>
+#include <vector>
 
 #include "base/format_macros.h"
 #include "base/logging.h"
@@ -49,6 +49,21 @@
   // Identifies the index of the previous navigation in the CRWSessionEntry
   // array.
   NSInteger _previousNavigationIndex;
+  // Ordered array of |CRWSessionEntry| objects, one for each site in session
+  // history. End of the list is the most recent load.
+  NSMutableArray* _entries;
+
+  // An entry we haven't gotten a response for yet. This will be discarded
+  // when we navigate again. It's used only so we know what the currently
+  // displayed tab is.  It backs the property of the same name and should only
+  // be set through its setter.
+  base::scoped_nsobject<CRWSessionEntry> _pendingEntry;
+
+  // The transient entry, if any. A transient entry is discarded on any
+  // navigation, and is used for representing interstitials that need to be
+  // represented in the session.  It backs the property of the same name and
+  // should only be set through its setter.
+  base::scoped_nsobject<CRWSessionEntry> _transientEntry;
 
   // The window name associated with the session.
   NSString* _windowName;
@@ -61,24 +76,15 @@
   NSTimeInterval _lastVisitedTimestamp;
 
   // If |YES|, override |currentEntry.useDesktopUserAgent| and create the
-  // pending item using the desktop user agent.
+  // pending entry using the desktop user agent.
   BOOL _useDesktopUserAgentForNextPendingItem;
 
   // The browser state associated with this CRWSessionController;
   web::BrowserState* _browserState;  // weak
 
-  // Time smoother for navigation item timestamps; see comment in
+  // Time smoother for navigation entry timestamps; see comment in
   // navigation_controller_impl.h
   web::TimeSmoother _timeSmoother;
-
-  // Backing objects for properties of the same name.
-  web::ScopedNavigationItemImplList _items;
-  // |_pendingItem| only contains a NavigationItem for non-history navigations.
-  // For back/forward navigations within session history, _pendingItemIndex will
-  // be equal to -1, and self.pendingItem will return an item contained within
-  // |_items|.
-  std::unique_ptr<web::NavigationItemImpl> _pendingItem;
-  std::unique_ptr<web::NavigationItemImpl> _transientItem;
 }
 
 // Redefine as readwrite.
@@ -87,6 +93,7 @@
 // TODO(rohitrao): These properties must be redefined readwrite to work around a
 // clang bug. crbug.com/228650
 @property(nonatomic, readwrite, copy) NSString* tabId;
+@property(nonatomic, readwrite, strong) NSArray* entries;
 @property(nonatomic, readwrite, strong)
     CRWSessionCertificatePolicyManager* sessionCertificatePolicyManager;
 
@@ -99,26 +106,21 @@
 @property(nonatomic, readwrite, assign) NSInteger previousNavigationIndex;
 
 - (NSString*)uniqueID;
-// Removes all items after currentNavigationIndex_.
+// Removes all entries after currentNavigationIndex_.
 - (void)clearForwardItems;
-// Discards the transient item, if any.
+// Discards the transient entry, if any.
 - (void)discardTransientItem;
-// Creates a NavigationItemImpl with the specified properties.
-- (std::unique_ptr<web::NavigationItemImpl>)
-        itemWithURL:(const GURL&)url
-           referrer:(const web::Referrer&)referrer
-         transition:(ui::PageTransition)transition
-useDesktopUserAgent:(BOOL)useDesktopUserAgent
-  rendererInitiated:(BOOL)rendererInitiated;
+// Create a new autoreleased session entry.
+- (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url
+                               referrer:(const web::Referrer&)referrer
+                             transition:(ui::PageTransition)transition
+                    useDesktopUserAgent:(BOOL)useDesktopUserAgent
+                      rendererInitiated:(BOOL)rendererInitiated;
 // Returns YES if the PageTransition for the underlying navigationItem at
-// |index| in |items| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
-- (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index;
-// Returns the CRWSessionEntry corresponding with |item|.
-- (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item;
-// Returns an autoreleased NSArray containing CRWSessionEntries corresponding
-// with the NavigationItems in |itemList|.
-- (NSArray*)entryListForItemList:(const web::NavigationItemList&)itemList;
-
+// |index| in |entries_| has ui::PAGE_TRANSITION_IS_REDIRECT_MASK.
+- (BOOL)isRedirectTransitionForItemAtIndex:(NSInteger)index;
+// Returns a NavigationItemList containing the NavigationItems from |entries|.
+- (web::NavigationItemList)itemListForEntryList:(NSArray*)entries;
 @end
 
 @implementation CRWSessionController
@@ -127,6 +129,7 @@
 @synthesize currentNavigationIndex = _currentNavigationIndex;
 @synthesize previousNavigationIndex = _previousNavigationIndex;
 @synthesize pendingItemIndex = _pendingItemIndex;
+@synthesize entries = _entries;
 @synthesize windowName = _windowName;
 @synthesize lastVisitedTimestamp = _lastVisitedTimestamp;
 @synthesize openerId = _openerId;
@@ -147,6 +150,7 @@
     _openedByDOM = openedByDOM;
     _openerNavigationIndex = openerIndex;
     _browserState = browserState;
+    _entries = [NSMutableArray array];
     _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
     _currentNavigationIndex = -1;
     _previousNavigationIndex = -1;
@@ -157,7 +161,8 @@
   return self;
 }
 
-- (id)initWithNavigationItems:(web::ScopedNavigationItemList)items
+- (id)initWithNavigationItems:
+          (std::vector<std::unique_ptr<web::NavigationItem>>)items
                  currentIndex:(NSUInteger)currentIndex
                  browserState:(web::BrowserState*)browserState {
   self = [super init];
@@ -165,12 +170,22 @@
     _tabId = [[self uniqueID] copy];
     _openerId = nil;
     _browserState = browserState;
-    _items = web::CreateScopedNavigationItemImplList(std::move(items));
+
+    // Create entries array from list of navigations.
+    _entries = [[NSMutableArray alloc] initWithCapacity:items.size()];
+
+    for (auto& item : items) {
+      base::scoped_nsobject<CRWSessionEntry> entry(
+          [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]);
+      [_entries addObject:entry];
+    }
     self.currentNavigationIndex = currentIndex;
-    if (_items.empty())
+    // Prior to M34, 0 was used as "no index" instead of -1; adjust for that.
+    if (![_entries count])
       self.currentNavigationIndex = -1;
-    _currentNavigationIndex = std::min(
-        _currentNavigationIndex, static_cast<NSInteger>(_items.size() - 1));
+    if (_currentNavigationIndex >= static_cast<NSInteger>(items.size())) {
+      self.currentNavigationIndex = static_cast<NSInteger>(items.size()) - 1;
+    }
     _previousNavigationIndex = -1;
     _pendingItemIndex = -1;
     _lastVisitedTimestamp = [[NSDate date] timeIntervalSince1970];
@@ -180,168 +195,6 @@
   return self;
 }
 
-#pragma mark - Accessors
-
-- (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex {
-  if (_currentNavigationIndex != currentNavigationIndex) {
-    _currentNavigationIndex = currentNavigationIndex;
-    if (_navigationManager)
-      _navigationManager->RemoveTransientURLRewriters();
-  }
-}
-
-- (void)setPendingItemIndex:(NSInteger)pendingItemIndex {
-  DCHECK_GE(pendingItemIndex, -1);
-  DCHECK_LT(pendingItemIndex, static_cast<NSInteger>(self.items.size()));
-  _pendingItemIndex = pendingItemIndex;
-  DCHECK(_pendingItemIndex == -1 || self.pendingItem);
-}
-
-- (const web::ScopedNavigationItemImplList&)items {
-  return _items;
-}
-
-- (web::NavigationItemImpl*)currentItem {
-  if (self.transientItem)
-    return self.transientItem;
-  if (self.pendingItem)
-    return self.pendingItem;
-  return self.lastCommittedItem;
-}
-
-- (web::NavigationItemImpl*)visibleItem {
-  if (self.transientItem)
-    return self.transientItem;
-  // Only return the |pendingItem| for new (non-history), browser-initiated
-  // navigations in order to prevent URL spoof attacks.
-  web::NavigationItemImpl* pendingItem = self.pendingItem;
-  bool safeToShowPending = pendingItem &&
-                           !pendingItem->is_renderer_initiated() &&
-                           _pendingItemIndex == -1;
-  if (safeToShowPending)
-    return pendingItem;
-  return self.lastCommittedItem;
-}
-
-- (web::NavigationItemImpl*)pendingItem {
-  if (self.pendingItemIndex == -1)
-    return _pendingItem.get();
-  return self.items[self.pendingItemIndex].get();
-}
-
-- (web::NavigationItemImpl*)transientItem {
-  return _transientItem.get();
-}
-
-- (web::NavigationItemImpl*)lastCommittedItem {
-  NSInteger index = self.currentNavigationIndex;
-  return index == -1 ? nullptr : self.items[index].get();
-}
-
-- (web::NavigationItemImpl*)previousItem {
-  NSInteger index = self.previousNavigationIndex;
-  return index == -1 || self.items.empty() ? nullptr : self.items[index].get();
-}
-
-- (web::NavigationItemImpl*)lastUserItem {
-  if (self.items.empty())
-    return nil;
-
-  NSInteger index = self.currentNavigationIndex;
-  // This will return the first NavigationItem if all other items are
-  // redirects, regardless of the transition state of the first item.
-  while (index > 0 && [self isRedirectTransitionForItemAtIndex:index])
-    --index;
-
-  return self.items[index].get();
-}
-
-- (web::NavigationItemList)backwardItems {
-  web::NavigationItemList items;
-  for (size_t index = _currentNavigationIndex; index > 0; --index) {
-    if (![self isRedirectTransitionForItemAtIndex:index])
-      items.push_back(self.items[index - 1].get());
-  }
-  return items;
-}
-
-- (web::NavigationItemList)forwardItems {
-  web::NavigationItemList items;
-  NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1;
-  while (lastNonRedirectedIndex < self.items.size()) {
-    web::NavigationItem* item = self.items[lastNonRedirectedIndex].get();
-    if (!ui::PageTransitionIsRedirect(item->GetTransitionType()))
-      items.push_back(item);
-    ++lastNonRedirectedIndex;
-  }
-  return items;
-}
-
-// DEPRECATED
-- (NSArray*)entries {
-  return [self entryListForItemList:web::CreateNavigationItemList(_items)];
-}
-
-// DEPRECATED
-- (CRWSessionEntry*)currentEntry {
-  return [self entryForItem:self.currentItem];
-}
-
-// DEPRECATED
-- (CRWSessionEntry*)visibleEntry {
-  return [self entryForItem:self.visibleItem];
-}
-
-// DEPRECATED
-- (CRWSessionEntry*)pendingEntry {
-  return [self entryForItem:self.pendingItem];
-}
-
-// DEPRECATED
-- (CRWSessionEntry*)transientEntry {
-  return [self entryForItem:self.transientItem];
-}
-
-// DEPRECATED
-- (CRWSessionEntry*)lastCommittedEntry {
-  return [self entryForItem:self.lastCommittedItem];
-}
-
-// DEPRECATED
-- (CRWSessionEntry*)previousEntry {
-  return [self entryForItem:self.previousItem];
-}
-
-// DEPRECATED
-- (CRWSessionEntry*)lastUserEntry {
-  return [self entryForItem:self.lastUserItem];
-}
-
-// DEPRECATED
-- (NSArray*)backwardEntries {
-  return [self entryListForItemList:self.backwardItems];
-}
-
-// DEPRECATED
-- (NSArray*)forwardEntries {
-  return [self entryListForItemList:self.forwardItems];
-}
-
-#pragma mark - NSObject
-
-- (NSString*)description {
-  return [NSString
-      stringWithFormat:
-          @"id: %@\nname: %@\nlast visit: %f\ncurrent index: %" PRIdNS
-          @"\nprevious index: %" PRIdNS @"\npending index: %" PRIdNS
-                                        @"\n%@\npending: %@\ntransient: %@\n",
-          _tabId, self.windowName, _lastVisitedTimestamp,
-          _currentNavigationIndex, _previousNavigationIndex, _pendingItemIndex,
-          self.entries, self.pendingEntry, self.transientEntry];
-}
-
-#pragma mark - NSCopying
-
 - (id)copyWithZone:(NSZone*)zone {
   CRWSessionController* copy = [[[self class] alloc] init];
   copy->_tabId = [_tabId copy];
@@ -353,17 +206,29 @@
   copy->_previousNavigationIndex = _previousNavigationIndex;
   copy->_pendingItemIndex = _pendingItemIndex;
   copy->_lastVisitedTimestamp = _lastVisitedTimestamp;
+  copy->_entries =
+      [[NSMutableArray alloc] initWithArray:_entries copyItems:YES];
   copy->_sessionCertificatePolicyManager =
       [_sessionCertificatePolicyManager copy];
-  for (size_t index = 0; index < self.items.size(); ++index) {
-    std::unique_ptr<web::NavigationItemImpl> itemCopy(
-        new web::NavigationItemImpl(*self.items[index].get()));
-    copy->_items.push_back(std::move(itemCopy));
-  }
   return copy;
 }
 
-#pragma mark - Public
+- (void)setCurrentNavigationIndex:(NSInteger)currentNavigationIndex {
+  if (_currentNavigationIndex != currentNavigationIndex) {
+    _currentNavigationIndex = currentNavigationIndex;
+    if (_navigationManager)
+      _navigationManager->RemoveTransientURLRewriters();
+  }
+}
+
+- (void)setPendingItemIndex:(NSInteger)index {
+  DCHECK_GE(index, -1);
+  DCHECK_LT(index, static_cast<NSInteger>(_entries.count));
+  _pendingItemIndex = index;
+  CRWSessionEntry* entry = index != -1 ? _entries[index] : nil;
+  _pendingEntry.reset(entry);
+  DCHECK(_pendingItemIndex == -1 || _pendingEntry);
+}
 
 - (void)setNavigationManager:(web::NavigationManagerImpl*)navigationManager {
   _navigationManager = navigationManager;
@@ -384,14 +249,113 @@
          _navigationManager->GetBrowserState() == _browserState);
 }
 
+- (NSString*)description {
+  return [NSString
+      stringWithFormat:
+          @"id: %@\nname: %@\nlast visit: %f\ncurrent index: %" PRIdNS
+          @"\nprevious index: %" PRIdNS @"\npending index: %" PRIdNS
+                                        @"\n%@\npending: %@\ntransient: %@\n",
+          _tabId, self.windowName, _lastVisitedTimestamp,
+          _currentNavigationIndex, _previousNavigationIndex, _pendingItemIndex,
+          _entries, _pendingEntry.get(), _transientEntry.get()];
+}
+
+- (web::NavigationItemList)items {
+  return [self itemListForEntryList:self.entries];
+}
+
+- (web::NavigationItemImpl*)currentItem {
+  return self.currentEntry.navigationItemImpl;
+}
+
+- (web::NavigationItemImpl*)visibleItem {
+  return self.visibleEntry.navigationItemImpl;
+}
+
+- (web::NavigationItemImpl*)pendingItem {
+  return self.pendingEntry.navigationItemImpl;
+}
+
+- (web::NavigationItemImpl*)transientItem {
+  return self.transientEntry.navigationItemImpl;
+}
+
+- (web::NavigationItemImpl*)lastCommittedItem {
+  return self.lastCommittedEntry.navigationItemImpl;
+}
+
+- (web::NavigationItemImpl*)previousItem {
+  return self.previousEntry.navigationItemImpl;
+}
+
+- (web::NavigationItemImpl*)lastUserItem {
+  return self.lastUserEntry.navigationItemImpl;
+}
+
+- (web::NavigationItemList)backwardItems {
+  return [self itemListForEntryList:self.backwardEntries];
+}
+
+- (web::NavigationItemList)forwardItems {
+  return [self itemListForEntryList:self.forwardEntries];
+}
+
+// Returns the current entry in the session list, or the pending entry if there
+// is a navigation in progress.
+- (CRWSessionEntry*)currentEntry {
+  if (_transientEntry)
+    return _transientEntry.get();
+  if (_pendingEntry)
+    return _pendingEntry.get();
+  return [self lastCommittedEntry];
+}
+
+// See NavigationController::GetVisibleEntry for the motivation for this
+// distinction.
+- (CRWSessionEntry*)visibleEntry {
+  if (_transientEntry)
+    return _transientEntry.get();
+  // Only return the pending_entry for new (non-history), browser-initiated
+  // navigations in order to prevent URL spoof attacks.
+  web::NavigationItemImpl* pendingItem = [_pendingEntry navigationItemImpl];
+  bool safeToShowPending = pendingItem &&
+                           !pendingItem->is_renderer_initiated() &&
+                           _pendingItemIndex == -1;
+  if (safeToShowPending) {
+    return _pendingEntry.get();
+  }
+  return [self lastCommittedEntry];
+}
+
+- (CRWSessionEntry*)pendingEntry {
+  return _pendingEntry.get();
+}
+
+- (CRWSessionEntry*)transientEntry {
+  return _transientEntry.get();
+}
+
+- (CRWSessionEntry*)lastCommittedEntry {
+  if (_currentNavigationIndex == -1)
+    return nil;
+  return [_entries objectAtIndex:_currentNavigationIndex];
+}
+
+// Returns the previous entry in the session list, or nil if there isn't any.
+- (CRWSessionEntry*)previousEntry {
+  if ((_previousNavigationIndex < 0) || (![_entries count]))
+    return nil;
+  return [_entries objectAtIndex:_previousNavigationIndex];
+}
+
 - (void)addPendingItem:(const GURL&)url
               referrer:(const web::Referrer&)ref
             transition:(ui::PageTransition)trans
      rendererInitiated:(BOOL)rendererInitiated {
   [self discardTransientItem];
-  self.pendingItemIndex = -1;
+  _pendingItemIndex = -1;
 
-  // Don't create a new item if it's already the same as the current item,
+  // Don't create a new entry if it's already the same as the current entry,
   // allowing this routine to be called multiple times in a row without issue.
   // Note: CRWSessionController currently has the responsibility to distinguish
   // between new navigations and history stack navigation, hence the inclusion
@@ -400,45 +364,51 @@
   // TODO(crbug.com/676129): Fix the way changes are detected/reported elsewhere
   // in the web layer so that this hack can be removed.
   // Remove the workaround code from -presentSafeBrowsingWarningForResource:.
-  web::NavigationItemImpl* currentItem = self.currentItem;
-  if (currentItem && currentItem->GetURL() == url &&
-      (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) ||
-       PageTransitionCoreTypeIs(currentItem->GetTransitionType(),
-                                ui::PAGE_TRANSITION_FORM_SUBMIT))) {
-    // Send the notification anyway, to preserve old behavior. It's unknown
-    // whether anything currently relies on this, but since both this whole
-    // hack and the content facade will both be going away, it's not worth
-    // trying to unwind.
-    if (_navigationManager && _navigationManager->GetFacadeDelegate())
-      _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
-    return;
+  CRWSessionEntry* currentEntry = self.currentEntry;
+  if (currentEntry) {
+    web::NavigationItem* item = [currentEntry navigationItem];
+    if (item->GetURL() == url &&
+        (!PageTransitionCoreTypeIs(trans, ui::PAGE_TRANSITION_FORM_SUBMIT) ||
+         PageTransitionCoreTypeIs(item->GetTransitionType(),
+                                  ui::PAGE_TRANSITION_FORM_SUBMIT))) {
+      // Send the notification anyway, to preserve old behavior. It's unknown
+      // whether anything currently relies on this, but since both this whole
+      // hack and the content facade will both be going away, it's not worth
+      // trying to unwind.
+      if (_navigationManager && _navigationManager->GetFacadeDelegate()) {
+        _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
+      }
+      return;
+    }
   }
 
   BOOL useDesktopUserAgent =
       _useDesktopUserAgentForNextPendingItem ||
-      (currentItem && currentItem->IsOverridingUserAgent());
+      (self.currentEntry.navigationItem &&
+       self.currentEntry.navigationItem->IsOverridingUserAgent());
   _useDesktopUserAgentForNextPendingItem = NO;
-  _pendingItem = [self itemWithURL:url
-                          referrer:ref
-                        transition:trans
-               useDesktopUserAgent:useDesktopUserAgent
-                 rendererInitiated:rendererInitiated];
+  _pendingEntry.reset([self sessionEntryWithURL:url
+                                       referrer:ref
+                                     transition:trans
+                            useDesktopUserAgent:useDesktopUserAgent
+                              rendererInitiated:rendererInitiated]);
 
-  if (_navigationManager && _navigationManager->GetFacadeDelegate())
+  if (_navigationManager && _navigationManager->GetFacadeDelegate()) {
     _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
+  }
 }
 
 - (void)updatePendingItem:(const GURL&)url {
-  // If there is no pending item, navigation is probably happening within the
-  // session history. Don't modify the item list.
-  web::NavigationItemImpl* item = self.pendingItem;
-  if (!item)
+  // If there is no pending entry, navigation is probably happening within the
+  // session history. Don't modify the entry list.
+  if (!_pendingEntry)
     return;
 
+  web::NavigationItemImpl* item = [_pendingEntry navigationItemImpl];
   if (url != item->GetURL()) {
-    // Assume a redirection, and discard any transient item.
+    // Assume a redirection, and discard any transient entry.
     // TODO(stuartmorgan): Once the current safe browsing code is gone,
-    // consider making this a DCHECK that there's no transient item.
+    // consider making this a DCHECK that there's no transient entry.
     [self discardTransientItem];
 
     item->SetURL(url);
@@ -451,95 +421,106 @@
 
   // This should probably not be sent if the URLs matched, but that's what was
   // done before, so preserve behavior in case something relies on it.
-  if (_navigationManager && _navigationManager->GetFacadeDelegate())
+  if (_navigationManager && _navigationManager->GetFacadeDelegate()) {
     _navigationManager->GetFacadeDelegate()->OnNavigationItemPending();
+  }
 }
 
 - (void)clearForwardItems {
-  DCHECK_EQ(self.pendingItemIndex, -1);
+  DCHECK_EQ(_pendingItemIndex, -1);
   [self discardTransientItem];
 
   NSInteger forwardItemStartIndex = _currentNavigationIndex + 1;
   DCHECK(forwardItemStartIndex >= 0);
 
-  size_t itemCount = self.items.size();
-  if (forwardItemStartIndex >= static_cast<NSInteger>(itemCount))
+  if (forwardItemStartIndex >= static_cast<NSInteger>([_entries count]))
     return;
 
+  NSRange remove = NSMakeRange(forwardItemStartIndex,
+                               [_entries count] - forwardItemStartIndex);
+  // Store removed items in temporary NSArray so they can be deallocated after
+  // their facades.
+  base::scoped_nsobject<NSArray> removedItems(
+      [_entries subarrayWithRange:remove]);
+  [_entries removeObjectsInRange:remove];
   if (_previousNavigationIndex >= forwardItemStartIndex)
     _previousNavigationIndex = -1;
-  if (_navigationManager)
-    _navigationManager->OnNavigationItemsPruned(self.items.size() -
-                                                forwardItemStartIndex);
-
-  // Remove the NavigationItems.
-  _items.erase(_items.begin() + forwardItemStartIndex, _items.end());
+  if (_navigationManager) {
+    _navigationManager->OnNavigationItemsPruned(remove.length);
+  }
 }
 
 - (void)commitPendingItem {
-  if (self.pendingItem) {
-    // Once an item is committed it's not renderer-initiated any more. (Matches
-    // the implementation in NavigationController.)
-    self.pendingItem->ResetForCommit();
-
-    NSInteger newNavigationIndex = self.pendingItemIndex;
-    if (newNavigationIndex == -1) {
+  if (_pendingEntry) {
+    NSInteger newNavigationIndex = _pendingItemIndex;
+    if (_pendingItemIndex == -1) {
       [self clearForwardItems];
-      // Add the new item at the end.
-      _items.push_back(std::move(_pendingItem));
-      newNavigationIndex = self.items.size() - 1;
+      // Add the new entry at the end.
+      [_entries addObject:_pendingEntry];
+      newNavigationIndex = [_entries count] - 1;
     }
     _previousNavigationIndex = _currentNavigationIndex;
     self.currentNavigationIndex = newNavigationIndex;
-    self.pendingItemIndex = -1;
+    // Once an entry is committed it's not renderer-initiated any more. (Matches
+    // the implementation in NavigationController.)
+    [_pendingEntry navigationItemImpl]->ResetForCommit();
+    _pendingEntry.reset();
+    _pendingItemIndex = -1;
   }
 
-  web::NavigationItem* item = self.currentItem;
+  CRWSessionEntry* currentEntry = self.currentEntry;
+  web::NavigationItem* item = currentEntry.navigationItem;
   // Update the navigation timestamp now that it's actually happened.
   if (item)
     item->SetTimestamp(_timeSmoother.GetSmoothedTime(base::Time::Now()));
 
   if (_navigationManager && item)
     _navigationManager->OnNavigationItemCommitted();
-  DCHECK_EQ(self.pendingItemIndex, -1);
+  DCHECK_EQ(_pendingItemIndex, -1);
 }
 
 - (void)addTransientItemWithURL:(const GURL&)URL {
-  _transientItem = [self itemWithURL:URL
-                            referrer:web::Referrer()
-                          transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
-                 useDesktopUserAgent:NO
-                   rendererInitiated:NO];
-  _transientItem->SetTimestamp(
+  _transientEntry.reset([self
+      sessionEntryWithURL:URL
+                 referrer:web::Referrer()
+               transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
+      useDesktopUserAgent:NO
+        rendererInitiated:NO]);
+
+  web::NavigationItem* navigationItem = [_transientEntry navigationItem];
+  DCHECK(navigationItem);
+  navigationItem->SetTimestamp(
       _timeSmoother.GetSmoothedTime(base::Time::Now()));
 }
 
 - (void)pushNewItemWithURL:(const GURL&)URL
                stateObject:(NSString*)stateObject
                 transition:(ui::PageTransition)transition {
-  DCHECK(!self.pendingItem);
-  web::NavigationItem* item = self.currentItem;
-  DCHECK(item);
+  DCHECK(![self pendingEntry]);
+  DCHECK([self currentEntry]);
+  web::NavigationItem* item = [self currentEntry].navigationItem;
   CHECK(
       web::history_state_util::IsHistoryStateChangeValid(item->GetURL(), URL));
   web::Referrer referrer(item->GetURL(), web::ReferrerPolicyDefault);
-  bool overrideUserAgent = self.currentItem->IsOverridingUserAgent();
-  std::unique_ptr<web::NavigationItemImpl> pushedItem =
-      [self itemWithURL:URL
-                     referrer:referrer
-                   transition:transition
-          useDesktopUserAgent:overrideUserAgent
-            rendererInitiated:NO];
+  bool overrideUserAgent =
+      self.currentEntry.navigationItem->IsOverridingUserAgent();
+  base::scoped_nsobject<CRWSessionEntry> pushedEntry([self
+      sessionEntryWithURL:URL
+                 referrer:referrer
+               transition:transition
+      useDesktopUserAgent:overrideUserAgent
+        rendererInitiated:NO]);
+  web::NavigationItemImpl* pushedItem = [pushedEntry navigationItemImpl];
   pushedItem->SetSerializedStateObject(stateObject);
   pushedItem->SetIsCreatedFromPushState(true);
-  web::SSLStatus& sslStatus = self.currentItem->GetSSL();
-  pushedItem->GetSSL() = sslStatus;
+  web::SSLStatus& sslStatus = [self currentEntry].navigationItem->GetSSL();
+  pushedEntry.get().navigationItem->GetSSL() = sslStatus;
 
   [self clearForwardItems];
-  // Add the new item at the end.
-  _items.push_back(std::move(pushedItem));
+  // Add the new entry at the end.
+  [_entries addObject:pushedEntry];
   _previousNavigationIndex = _currentNavigationIndex;
-  self.currentNavigationIndex = self.items.size() - 1;
+  self.currentNavigationIndex = [_entries count] - 1;
 
   if (_navigationManager)
     _navigationManager->OnNavigationItemCommitted();
@@ -547,61 +528,64 @@
 
 - (void)updateCurrentItemWithURL:(const GURL&)url
                      stateObject:(NSString*)stateObject {
-  DCHECK(!self.transientItem);
-  web::NavigationItemImpl* currentItem = self.currentItem;
+  DCHECK(!_transientEntry);
+  CRWSessionEntry* currentEntry = self.currentEntry;
+  web::NavigationItemImpl* currentItem = self.currentEntry.navigationItemImpl;
   currentItem->SetURL(url);
   currentItem->SetSerializedStateObject(stateObject);
   currentItem->SetHasStateBeenReplaced(true);
   currentItem->SetPostData(nil);
-  // If the change is to a committed item, notify interested parties.
-  if (currentItem != self.pendingItem && _navigationManager)
+  currentEntry.navigationItem->SetURL(url);
+  // If the change is to a committed entry, notify interested parties.
+  if (currentEntry != self.pendingEntry && _navigationManager)
     _navigationManager->OnNavigationItemChanged();
 }
 
 - (void)discardNonCommittedItems {
   [self discardTransientItem];
-  _pendingItem.reset();
-  self.pendingItemIndex = -1;
+  _pendingEntry.reset();
+  _pendingItemIndex = -1;
 }
 
 - (void)discardTransientItem {
-  _transientItem.reset();
+  // Keep the entry alive temporarily. There are flows that get the current
+  // entry, do some navigation operation, and then try to use that old current
+  // entry; since navigations clear the transient entry, these flows might
+  // crash. (This should be removable once more session management is handled
+  // within this class and/or NavigationManager).
+  _transientEntry.reset();
 }
 
 - (void)insertStateFromSessionController:(CRWSessionController*)sourceSession {
   DCHECK(sourceSession);
   self.windowName = sourceSession.windowName;
 
-  // The other session may not have any items, in which case there is nothing
-  // to insert.  The other session's currentItem will be bogus
+  // The other session may not have any entries, in which case there is nothing
+  // to insert.  The other session's currentNavigationEntry will be bogus
   // in such cases, so ignore it and return early.
-  web::ScopedNavigationItemImplList& sourceItems = sourceSession->_items;
-  if (sourceItems.empty())
+  NSArray* sourceEntries = sourceSession.entries;
+  if (!sourceEntries.count)
     return;
 
-  // Cycle through the items from the other session and insert them before any
-  // items from this session.  Do not copy anything that comes after the other
-  // session's current item.
+  // Cycle through the entries from the other session and insert them before any
+  // entries from this session.  Do not copy anything that comes after the other
+  // session's current entry.
   NSInteger lastIndexToCopy = sourceSession.currentNavigationIndex;
   for (NSInteger i = 0; i <= lastIndexToCopy; ++i) {
-    std::unique_ptr<web::NavigationItemImpl> sourceItemCopy(
-        new web::NavigationItemImpl(*sourceItems[i].get()));
-    _items.insert(_items.begin() + i, std::move(sourceItemCopy));
+    [_entries insertObject:sourceEntries[i] atIndex:i];
   }
 
-  // Update state to reflect inserted NavigationItems.
   _previousNavigationIndex = -1;
   _currentNavigationIndex += lastIndexToCopy + 1;
-  if (self.pendingItemIndex != -1)
-    self.pendingItemIndex += lastIndexToCopy + 1;
+  if (_pendingItemIndex != -1)
+    _pendingItemIndex += lastIndexToCopy + 1;
 
-  DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex),
-            self.items.size());
-  DCHECK(self.pendingItemIndex == -1 || self.pendingItem);
+  DCHECK_LT(static_cast<NSUInteger>(_currentNavigationIndex), _entries.count);
+  DCHECK(_pendingItemIndex == -1 || _pendingEntry);
 }
 
 - (void)goToItemAtIndex:(NSInteger)index {
-  if (index < 0 || static_cast<NSUInteger>(index) >= self.items.size())
+  if (index < 0 || static_cast<NSUInteger>(index) >= _entries.count)
     return;
 
   if (index < _currentNavigationIndex) {
@@ -620,19 +604,42 @@
 }
 
 - (void)removeItemAtIndex:(NSInteger)index {
-  DCHECK(index < static_cast<NSInteger>(self.items.size()));
+  DCHECK(index < static_cast<NSInteger>([_entries count]));
   DCHECK(index != _currentNavigationIndex);
   DCHECK(index >= 0);
 
   [self discardNonCommittedItems];
 
-  _items.erase(_items.begin() + index);
+  [_entries removeObjectAtIndex:index];
   if (_currentNavigationIndex > index)
     _currentNavigationIndex--;
   if (_previousNavigationIndex >= index)
     _previousNavigationIndex--;
 }
 
+- (NSArray*)backwardEntries {
+  NSMutableArray* entries = [NSMutableArray array];
+  for (NSInteger index = _currentNavigationIndex; index > 0; --index) {
+    if (![self isRedirectTransitionForItemAtIndex:index])
+      [entries addObject:_entries[index - 1]];
+  }
+  return entries;
+}
+
+- (NSArray*)forwardEntries {
+  NSMutableArray* entries = [NSMutableArray array];
+  NSUInteger lastNonRedirectedIndex = _currentNavigationIndex + 1;
+  while (lastNonRedirectedIndex < [_entries count]) {
+    CRWSessionEntry* entry = [_entries objectAtIndex:lastNonRedirectedIndex];
+    if (!ui::PageTransitionIsRedirect(
+            entry.navigationItem->GetTransitionType())) {
+      [entries addObject:entry];
+    }
+    ++lastNonRedirectedIndex;
+  }
+  return entries;
+}
+
 - (BOOL)isSameDocumentNavigationBetweenItem:(web::NavigationItem*)firstItem
                                     andItem:(web::NavigationItem*)secondItem {
   if (!firstItem || !secondItem || firstItem == secondItem)
@@ -645,12 +652,12 @@
   NSUInteger endIndex = firstIndex < secondIndex ? secondIndex : firstIndex;
 
   for (NSUInteger i = startIndex + 1; i <= endIndex; i++) {
-    web::NavigationItemImpl* item = self.items[i].get();
-    // Every item in the sequence has to be created from a hash change or
+    web::NavigationItemImpl* item = [_entries[i] navigationItemImpl];
+    // Every entry in the sequence has to be created from a hash change or
     // pushState() call.
     if (!item->IsCreatedFromPushState() && !item->IsCreatedFromHashChange())
       return NO;
-    // Every item in the sequence has to have a URL that could have been
+    // Every entry in the sequence has to have a URL that could have been
     // created from a pushState() call.
     if (!web::history_state_util::IsHistoryStateChangeValid(firstItem->GetURL(),
                                                             item->GetURL()))
@@ -659,18 +666,31 @@
   return YES;
 }
 
+- (CRWSessionEntry*)lastUserEntry {
+  if (![_entries count])
+    return nil;
+
+  NSInteger index = _currentNavigationIndex;
+  // This will return the first session entry if all other entries are
+  // redirects, regardless of the transition state of the first entry.
+  while (index > 0 && [self isRedirectTransitionForItemAtIndex:index]) {
+    --index;
+  }
+  return [_entries objectAtIndex:index];
+}
+
 - (void)useDesktopUserAgentForNextPendingItem {
-  if (self.pendingItem)
-    self.pendingItem->SetIsOverridingUserAgent(true);
+  if (_pendingEntry)
+    [_pendingEntry navigationItem]->SetIsOverridingUserAgent(true);
   else
     _useDesktopUserAgentForNextPendingItem = YES;
 }
 
 - (NSInteger)indexOfItem:(web::NavigationItem*)item {
-  DCHECK(item);
-  for (size_t index = 0; index < self.items.size(); ++index) {
-    if (self.items[index].get() == item)
-      return index;
+  web::NavigationItemList items = self.items;
+  for (NSInteger i = 0; i < static_cast<NSInteger>(items.size()); ++i) {
+    if (items[i] == item)
+      return i;
   }
   return NSNotFound;
 }
@@ -689,12 +709,11 @@
   return uuid;
 }
 
-- (std::unique_ptr<web::NavigationItemImpl>)
-        itemWithURL:(const GURL&)url
-           referrer:(const web::Referrer&)referrer
-         transition:(ui::PageTransition)transition
-useDesktopUserAgent:(BOOL)useDesktopUserAgent
-  rendererInitiated:(BOOL)rendererInitiated {
+- (CRWSessionEntry*)sessionEntryWithURL:(const GURL&)url
+                               referrer:(const web::Referrer&)referrer
+                             transition:(ui::PageTransition)transition
+                    useDesktopUserAgent:(BOOL)useDesktopUserAgent
+                      rendererInitiated:(BOOL)rendererInitiated {
   GURL loaded_url(url);
   BOOL urlWasRewritten = NO;
   if (_navigationManager) {
@@ -716,34 +735,20 @@
   item->SetTransitionType(transition);
   item->SetIsOverridingUserAgent(useDesktopUserAgent);
   item->set_is_renderer_initiated(rendererInitiated);
-  return item;
+  return [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)];
 }
 
-- (BOOL)isRedirectTransitionForItemAtIndex:(size_t)index {
-  DCHECK_LT(index, self.items.size());
-  ui::PageTransition transition = self.items[index]->GetTransitionType();
+- (BOOL)isRedirectTransitionForItemAtIndex:(NSInteger)index {
+  ui::PageTransition transition =
+      [_entries[index] navigationItem]->GetTransitionType();
   return (transition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) ? YES : NO;
 }
 
-- (CRWSessionEntry*)entryForItem:(web::NavigationItemImpl*)item {
-  if (!item)
-    return nil;
-  // CRWSessionEntries vended by a CRWSessionController should always correspond
-  // with a NavigationItem that is owned by that CRWSessionController.
-  DCHECK([self indexOfItem:item] != NSNotFound || item == _pendingItem.get() ||
-         item == _transientItem.get());
-  return [[CRWSessionEntry alloc] initWithNavigationItem:item];
-}
-
-- (NSArray*)entryListForItemList:(const web::NavigationItemList&)itemList {
-  NSMutableArray* entryList =
-      [[NSMutableArray alloc] initWithCapacity:itemList.size()];
-  for (web::NavigationItem* item : itemList) {
-    CRWSessionEntry* entry =
-        [self entryForItem:static_cast<web::NavigationItemImpl*>(item)];
-    [entryList addObject:entry];
-  }
-  return entryList;
+- (web::NavigationItemList)itemListForEntryList:(NSArray*)entries {
+  web::NavigationItemList list(entries.count);
+  for (size_t index = 0; index < entries.count; ++index)
+    list[index] = [entries[index] navigationItem];
+  return list;
 }
 
 @end
diff --git a/ios/web/navigation/crw_session_controller_unittest.mm b/ios/web/navigation/crw_session_controller_unittest.mm
index ad09509..40b2c18 100644
--- a/ios/web/navigation/crw_session_controller_unittest.mm
+++ b/ios/web/navigation/crw_session_controller_unittest.mm
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/sys_string_conversions.h"
 #import "ios/web/navigation/crw_session_controller+private_constructors.h"
+#import "ios/web/navigation/crw_session_entry.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #include "ios/web/public/referrer.h"
 #include "ios/web/public/test/fakes/test_browser_state.h"
@@ -23,20 +24,20 @@
 #include "testing/platform_test.h"
 
 @interface CRWSessionController (Testing)
-- (GURL)URLForNavigationItemAtIndex:(size_t)index;
-- (GURL)currentURL;
+- (const GURL&)URLForSessionAtIndex:(NSUInteger)index;
+- (const GURL&)currentURL;
 @end
 
 @implementation CRWSessionController (Testing)
-- (GURL)URLForNavigationItemAtIndex:(size_t)index {
-  if (index < self.items.size())
-    return self.items[index]->GetURL();
-  return GURL();
+- (const GURL&)URLForSessionAtIndex:(NSUInteger)index {
+  CRWSessionEntry* entry =
+      static_cast<CRWSessionEntry*>([self.entries objectAtIndex:index]);
+  return entry.navigationItem->GetURL();
 }
 
-- (GURL)currentURL {
-  web::NavigationItem* currentItem = self.currentItem;
-  return currentItem ? currentItem->GetURL() : GURL();
+- (const GURL&)currentURL {
+  DCHECK([self currentEntry]);
+  return [self currentEntry].navigationItem->GetURL();
 }
 @end
 
@@ -66,8 +67,8 @@
   EXPECT_NSEQ(@"test window", [session_controller_ windowName]);
   EXPECT_NSEQ(@"opener", [session_controller_ openerId]);
   EXPECT_FALSE([session_controller_ isOpenedByDOM]);
-  EXPECT_EQ(0U, [session_controller_ items].size());
-  EXPECT_EQ(nullptr, [session_controller_ currentItem]);
+  EXPECT_EQ(0U, [[session_controller_ entries] count]);
+  EXPECT_EQ(nil, [session_controller_ currentEntry]);
 }
 
 // Tests session controller state after setting a pending index.
@@ -81,8 +82,8 @@
   EXPECT_EQ(-1, [session_controller_ pendingItemIndex]);
   [session_controller_ setPendingItemIndex:0];
   EXPECT_EQ(0, [session_controller_ pendingItemIndex]);
-  EXPECT_EQ([session_controller_ items].back().get(),
-            [session_controller_ pendingItem]);
+  EXPECT_EQ([[session_controller_ entries] lastObject],
+            [session_controller_ pendingEntry]);
 }
 
 TEST_F(CRWSessionControllerTest, addPendingItem) {
@@ -91,13 +92,13 @@
                            transition:ui::PAGE_TRANSITION_TYPED
                     rendererInitiated:NO];
 
-  EXPECT_EQ(0U, [session_controller_ items].size());
+  EXPECT_EQ(0U, [[session_controller_ entries] count]);
   EXPECT_EQ(
       GURL("http://www.url.com/"),
       [session_controller_ currentURL]);
 }
 
-TEST_F(CRWSessionControllerTest, addPendingItemWithCommittedItems) {
+TEST_F(CRWSessionControllerTest, addPendingItemWithCommittedEntries) {
   [session_controller_ addPendingItem:GURL("http://www.committed.url.com")
                              referrer:MakeReferrer("http://www.referer.com")
                            transition:ui::PAGE_TRANSITION_TYPED
@@ -109,16 +110,17 @@
                            transition:ui::PAGE_TRANSITION_TYPED
                     rendererInitiated:NO];
 
-  EXPECT_EQ(1U, [session_controller_ items].size());
-  EXPECT_EQ(GURL("http://www.committed.url.com/"),
-            [session_controller_ URLForNavigationItemAtIndex:0U]);
+  EXPECT_EQ(1U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      GURL("http://www.committed.url.com/"),
+      [session_controller_ URLForSessionAtIndex:0U]);
   EXPECT_EQ(
       GURL("http://www.url.com/"),
       [session_controller_ currentURL]);
 }
 
-// Tests that adding a pending item resets pending item index.
-TEST_F(CRWSessionControllerTest, addPendingItemWithExisingPendingItemIndex) {
+// Tests that adding a pending entry resets pending entry index.
+TEST_F(CRWSessionControllerTest, addPendingItemWithExisingPendingEntryIndex) {
   [session_controller_ addPendingItem:GURL("http://www.example.com")
                              referrer:web::Referrer()
                            transition:ui::PAGE_TRANSITION_TYPED
@@ -130,19 +132,19 @@
                     rendererInitiated:NO];
   [session_controller_ commitPendingItem];
 
-  // Set 0 as pending item index.
+  // Set 0 as pending entry index.
   [session_controller_ setPendingItemIndex:0];
   EXPECT_EQ(GURL("http://www.example.com/"),
-            [session_controller_ pendingItem]->GetURL());
+            [[session_controller_ pendingEntry] navigationItem]->GetURL());
   EXPECT_EQ(0, [session_controller_ pendingItemIndex]);
 
-  // Add a pending item, which should drop pending navigation index.
+  // Add a pending entry, which should drop pending navigation index.
   [session_controller_ addPendingItem:GURL("http://www.example.com/1")
                              referrer:web::Referrer()
                            transition:ui::PAGE_TRANSITION_TYPED
                     rendererInitiated:NO];
   EXPECT_EQ(GURL("http://www.example.com/1"),
-            [session_controller_ pendingItem]->GetURL());
+            [[session_controller_ pendingEntry] navigationItem]->GetURL());
   EXPECT_EQ(-1, [session_controller_ pendingItemIndex]);
 }
 
@@ -157,7 +159,7 @@
              transition:ui::PAGE_TRANSITION_TYPED
       rendererInitiated:NO];
 
-  EXPECT_EQ(0U, [session_controller_ items].size());
+  EXPECT_EQ(0U, [[session_controller_ entries] count]);
   EXPECT_EQ(
       GURL("http://www.another.url.com/"),
       [session_controller_ currentURL]);
@@ -170,11 +172,13 @@
                     rendererInitiated:NO];
   [session_controller_ commitPendingItem];
 
-  EXPECT_EQ(1U, [session_controller_ items].size());
-  EXPECT_EQ(GURL("http://www.url.com/"),
-            [session_controller_ URLForNavigationItemAtIndex:0U]);
-  EXPECT_EQ([session_controller_ items].front().get(),
-            [session_controller_ currentItem]);
+  EXPECT_EQ(1U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      GURL("http://www.url.com/"),
+      [session_controller_ URLForSessionAtIndex:0U]);
+  EXPECT_EQ(
+      [[session_controller_ entries] objectAtIndex:0U],
+      [session_controller_ currentEntry]);
 }
 
 TEST_F(CRWSessionControllerTest, addPendingItemOverridingAndCommit) {
@@ -189,11 +193,13 @@
       rendererInitiated:NO];
   [session_controller_ commitPendingItem];
 
-  EXPECT_EQ(1U, [session_controller_ items].size());
-  EXPECT_EQ(GURL("http://www.another.url.com/"),
-            [session_controller_ URLForNavigationItemAtIndex:0U]);
-  EXPECT_EQ([session_controller_ items].front().get(),
-            [session_controller_ currentItem]);
+  EXPECT_EQ(1U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      GURL("http://www.another.url.com/"),
+      [session_controller_ URLForSessionAtIndex:0U]);
+  EXPECT_EQ(
+      [[session_controller_ entries] objectAtIndex:0U],
+      [session_controller_ currentEntry]);
 }
 
 TEST_F(CRWSessionControllerTest, addPendingItemAndCommitMultiple) {
@@ -210,13 +216,16 @@
       rendererInitiated:NO];
   [session_controller_ commitPendingItem];
 
-  EXPECT_EQ(2U, [session_controller_ items].size());
-  EXPECT_EQ(GURL("http://www.url.com/"),
-            [session_controller_ URLForNavigationItemAtIndex:0U]);
-  EXPECT_EQ(GURL("http://www.another.url.com/"),
-            [session_controller_ URLForNavigationItemAtIndex:1U]);
-  EXPECT_EQ([session_controller_ items][1].get(),
-            [session_controller_ currentItem]);
+  EXPECT_EQ(2U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      GURL("http://www.url.com/"),
+      [session_controller_ URLForSessionAtIndex:0U]);
+  EXPECT_EQ(
+      GURL("http://www.another.url.com/"),
+      [session_controller_ URLForSessionAtIndex:1U]);
+  EXPECT_EQ(
+      [[session_controller_ entries] objectAtIndex:1U],
+      [session_controller_ currentEntry]);
 }
 
 TEST_F(CRWSessionControllerTest, addPendingItemAndDiscard) {
@@ -226,11 +235,11 @@
                     rendererInitiated:NO];
   [session_controller_ discardNonCommittedItems];
 
-  EXPECT_EQ(0U, [session_controller_ items].size());
-  EXPECT_EQ(nullptr, [session_controller_ currentItem]);
+  EXPECT_EQ(0U, [[session_controller_ entries] count]);
+  EXPECT_EQ(nil, [session_controller_ currentEntry]);
 }
 
-// Tests discarding pending item added via |setPendingItemIndex:| call.
+// Tests discarding pending entry added via |setPendingItemIndex:| call.
 TEST_F(CRWSessionControllerTest, setPendingItemIndexAndDiscard) {
   [session_controller_ addPendingItem:GURL("http://www.example.com")
                              referrer:web::Referrer()
@@ -239,11 +248,11 @@
   [session_controller_ commitPendingItem];
 
   [session_controller_ setPendingItemIndex:0];
-  EXPECT_TRUE([session_controller_ pendingItem]);
+  EXPECT_TRUE([session_controller_ pendingEntry]);
   EXPECT_EQ(0, [session_controller_ pendingItemIndex]);
 
   [session_controller_ discardNonCommittedItems];
-  EXPECT_FALSE([session_controller_ pendingItem]);
+  EXPECT_FALSE([session_controller_ pendingEntry]);
   EXPECT_EQ(-1, [session_controller_ pendingItemIndex]);
 }
 
@@ -260,11 +269,13 @@
                     rendererInitiated:NO];
   [session_controller_ commitPendingItem];
 
-  EXPECT_EQ(1U, [session_controller_ items].size());
-  EXPECT_EQ(GURL("http://www.another.url.com/"),
-            [session_controller_ URLForNavigationItemAtIndex:0U]);
-  EXPECT_EQ([session_controller_ items].front().get(),
-            [session_controller_ currentItem]);
+  EXPECT_EQ(1U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      GURL("http://www.another.url.com/"),
+      [session_controller_ URLForSessionAtIndex:0U]);
+  EXPECT_EQ(
+      [[session_controller_ entries] objectAtIndex:0U],
+      [session_controller_ currentEntry]);
 }
 
 TEST_F(CRWSessionControllerTest, addPendingItemAndCommitAndAddAndDiscard) {
@@ -280,41 +291,44 @@
                     rendererInitiated:NO];
   [session_controller_ discardNonCommittedItems];
 
-  EXPECT_EQ(1U, [session_controller_ items].size());
-  EXPECT_EQ(GURL("http://www.url.com/"),
-            [session_controller_ URLForNavigationItemAtIndex:0U]);
-  EXPECT_EQ([session_controller_ items].front().get(),
-            [session_controller_ currentItem]);
+  EXPECT_EQ(1U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      GURL("http://www.url.com/"),
+      [session_controller_ URLForSessionAtIndex:0U]);
+  EXPECT_EQ(
+      [[session_controller_ entries] objectAtIndex:0U],
+      [session_controller_ currentEntry]);
 }
 
 TEST_F(CRWSessionControllerTest,
-       commitPendingItemWithoutPendingOrCommittedItem) {
+       commitPendingItemWithoutPendingOrCommittedEntry) {
   [session_controller_ commitPendingItem];
 
-  EXPECT_EQ(0U, [session_controller_ items].size());
-  EXPECT_EQ(nullptr, [session_controller_ currentItem]);
+  EXPECT_EQ(0U, [[session_controller_ entries] count]);
+  EXPECT_EQ(nil, [session_controller_ currentEntry]);
 }
 
 TEST_F(CRWSessionControllerTest,
-       commitPendingItemWithoutPendingItemWithCommittedItem) {
-  // Setup committed item
+       commitPendingItemWithoutPendingEntryWithCommittedEntry) {
+  // Setup committed entry
   [session_controller_ addPendingItem:GURL("http://www.url.com")
                              referrer:MakeReferrer("http://www.referer.com")
                            transition:ui::PAGE_TRANSITION_TYPED
                     rendererInitiated:NO];
   [session_controller_ commitPendingItem];
 
-  // Commit pending item when there is no such one
+  // Commit pending entry when there is no such one
   [session_controller_ commitPendingItem];
 
-  EXPECT_EQ(1U, [session_controller_ items].size());
-  EXPECT_EQ([session_controller_ items].front().get(),
-            [session_controller_ currentItem]);
+  EXPECT_EQ(1U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      [[session_controller_ entries] objectAtIndex:0U],
+      [session_controller_ currentEntry]);
 }
 
-// Tests that forward items are discarded after navigation item is committed.
-TEST_F(CRWSessionControllerTest, commitPendingItemWithExistingForwardItems) {
-  // Make 3 items.
+// Tests that forward entries are discarded after navigation entry is committed.
+TEST_F(CRWSessionControllerTest, commitPendingItemWithExistingForwardEntries) {
+  // Make 3 entries.
   [session_controller_ addPendingItem:GURL("http://www.example.com/0")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
@@ -331,24 +345,24 @@
                     rendererInitiated:YES];
   [session_controller_ commitPendingItem];
 
-  // Go back to the first item.
+  // Go back to the first entry.
   [session_controller_ goToItemAtIndex:0];
 
-  // Create and commit a new pending item.
+  // Create and commit a new pending entry.
   [session_controller_ addPendingItem:GURL("http://www.example.com/2")
                              referrer:MakeReferrer("http://www.example.com/c")
                            transition:ui::PAGE_TRANSITION_LINK
                     rendererInitiated:YES];
   [session_controller_ commitPendingItem];
 
-  // All forward items should go away.
-  EXPECT_EQ(2U, [session_controller_ items].size());
-  EXPECT_EQ(0U, [session_controller_ forwardItems].size());
+  // All forward entries should go away.
+  EXPECT_EQ(2U, [[session_controller_ entries] count]);
+  EXPECT_EQ(0U, [[session_controller_ forwardEntries] count]);
   ASSERT_EQ(1, [session_controller_ currentNavigationIndex]);
   ASSERT_EQ(0, [session_controller_ previousNavigationIndex]);
 }
 
-// Tests committing pending item index from the middle.
+// Tests committing pending entry index from the middle.
 TEST_F(CRWSessionControllerTest, commitPendingItemIndex) {
   [session_controller_ addPendingItem:GURL("http://www.example.com/0")
                              referrer:web::Referrer()
@@ -365,62 +379,64 @@
                            transition:ui::PAGE_TRANSITION_TYPED
                     rendererInitiated:NO];
   [session_controller_ commitPendingItem];
-  ASSERT_EQ(3U, [session_controller_ items].size());
+  ASSERT_EQ(3U, [[session_controller_ entries] count]);
 
-  // Go to the middle, and commit first pending item index.
+  // Go to the middle, and commit first pending entry index.
   [session_controller_ goToItemAtIndex:1];
   [session_controller_ setPendingItemIndex:0];
   ASSERT_EQ(0, [session_controller_ pendingItemIndex]);
-  web::NavigationItemImpl* pending_item = [session_controller_ pendingItem];
-  ASSERT_TRUE(pending_item);
+  base::scoped_nsobject<CRWSessionEntry> pendingEntry(
+      [[session_controller_ pendingEntry] retain]);
+  ASSERT_TRUE(pendingEntry);
   ASSERT_EQ(1, [session_controller_ currentNavigationIndex]);
   EXPECT_EQ(2, [session_controller_ previousNavigationIndex]);
   [session_controller_ commitPendingItem];
 
-  // Verify that pending item has been committed and current and previous item
+  // Verify that pending entry has been committed and current and previous entry
   // indices updated.
-  EXPECT_EQ(pending_item, [session_controller_ lastCommittedItem]);
+  EXPECT_EQ(pendingEntry, [session_controller_ lastCommittedEntry]);
   EXPECT_EQ(-1, [session_controller_ pendingItemIndex]);
-  EXPECT_FALSE([session_controller_ pendingItem]);
+  EXPECT_FALSE([session_controller_ pendingEntry]);
   EXPECT_EQ(0, [session_controller_ currentNavigationIndex]);
   EXPECT_EQ(1, [session_controller_ previousNavigationIndex]);
-  EXPECT_EQ(3U, [session_controller_ items].size());
+  EXPECT_EQ(3U, [[session_controller_ entries] count]);
 }
 
 TEST_F(CRWSessionControllerTest,
-       DiscardPendingItemWithoutPendingOrCommittedItem) {
+       DiscardPendingEntryWithoutPendingOrCommittedEntry) {
   [session_controller_ discardNonCommittedItems];
 
-  EXPECT_EQ(0U, [session_controller_ items].size());
-  EXPECT_EQ(nil, [session_controller_ currentItem]);
+  EXPECT_EQ(0U, [[session_controller_ entries] count]);
+  EXPECT_EQ(nil, [session_controller_ currentEntry]);
 }
 
 TEST_F(CRWSessionControllerTest,
-       DiscardPendingItemWithoutPendingItemWithCommittedItem) {
-  // Setup committed item
+       DiscardPendingEntryWithoutPendingEntryWithCommittedEntry) {
+  // Setup committed entry
   [session_controller_ addPendingItem:GURL("http://www.url.com")
                              referrer:MakeReferrer("http://www.referer.com")
                            transition:ui::PAGE_TRANSITION_TYPED
                     rendererInitiated:NO];
   [session_controller_ commitPendingItem];
 
-  // Discard noncommitted items when there is no such one
+  // Discard noncommitted entries when there is no such one
   [session_controller_ discardNonCommittedItems];
 
-  EXPECT_EQ(1U, [session_controller_ items].size());
-  EXPECT_EQ([session_controller_ items].front().get(),
-            [session_controller_ currentItem]);
+  EXPECT_EQ(1U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      [[session_controller_ entries] objectAtIndex:0U],
+      [session_controller_ currentEntry]);
 }
 
-TEST_F(CRWSessionControllerTest, updatePendingItemWithoutPendingItem) {
+TEST_F(CRWSessionControllerTest, updatePendingItemWithoutPendingEntry) {
   [session_controller_ updatePendingItem:GURL("http://www.another.url.com")];
   [session_controller_ commitPendingItem];
 
-  EXPECT_EQ(0U, [session_controller_ items].size());
-  EXPECT_EQ(nil, [session_controller_ currentItem]);
+  EXPECT_EQ(0U, [[session_controller_ entries] count]);
+  EXPECT_EQ(nil, [session_controller_ currentEntry]);
 }
 
-TEST_F(CRWSessionControllerTest, updatePendingItemWithPendingItem) {
+TEST_F(CRWSessionControllerTest, updatePendingItemWithPendingEntry) {
   [session_controller_ addPendingItem:GURL("http://www.url.com")
                              referrer:MakeReferrer("http://www.referer.com")
                            transition:ui::PAGE_TRANSITION_TYPED
@@ -433,7 +449,7 @@
 }
 
 TEST_F(CRWSessionControllerTest,
-       updatePendingItemWithPendingItemAlreadyCommited) {
+       updatePendingItemWithPendingEntryAlreadyCommited) {
   [session_controller_ addPendingItem:GURL("http://www.url.com")
                              referrer:MakeReferrer("http://www.referer.com")
                            transition:ui::PAGE_TRANSITION_TYPED
@@ -442,16 +458,18 @@
   [session_controller_ updatePendingItem:GURL("http://www.another.url.com")];
   [session_controller_ commitPendingItem];
 
-  EXPECT_EQ(1U, [session_controller_ items].size());
-  EXPECT_EQ(GURL("http://www.url.com/"),
-            [session_controller_ URLForNavigationItemAtIndex:0U]);
-  EXPECT_EQ([session_controller_ items].front().get(),
-            [session_controller_ currentItem]);
+  EXPECT_EQ(1U, [[session_controller_ entries] count]);
+  EXPECT_EQ(
+      GURL("http://www.url.com/"),
+      [session_controller_ URLForSessionAtIndex:0U]);
+  EXPECT_EQ(
+      [[session_controller_ entries] objectAtIndex:0U],
+      [session_controller_ currentEntry]);
 }
 
 // Tests inserting session controller state.
 TEST_F(CRWSessionControllerTest, InsertState) {
-  // Add 1 committed and 1 pending item to target controller.
+  // Add 1 committed and 1 pending entry to target controller.
   [session_controller_ addPendingItem:GURL("http://www.url.com/2")
                              referrer:web::Referrer()
                            transition:ui::PAGE_TRANSITION_TYPED
@@ -462,7 +480,7 @@
                            transition:ui::PAGE_TRANSITION_TYPED
                     rendererInitiated:NO];
 
-  // Create source session controller with 1 committed item.
+  // Create source session controller with 1 committed entry.
   base::scoped_nsobject<CRWSessionController> other_session_controller(
       [[CRWSessionController alloc] initWithWindowName:nil
                                               openerId:nil
@@ -485,22 +503,22 @@
       insertStateFromSessionController:other_session_controller.get()];
 
   EXPECT_NSEQ(@"test-window", [session_controller_ windowName]);
-  EXPECT_EQ(2U, [session_controller_ items].size());
+  EXPECT_EQ(2U, [[session_controller_ entries] count]);
   EXPECT_EQ(1, [session_controller_ currentNavigationIndex]);
   EXPECT_EQ(-1, [session_controller_ previousNavigationIndex]);
   EXPECT_EQ(-1, [session_controller_ pendingItemIndex]);
 
   EXPECT_EQ(GURL("http://www.url.com/0"),
-            [session_controller_ URLForNavigationItemAtIndex:0]);
+            [session_controller_ URLForSessionAtIndex:0]);
   EXPECT_EQ(GURL("http://www.url.com/2"),
-            [session_controller_ URLForNavigationItemAtIndex:1]);
+            [session_controller_ URLForSessionAtIndex:1]);
   EXPECT_EQ(GURL("http://www.url.com/3"),
-            [session_controller_ pendingItem]->GetURL());
+            [[session_controller_ pendingEntry] navigationItem]->GetURL());
 }
 
 // Tests inserting session controller state from empty session controller.
 TEST_F(CRWSessionControllerTest, InsertStateFromEmptySessionController) {
-  // Add 2 committed items to target controller.
+  // Add 2 committed entries to target controller.
   [session_controller_ addPendingItem:GURL("http://www.url.com/0")
                              referrer:web::Referrer()
                            transition:ui::PAGE_TRANSITION_TYPED
@@ -526,21 +544,21 @@
       insertStateFromSessionController:other_session_controller.get()];
 
   EXPECT_NSEQ(@"test-window", [session_controller_ windowName]);
-  EXPECT_EQ(2U, [session_controller_ items].size());
+  EXPECT_EQ(2U, [[session_controller_ entries] count]);
   EXPECT_EQ(1, [session_controller_ currentNavigationIndex]);
   EXPECT_EQ(0, [session_controller_ previousNavigationIndex]);
   EXPECT_EQ(-1, [session_controller_ pendingItemIndex]);
-  EXPECT_FALSE([session_controller_ pendingItem]);
+  EXPECT_FALSE([session_controller_ pendingEntry]);
   EXPECT_EQ(GURL("http://www.url.com/0"),
-            [session_controller_ URLForNavigationItemAtIndex:0]);
+            [session_controller_ URLForSessionAtIndex:0]);
   EXPECT_EQ(GURL("http://www.url.com/1"),
-            [session_controller_ URLForNavigationItemAtIndex:1]);
+            [session_controller_ URLForSessionAtIndex:1]);
 }
 
 // Tests inserting session controller state to empty session controller.
 TEST_F(CRWSessionControllerTest, InsertStateToEmptySessionController) {
-  // Create source session controller with 2 committed items and one
-  // pending item.
+  // Create source session controller with 2 committed entries and one
+  // pending entry.
   base::scoped_nsobject<CRWSessionController> other_session_controller(
       [[CRWSessionController alloc] initWithWindowName:nil
                                               openerId:nil
@@ -568,22 +586,22 @@
       insertStateFromSessionController:other_session_controller.get()];
 
   EXPECT_NSEQ(@"test-window", [session_controller_ windowName]);
-  EXPECT_EQ(2U, [session_controller_ items].size());
+  EXPECT_EQ(2U, [[session_controller_ entries] count]);
   EXPECT_EQ(1, [session_controller_ currentNavigationIndex]);
   EXPECT_EQ(-1, [session_controller_ previousNavigationIndex]);
   EXPECT_EQ(-1, [session_controller_ pendingItemIndex]);
-  EXPECT_FALSE([session_controller_ pendingItem]);
+  EXPECT_FALSE([session_controller_ pendingEntry]);
   EXPECT_EQ(GURL("http://www.url.com/0"),
-            [session_controller_ URLForNavigationItemAtIndex:0]);
+            [session_controller_ URLForSessionAtIndex:0]);
   EXPECT_EQ(GURL("http://www.url.com/1"),
-            [session_controller_ URLForNavigationItemAtIndex:1]);
+            [session_controller_ URLForSessionAtIndex:1]);
 }
 
-// Tests inserting session controller state. Verifies that pending item index
+// Tests inserting session controller state. Verifies that pending entry index
 // remains valid.
 TEST_F(CRWSessionControllerTest,
-       InsertStateWithPendingItemIndexInTargetController) {
-  // Add 2 committed items and make the first item pending.
+       InsertStateWithPendingEntryIndexInTargetController) {
+  // Add 2 committed entries and make the first entry pending.
   [session_controller_ addPendingItem:GURL("http://www.url.com/2")
                              referrer:web::Referrer()
                            transition:ui::PAGE_TRANSITION_TYPED
@@ -596,7 +614,7 @@
   [session_controller_ commitPendingItem];
   [session_controller_ setPendingItemIndex:0];
 
-  // Create source session controller with 1 committed item.
+  // Create source session controller with 1 committed entry.
   base::scoped_nsobject<CRWSessionController> other_session_controller(
       [[CRWSessionController alloc] initWithWindowName:nil
                                               openerId:nil
@@ -615,25 +633,25 @@
       insertStateFromSessionController:other_session_controller.get()];
 
   EXPECT_NSEQ(@"test-window", [session_controller_ windowName]);
-  EXPECT_EQ(3U, [session_controller_ items].size());
+  EXPECT_EQ(3U, [[session_controller_ entries] count]);
   EXPECT_EQ(2, [session_controller_ currentNavigationIndex]);
   EXPECT_EQ(-1, [session_controller_ previousNavigationIndex]);
   EXPECT_EQ(1, [session_controller_ pendingItemIndex]);
   EXPECT_EQ(GURL("http://www.url.com/0"),
-            [session_controller_ URLForNavigationItemAtIndex:0]);
+            [session_controller_ URLForSessionAtIndex:0]);
   EXPECT_EQ(GURL("http://www.url.com/2"),
-            [session_controller_ URLForNavigationItemAtIndex:1]);
+            [session_controller_ URLForSessionAtIndex:1]);
   EXPECT_EQ(GURL("http://www.url.com/2"),
-            [session_controller_ pendingItem]->GetURL());
+            [[session_controller_ pendingEntry] navigationItem]->GetURL());
 }
 
 // Tests state of an empty session controller.
 TEST_F(CRWSessionControllerTest, EmptyController) {
-  EXPECT_EQ(0U, [session_controller_ items].size());
+  EXPECT_EQ(0U, [[session_controller_ entries] count]);
   EXPECT_EQ(-1, [session_controller_ currentNavigationIndex]);
   EXPECT_EQ(-1, [session_controller_ previousNavigationIndex]);
-  EXPECT_FALSE([session_controller_ currentItem]);
-  EXPECT_FALSE([session_controller_ pendingItem]);
+  EXPECT_FALSE([session_controller_ currentEntry]);
+  EXPECT_FALSE([session_controller_ pendingEntry]);
   EXPECT_EQ(-1, [session_controller_ pendingItemIndex]);
 }
 
@@ -660,10 +678,10 @@
       [[CRWSessionController alloc] initWithNavigationItems:std::move(items)
                                                currentIndex:0
                                                browserState:&browser_state_]);
-  EXPECT_EQ(controller.get().items.size(), 0U);
+  EXPECT_EQ(controller.get().entries.count, 0U);
   EXPECT_EQ(controller.get().currentNavigationIndex, -1);
   EXPECT_EQ(controller.get().previousNavigationIndex, -1);
-  EXPECT_FALSE(controller.get().currentItem);
+  EXPECT_FALSE(controller.get().currentEntry);
 }
 
 TEST_F(CRWSessionControllerTest, CreateWithNavList) {
@@ -679,17 +697,19 @@
                                                currentIndex:1
                                                browserState:&browser_state_]);
 
-  EXPECT_EQ(controller.get().items.size(), 3U);
+  EXPECT_EQ(controller.get().entries.count, 3U);
   EXPECT_EQ(controller.get().currentNavigationIndex, 1);
   EXPECT_EQ(controller.get().previousNavigationIndex, -1);
-  // Sanity check the current item, the NavigationItem unit test will ensure
+  // Sanity check the current entry, the CRWSessionEntry unit test will ensure
   // the entire object is created properly.
-  EXPECT_EQ([controller currentItem]->GetURL(), GURL("http://www.yahoo.com"));
+  CRWSessionEntry* current_entry = controller.get().currentEntry;
+  EXPECT_EQ(current_entry.navigationItem->GetURL(),
+            GURL("http://www.yahoo.com"));
   EXPECT_EQ([[controller openerId] length], 0UL);
 }
 
-// Tests index of previous navigation item.
-TEST_F(CRWSessionControllerTest, PreviousNavigationItem) {
+// Tests index of previous navigation entry.
+TEST_F(CRWSessionControllerTest, PreviousNavigationEntry) {
   EXPECT_EQ(session_controller_.get().previousNavigationIndex, -1);
   [session_controller_ addPendingItem:GURL("http://www.url.com")
                              referrer:MakeReferrer("http://www.referer.com")
@@ -724,7 +744,7 @@
   EXPECT_EQ(session_controller_.get().previousNavigationIndex, 1);
 }
 
-TEST_F(CRWSessionControllerTest, PushNewItem) {
+TEST_F(CRWSessionControllerTest, PushNewEntry) {
   std::vector<std::unique_ptr<web::NavigationItem>> items;
   items.push_back(CreateNavigationItem("http://www.firstpage.com",
                                        "http://www.starturl.com", @"First"));
@@ -742,26 +762,29 @@
   [controller pushNewItemWithURL:pushPageGurl1
                      stateObject:stateObject1
                       transition:ui::PAGE_TRANSITION_LINK];
-  web::NavigationItemImpl* pushedItem = [controller currentItem];
+  CRWSessionEntry* pushedEntry = [controller currentEntry];
+  web::NavigationItemImpl* pushedItem = pushedEntry.navigationItemImpl;
   NSUInteger expectedCount = 2;
-  EXPECT_EQ(expectedCount, [controller items].size());
-  EXPECT_EQ(pushPageGurl1, pushedItem->GetURL());
+  EXPECT_EQ(expectedCount, controller.get().entries.count);
+  EXPECT_EQ(pushPageGurl1, pushedEntry.navigationItem->GetURL());
   EXPECT_TRUE(pushedItem->IsCreatedFromPushState());
   EXPECT_NSEQ(stateObject1, pushedItem->GetSerializedStateObject());
-  EXPECT_EQ(GURL("http://www.firstpage.com/"), pushedItem->GetReferrer().url);
+  EXPECT_EQ(GURL("http://www.firstpage.com/"),
+            pushedEntry.navigationItem->GetReferrer().url);
 
-  // Add another new item and check size and fields again.
+  // Add another new entry and check size and fields again.
   GURL pushPageGurl2("http://www.firstpage.com/push2");
   [controller pushNewItemWithURL:pushPageGurl2
                      stateObject:nil
                       transition:ui::PAGE_TRANSITION_LINK];
-  pushedItem = [controller currentItem];
+  pushedEntry = [controller currentEntry];
+  pushedItem = pushedEntry.navigationItemImpl;
   expectedCount = 3;
-  EXPECT_EQ(expectedCount, [controller items].size());
-  EXPECT_EQ(pushPageGurl2, pushedItem->GetURL());
+  EXPECT_EQ(expectedCount, controller.get().entries.count);
+  EXPECT_EQ(pushPageGurl2, pushedEntry.navigationItem->GetURL());
   EXPECT_TRUE(pushedItem->IsCreatedFromPushState());
   EXPECT_EQ(nil, pushedItem->GetSerializedStateObject());
-  EXPECT_EQ(pushPageGurl1, pushedItem->GetReferrer().url);
+  EXPECT_EQ(pushPageGurl1, pushedEntry.navigationItem->GetReferrer().url);
 }
 
 TEST_F(CRWSessionControllerTest, IsSameDocumentNavigation) {
@@ -785,12 +808,18 @@
       [[CRWSessionController alloc] initWithNavigationItems:std::move(items)
                                                currentIndex:0
                                                browserState:&browser_state_]);
-  web::NavigationItemImpl* item0 = [controller items][0].get();
-  web::NavigationItemImpl* item1 = [controller items][1].get();
-  web::NavigationItemImpl* item2 = [controller items][2].get();
-  web::NavigationItemImpl* item3 = [controller items][3].get();
-  web::NavigationItemImpl* item4 = [controller items][4].get();
-  web::NavigationItemImpl* item5 = [controller items][5].get();
+  web::NavigationItemImpl* item0 =
+      static_cast<web::NavigationItemImpl*>([controller items][0]);
+  web::NavigationItemImpl* item1 =
+      static_cast<web::NavigationItemImpl*>([controller items][1]);
+  web::NavigationItemImpl* item2 =
+      static_cast<web::NavigationItemImpl*>([controller items][2]);
+  web::NavigationItemImpl* item3 =
+      static_cast<web::NavigationItemImpl*>([controller items][3]);
+  web::NavigationItemImpl* item4 =
+      static_cast<web::NavigationItemImpl*>([controller items][4]);
+  web::NavigationItemImpl* item5 =
+      static_cast<web::NavigationItemImpl*>([controller items][5]);
   item1->SetIsCreatedFromPushState(true);
   item4->SetIsCreatedFromHashChange(true);
   item5->SetIsCreatedFromPushState(true);
@@ -811,7 +840,7 @@
       [controller isSameDocumentNavigationBetweenItem:item2 andItem:item4]);
 }
 
-TEST_F(CRWSessionControllerTest, UpdateCurrentItem) {
+TEST_F(CRWSessionControllerTest, UpdateCurrentEntry) {
   std::vector<std::unique_ptr<web::NavigationItem>> items;
   items.push_back(CreateNavigationItem("http://www.firstpage.com",
                                        "http://www.starturl.com", @"First"));
@@ -827,30 +856,34 @@
   GURL replacePageGurl1("http://www.firstpage.com/#replace1");
   NSString* stateObject1 = @"{'foo': 1}";
 
-  // Replace current item and check the size of history and fields of the
-  // modified item.
+  // Replace current entry and check the size of history and fields of the
+  // modified entry.
   [controller updateCurrentItemWithURL:replacePageGurl1
                            stateObject:stateObject1];
-  web::NavigationItemImpl* replacedItem = [controller currentItem];
+  CRWSessionEntry* replacedEntry = [controller currentEntry];
+  web::NavigationItemImpl* replacedItem = replacedEntry.navigationItemImpl;
   NSUInteger expectedCount = 3;
-  EXPECT_EQ(expectedCount, [controller items].size());
-  EXPECT_EQ(replacePageGurl1, replacedItem->GetURL());
+  EXPECT_EQ(expectedCount, controller.get().entries.count);
+  EXPECT_EQ(replacePageGurl1, replacedEntry.navigationItem->GetURL());
   EXPECT_FALSE(replacedItem->IsCreatedFromPushState());
   EXPECT_NSEQ(stateObject1, replacedItem->GetSerializedStateObject());
-  EXPECT_EQ(GURL("http://www.starturl.com/"), replacedItem->GetReferrer().url);
+  EXPECT_EQ(GURL("http://www.starturl.com/"),
+            replacedEntry.navigationItem->GetReferrer().url);
 
-  // Replace current item and check size and fields again.
+  // Replace current entry and check size and fields again.
   GURL replacePageGurl2("http://www.firstpage.com/#replace2");
   [controller.get() updateCurrentItemWithURL:replacePageGurl2 stateObject:nil];
-  replacedItem = [controller currentItem];
-  EXPECT_EQ(expectedCount, [controller items].size());
-  EXPECT_EQ(replacePageGurl2, replacedItem->GetURL());
+  replacedEntry = [controller currentEntry];
+  replacedItem = replacedEntry.navigationItemImpl;
+  EXPECT_EQ(expectedCount, controller.get().entries.count);
+  EXPECT_EQ(replacePageGurl2, replacedEntry.navigationItem->GetURL());
   EXPECT_FALSE(replacedItem->IsCreatedFromPushState());
   EXPECT_NSEQ(nil, replacedItem->GetSerializedStateObject());
-  EXPECT_EQ(GURL("http://www.starturl.com/"), replacedItem->GetReferrer().url);
+  EXPECT_EQ(GURL("http://www.starturl.com/"),
+            replacedEntry.navigationItem->GetReferrer().url);
 }
 
-TEST_F(CRWSessionControllerTest, TestBackwardForwardItems) {
+TEST_F(CRWSessionControllerTest, TestBackwardForwardEntries) {
   [session_controller_ addPendingItem:GURL("http://www.example.com/0")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
@@ -873,25 +906,26 @@
   [session_controller_ commitPendingItem];
 
   EXPECT_EQ(3, session_controller_.get().currentNavigationIndex);
-  web::NavigationItemList backItems = [session_controller_ backwardItems];
-  EXPECT_EQ(2U, backItems.size());
-  EXPECT_EQ(0U, [session_controller_ forwardItems].size());
+  NSArray* backEntries = [session_controller_ backwardEntries];
+  EXPECT_EQ(2U, [backEntries count]);
+  EXPECT_EQ(0U, [[session_controller_ forwardEntries] count]);
   EXPECT_EQ("http://www.example.com/redirect",
-            backItems.front()->GetURL().spec());
+            [[backEntries objectAtIndex:0] navigationItem]->GetURL().spec());
 
   [session_controller_ goToItemAtIndex:1];
-  EXPECT_EQ(1U, [session_controller_ backwardItems].size());
-  EXPECT_EQ(1U, [session_controller_ forwardItems].size());
+  EXPECT_EQ(1U, [[session_controller_ backwardEntries] count]);
+  EXPECT_EQ(1U, [[session_controller_ forwardEntries] count]);
 
   [session_controller_ goToItemAtIndex:0];
-  web::NavigationItemList forwardItems = [session_controller_ forwardItems];
-  EXPECT_EQ(0U, [session_controller_ backwardItems].size());
-  EXPECT_EQ(2U, forwardItems.size());
-  EXPECT_EQ("http://www.example.com/2", forwardItems[1]->GetURL().spec());
+  NSArray* forwardEntries = [session_controller_ forwardEntries];
+  EXPECT_EQ(0U, [[session_controller_ backwardEntries] count]);
+  EXPECT_EQ(2U, [forwardEntries count]);
+  EXPECT_EQ("http://www.example.com/2",
+            [[forwardEntries objectAtIndex:1] navigationItem]->GetURL().spec());
 }
 
-// Tests going to items with existing and non-existing indices.
-TEST_F(CRWSessionControllerTest, GoToItemAtIndex) {
+// Tests going to entries with existing and non-existing indices.
+TEST_F(CRWSessionControllerTest, GoToEntryAtIndex) {
   [session_controller_ addPendingItem:GURL("http://www.example.com/0")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
@@ -919,23 +953,23 @@
   [session_controller_ addTransientItemWithURL:GURL("http://www.example.com")];
   EXPECT_EQ(3, session_controller_.get().currentNavigationIndex);
   EXPECT_EQ(2, session_controller_.get().previousNavigationIndex);
-  EXPECT_TRUE(session_controller_.get().pendingItem);
-  EXPECT_TRUE(session_controller_.get().transientItem);
+  EXPECT_TRUE(session_controller_.get().pendingEntry);
+  EXPECT_TRUE(session_controller_.get().transientEntry);
 
-  // Going back should discard transient and pending items.
+  // Going back should discard transient and pending entries.
   [session_controller_ goToItemAtIndex:1];
   EXPECT_EQ(1, session_controller_.get().currentNavigationIndex);
   EXPECT_EQ(3, session_controller_.get().previousNavigationIndex);
-  EXPECT_FALSE(session_controller_.get().pendingItem);
-  EXPECT_FALSE(session_controller_.get().transientItem);
+  EXPECT_FALSE(session_controller_.get().pendingEntry);
+  EXPECT_FALSE(session_controller_.get().transientEntry);
 
-  // Going forward should discard transient item.
+  // Going forward should discard transient entry.
   [session_controller_ addTransientItemWithURL:GURL("http://www.example.com")];
-  EXPECT_TRUE(session_controller_.get().transientItem);
+  EXPECT_TRUE(session_controller_.get().transientEntry);
   [session_controller_ goToItemAtIndex:2];
   EXPECT_EQ(2, session_controller_.get().currentNavigationIndex);
   EXPECT_EQ(1, session_controller_.get().previousNavigationIndex);
-  EXPECT_FALSE(session_controller_.get().transientItem);
+  EXPECT_FALSE(session_controller_.get().transientEntry);
 
   // Out of bounds navigations should be no-op.
   [session_controller_ goToItemAtIndex:-1];
@@ -952,44 +986,47 @@
 }
 
 // Tests that visible URL is the same as transient URL if there are no committed
-// items.
-TEST_F(CRWSessionControllerTest, VisibleItemWithSingleTransientItem) {
+// entries.
+TEST_F(CRWSessionControllerTest, VisibleEntryWithSingleTransientEntry) {
   [session_controller_ addTransientItemWithURL:GURL("http://www.example.com")];
-  web::NavigationItemImpl* visible_item = [session_controller_ visibleItem];
+  web::NavigationItem* visible_item =
+      [[session_controller_ visibleEntry] navigationItem];
   ASSERT_TRUE(visible_item);
   EXPECT_EQ("http://www.example.com/", visible_item->GetURL().spec());
 }
 
 // Tests that visible URL is the same as transient URL if there is a committed
-// item.
-TEST_F(CRWSessionControllerTest, VisibleItemWithCommittedAndTransientItems) {
+// entry.
+TEST_F(CRWSessionControllerTest, VisibleEntryWithCommittedAndTransientEntries) {
   [session_controller_ addPendingItem:GURL("http://www.example.com/0")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
                     rendererInitiated:NO];
   [session_controller_ commitPendingItem];
   [session_controller_ addTransientItemWithURL:GURL("http://www.example.com")];
-  web::NavigationItemImpl* visible_item = [session_controller_ visibleItem];
+  web::NavigationItem* visible_item =
+      [[session_controller_ visibleEntry] navigationItem];
   ASSERT_TRUE(visible_item);
   EXPECT_EQ("http://www.example.com/", visible_item->GetURL().spec());
 }
 
 // Tests that visible URL is the same as pending URL if it was user-initiated.
 TEST_F(CRWSessionControllerTest,
-       VisibleItemWithSingleUserInitiatedPendingItem) {
+       VisibleEntryWithSingleUserInitiatedPendingEntry) {
   [session_controller_ addPendingItem:GURL("http://www.example.com/0")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
                     rendererInitiated:NO];
-  web::NavigationItemImpl* visible_item = [session_controller_ visibleItem];
+  web::NavigationItem* visible_item =
+      [[session_controller_ visibleEntry] navigationItem];
   ASSERT_TRUE(visible_item);
   EXPECT_EQ("http://www.example.com/0", visible_item->GetURL().spec());
 }
 
 // Tests that visible URL is the same as pending URL if it was user-initiated
-// and there is a committed item.
+// and there is a committed entry.
 TEST_F(CRWSessionControllerTest,
-       VisibleItemWithCommittedAndUserInitiatedPendingItem) {
+       VisibleEntryWithCommittedAndUserInitiatedPendingEntry) {
   [session_controller_ addPendingItem:GURL("http://www.example.com")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
@@ -999,7 +1036,8 @@
                              referrer:MakeReferrer("http://www.example.com/b")
                            transition:ui::PAGE_TRANSITION_LINK
                     rendererInitiated:NO];
-  web::NavigationItemImpl* visible_item = [session_controller_ visibleItem];
+  web::NavigationItem* visible_item =
+      [[session_controller_ visibleEntry] navigationItem];
   ASSERT_TRUE(visible_item);
   EXPECT_EQ("http://www.example.com/0", visible_item->GetURL().spec());
 }
@@ -1007,19 +1045,20 @@
 // Tests that visible URL is not the same as pending URL if it was
 // renderer-initiated.
 TEST_F(CRWSessionControllerTest,
-       VisibleItemWithSingleRendererInitiatedPendingItem) {
+       VisibleEntryWithSingleRendererInitiatedPendingEntry) {
   [session_controller_ addPendingItem:GURL("http://www.example.com/0")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
                     rendererInitiated:YES];
-  web::NavigationItemImpl* visible_item = [session_controller_ visibleItem];
+  web::NavigationItem* visible_item =
+      [[session_controller_ visibleEntry] navigationItem];
   ASSERT_FALSE(visible_item);
 }
 
 // Tests that visible URL is not the same as pending URL if it was
-// renderer-initiated and there is a committed item.
+// renderer-initiated and there is a committed entry.
 TEST_F(CRWSessionControllerTest,
-       VisibleItemWithCommittedAndRendererInitiatedPendingItem) {
+       VisibleEntryWithCommittedAndRendererInitiatedPendingEntry) {
   [session_controller_ addPendingItem:GURL("http://www.example.com")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
@@ -1029,14 +1068,15 @@
                              referrer:MakeReferrer("http://www.example.com/b")
                            transition:ui::PAGE_TRANSITION_LINK
                     rendererInitiated:YES];
-  web::NavigationItemImpl* visible_item = [session_controller_ visibleItem];
+  web::NavigationItem* visible_item =
+      [[session_controller_ visibleEntry] navigationItem];
   ASSERT_TRUE(visible_item);
   EXPECT_EQ("http://www.example.com/", visible_item->GetURL().spec());
 }
 
 // Tests that visible URL is not the same as pending URL created via pending
 // navigation index.
-TEST_F(CRWSessionControllerTest, VisibleItemWithPendingNavigationIndex) {
+TEST_F(CRWSessionControllerTest, VisibleEntryWithPendingNavigationIndex) {
   [session_controller_ addPendingItem:GURL("http://www.example.com")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_LINK
@@ -1050,14 +1090,15 @@
 
   [session_controller_ setPendingItemIndex:0];
 
-  web::NavigationItemImpl* visible_item = [session_controller_ visibleItem];
+  web::NavigationItem* visible_item =
+      [[session_controller_ visibleEntry] navigationItem];
   ASSERT_TRUE(visible_item);
   EXPECT_EQ("http://www.example.com/0", visible_item->GetURL().spec());
 }
 
-// Tests that |-backwardItems| is empty if all preceding items are
+// Tests that |-backwardEntries| is empty if all preceding entries are
 // redirects.
-TEST_F(CRWSessionControllerTest, BackwardItemsForAllRedirects) {
+TEST_F(CRWSessionControllerTest, BackwardEntriesForAllRedirects) {
   [session_controller_ addPendingItem:GURL("http://www.example.com")
                              referrer:MakeReferrer("http://www.example.com/a")
                            transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
@@ -1068,7 +1109,7 @@
                            transition:ui::PAGE_TRANSITION_CLIENT_REDIRECT
                     rendererInitiated:YES];
   [session_controller_ commitPendingItem];
-  EXPECT_EQ(0U, [session_controller_ backwardItems].size());
+  EXPECT_EQ(0U, [session_controller_ backwardEntries].count);
 }
 
 }  // anonymous namespace
diff --git a/ios/web/navigation/crw_session_entry.h b/ios/web/navigation/crw_session_entry.h
index f584712..1251d34 100644
--- a/ios/web/navigation/crw_session_entry.h
+++ b/ios/web/navigation/crw_session_entry.h
@@ -8,6 +8,8 @@
 #import <Foundation/Foundation.h>
 #include <stdint.h>
 
+#include <memory>
+
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "ui/base/page_transition_types.h"
@@ -25,7 +27,7 @@
 // DEPRECATED, do not use this class and do not add any methods to it.
 // Use web::NavigationItem instead.
 // TODO(crbug.com/454984): Remove this class.
-@interface CRWSessionEntry : NSObject
+@interface CRWSessionEntry : NSObject<NSCopying>
 
 // Pointer to the NavigationItem associated with this CRWSessionEntry.
 // Eventually, this will replace CRWSessionEntry entirely.
@@ -35,7 +37,8 @@
 @property(nonatomic, readonly) web::NavigationItemImpl* navigationItemImpl;
 
 // Initialize the session entry with the given NavigationItem.
-- (instancetype)initWithNavigationItem:(web::NavigationItem*)item;
+- (instancetype)initWithNavigationItem:
+    (std::unique_ptr<web::NavigationItem>)item;
 
 @end
 
diff --git a/ios/web/navigation/crw_session_entry.mm b/ios/web/navigation/crw_session_entry.mm
index dc381c4..2462bfc 100644
--- a/ios/web/navigation/crw_session_entry.mm
+++ b/ios/web/navigation/crw_session_entry.mm
@@ -21,46 +21,54 @@
 #endif
 
 @interface CRWSessionEntry () {
-  // The NavigationItem passed on initialization.
-  web::NavigationItemImpl* _item;
+  // The NavigationItemImpl corresponding to this CRWSessionEntry.
+  // TODO(stuartmorgan): Move ownership to NavigationManagerImpl.
+  std::unique_ptr<web::NavigationItemImpl> _navigationItem;
 }
 
 @end
 
 @implementation CRWSessionEntry
 
-- (instancetype)initWithNavigationItem:(web::NavigationItem*)item {
+- (instancetype)initWithNavigationItem:
+    (std::unique_ptr<web::NavigationItem>)item {
   self = [super init];
   if (self) {
-    DCHECK(item);
-    _item = static_cast<web::NavigationItemImpl*>(item);
+    _navigationItem.reset(
+        static_cast<web::NavigationItemImpl*>(item.release()));
   }
   return self;
 }
 
+// TODO(ios): Shall we overwrite EqualTo:?
+
+- (instancetype)copyWithZone:(NSZone*)zone {
+  CRWSessionEntry* copy = [[[self class] alloc] init];
+  copy->_navigationItem.reset(
+      new web::NavigationItemImpl(*_navigationItem.get()));
+  return copy;
+}
+
 - (NSString*)description {
   return [NSString
       stringWithFormat:
           @"url:%@ originalurl:%@ title:%@ transition:%d displayState:%@ "
           @"desktopUA:%d",
-          base::SysUTF8ToNSString(_item->GetURL().spec()),
-          base::SysUTF8ToNSString(_item->GetOriginalRequestURL().spec()),
-          base::SysUTF16ToNSString(_item->GetTitle()),
-          _item->GetTransitionType(),
-          _item->GetPageDisplayState().GetDescription(),
-          _item->IsOverridingUserAgent()];
+          base::SysUTF8ToNSString(_navigationItem->GetURL().spec()),
+          base::SysUTF8ToNSString(
+              _navigationItem->GetOriginalRequestURL().spec()),
+          base::SysUTF16ToNSString(_navigationItem->GetTitle()),
+          _navigationItem->GetTransitionType(),
+          _navigationItem->GetPageDisplayState().GetDescription(),
+          _navigationItem->IsOverridingUserAgent()];
 }
 
 - (web::NavigationItem*)navigationItem {
-  return _item;
+  return _navigationItem.get();
 }
 
 - (web::NavigationItemImpl*)navigationItemImpl {
-  return _item;
-}
-
-- (BOOL)isEqual:(CRWSessionEntry*)object {
-  return _item == [object navigationItem];
+  return _navigationItem.get();
 }
 
 @end
diff --git a/ios/web/navigation/crw_session_entry_unittest.mm b/ios/web/navigation/crw_session_entry_unittest.mm
index 9c0f05f..a5b9323 100644
--- a/ios/web/navigation/crw_session_entry_unittest.mm
+++ b/ios/web/navigation/crw_session_entry_unittest.mm
@@ -33,18 +33,18 @@
     GURL url("http://init.test");
     ui::PageTransition transition =
         ui::PAGE_TRANSITION_AUTO_BOOKMARK;
-    item_.reset(new web::NavigationItemImpl());
-    item_->SetOriginalRequestURL(url);
-    item_->SetURL(url);
-    item_->SetTransitionType(transition);
-    item_->SetTimestamp(base::Time::Now());
-    item_->SetPostData([@"Test data" dataUsingEncoding:NSUTF8StringEncoding]);
+    std::unique_ptr<web::NavigationItemImpl> item(
+        new web::NavigationItemImpl());
+    item->SetOriginalRequestURL(url);
+    item->SetURL(url);
+    item->SetTransitionType(transition);
+    item->SetTimestamp(base::Time::Now());
+    item->SetPostData([@"Test data" dataUsingEncoding:NSUTF8StringEncoding]);
     session_entry_.reset(
-        [[CRWSessionEntry alloc] initWithNavigationItem:item_.get()]);
+        [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item)]);
   }
 
  protected:
-  std::unique_ptr<web::NavigationItemImpl> item_;
   base::scoped_nsobject<CRWSessionEntry> session_entry_;
 };
 
diff --git a/ios/web/navigation/crw_session_storage_unittest.mm b/ios/web/navigation/crw_session_storage_unittest.mm
new file mode 100644
index 0000000..ffed4aa
--- /dev/null
+++ b/ios/web/navigation/crw_session_storage_unittest.mm
@@ -0,0 +1,105 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/public/crw_session_storage.h"
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#import "ios/web/navigation/navigation_item_impl.h"
+#import "ios/web/navigation/navigation_item_storage_test_util.h"
+#import "ios/web/navigation/serializable_user_data_manager_impl.h"
+#import "ios/web/public/crw_navigation_item_storage.h"
+#include "ios/web/public/referrer.h"
+#import "net/base/mac/url_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+#include "third_party/ocmock/gtest_support.h"
+#include "ui/base/page_transition_types.h"
+
+namespace {
+// Checks for equality between the item storages in |items1| and |items2|.
+BOOL ItemStorageListsAreEqual(NSArray* items1, NSArray* items2) {
+  __block BOOL items_are_equal = items1.count == items2.count;
+  if (!items_are_equal)
+    return NO;
+  [items1 enumerateObjectsUsingBlock:^(CRWNavigationItemStorage* item,
+                                       NSUInteger idx, BOOL* stop) {
+    items_are_equal &= web::ItemStoragesAreEqual(item, items2[idx]);
+    *stop = !items_are_equal;
+  }];
+  return items_are_equal;
+}
+// Checks for equality between |user_data1| and |user_data2|.
+BOOL UserDataAreEqual(web::SerializableUserData* user_data1,
+                      web::SerializableUserData* user_data2) {
+  web::SerializableUserDataImpl* data1 =
+      static_cast<web::SerializableUserDataImpl*>(user_data1);
+  web::SerializableUserDataImpl* data2 =
+      static_cast<web::SerializableUserDataImpl*>(user_data2);
+  return (data1 == nullptr) == (data2 == nullptr) &&
+         (!data1 || [data1->data() isEqualToDictionary:data2->data()]);
+}
+// Checks for equality between |session1| and |session2|.
+BOOL SessionStoragesAreEqual(CRWSessionStorage* session1,
+                             CRWSessionStorage* session2) {
+  // Check the rest of the properties.
+  NSArray* items1 = session1.itemStorages;
+  NSArray* items2 = session2.itemStorages;
+  return ItemStorageListsAreEqual(items1, items2) &&
+         [session1.openerID isEqual:session2.openerID] &&
+         session1.openedByDOM == session2.openedByDOM &&
+         session1.openerNavigationIndex == session2.openerNavigationIndex &&
+         [session1.windowName isEqual:session2.windowName] &&
+         session1.currentNavigationIndex == session2.currentNavigationIndex &&
+         session1.previousNavigationIndex == session2.previousNavigationIndex &&
+         session1.lastVisitedTimestamp == session2.lastVisitedTimestamp &&
+         UserDataAreEqual(session1.userData, session2.userData);
+}
+}  // namespace
+
+class CRWNSessionStorageTest : public PlatformTest {
+ protected:
+  CRWNSessionStorageTest()
+      : session_storage_([[CRWSessionStorage alloc] init]) {
+    // Set up |session_storage_|.
+    [session_storage_ setOpenerID:@"openerID"];
+    [session_storage_ setOpenedByDOM:YES];
+    [session_storage_ setOpenerNavigationIndex:2];
+    [session_storage_ setWindowName:@"windowName"];
+    [session_storage_ setCurrentNavigationIndex:4];
+    [session_storage_ setPreviousNavigationIndex:3];
+    [session_storage_ setLastVisitedTimestamp:CFAbsoluteTimeGetCurrent()];
+    // Create an item storage.
+    base::scoped_nsobject<CRWNavigationItemStorage> item_storage(
+        [[CRWNavigationItemStorage alloc] init]);
+    [item_storage setVirtualURL:GURL("http://init.test")];
+    [item_storage setReferrer:web::Referrer(GURL("http://referrer.url"),
+                                            web::ReferrerPolicyDefault)];
+    [item_storage setTimestamp:base::Time::Now()];
+    [item_storage setTitle:base::SysNSStringToUTF16(@"Title")];
+    [item_storage
+        setDisplayState:web::PageDisplayState(0.0, 0.0, 0.0, 0.0, 0.0)];
+    [item_storage
+        setPOSTData:[@"Test data" dataUsingEncoding:NSUTF8StringEncoding]];
+    [item_storage setHTTPRequestHeaders:@{ @"HeaderKey" : @"HeaderValue" }];
+    [session_storage_ setItemStorages:@[ item_storage ]];
+    // Create serializable user data.
+    std::unique_ptr<web::SerializableUserDataImpl> user_data(
+        new web::SerializableUserDataImpl(
+            @{ @"key" : @"value" }));
+    [session_storage_ setSerializableUserData:std::move(user_data)];
+  }
+
+ protected:
+  base::scoped_nsobject<CRWSessionStorage> session_storage_;
+};
+
+// Tests that unarchiving CRWSessionStorage data results in an equivalent
+// storage.
+TEST_F(CRWNSessionStorageTest, EncodeDecode) {
+  NSData* data = [NSKeyedArchiver archivedDataWithRootObject:session_storage_];
+  id decoded = [NSKeyedUnarchiver unarchiveObjectWithData:data];
+  EXPECT_TRUE(SessionStoragesAreEqual(session_storage_, decoded));
+}
diff --git a/ios/web/navigation/navigation_item_impl_list.h b/ios/web/navigation/navigation_item_impl_list.h
index 2aa0598..432f37b9 100644
--- a/ios/web/navigation/navigation_item_impl_list.h
+++ b/ios/web/navigation/navigation_item_impl_list.h
@@ -24,10 +24,6 @@
 ScopedNavigationItemImplList CreateScopedNavigationItemImplList(
     ScopedNavigationItemList scoped_item_list);
 
-// Creates a NavigationItemList from |scoped_item_list|.
-NavigationItemList CreateNavigationItemList(
-    ScopedNavigationItemImplList& scoped_item_list);
-
 }  // namespace web
 
 #endif  // IOS_WEB_NAVIGATION_NAVIGATION_ITEM_IMPL_LIST_H_
diff --git a/ios/web/navigation/navigation_item_impl_list.mm b/ios/web/navigation/navigation_item_impl_list.mm
index 03d4c87..22d58130 100644
--- a/ios/web/navigation/navigation_item_impl_list.mm
+++ b/ios/web/navigation/navigation_item_impl_list.mm
@@ -19,13 +19,4 @@
   return list;
 }
 
-NavigationItemList CreateNavigationItemList(
-    ScopedNavigationItemImplList& scoped_item_list) {
-  NavigationItemList list(scoped_item_list.size());
-  for (size_t index = 0; index < scoped_item_list.size(); ++index) {
-    list[index] = scoped_item_list[index].get();
-  }
-  return list;
-}
-
 }  // namespace web
diff --git a/ios/web/navigation/navigation_item_storage_test_util.h b/ios/web/navigation/navigation_item_storage_test_util.h
new file mode 100644
index 0000000..7c207a29
--- /dev/null
+++ b/ios/web/navigation/navigation_item_storage_test_util.h
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_NAVIGATION_NAVIGATION_ITEM_STORAGE_TEST_UTIL_H_
+#define IOS_WEB_NAVIGATION_NAVIGATION_ITEM_STORAGE_TEST_UTIL_H_
+
+#import <Foundation/Foundation.h>
+
+@class CRWNavigationItemStorage;
+
+namespace web {
+
+// Returns whether |item1| is equivalent to |item2|.
+BOOL ItemStoragesAreEqual(CRWNavigationItemStorage* item1,
+                          CRWNavigationItemStorage* item2);
+}
+
+#endif  // IOS_WEB_NAVIGATION_NAVIGATION_ITEM_STORAGE_TEST_UTIL_H_
diff --git a/ios/web/navigation/navigation_item_storage_test_util.mm b/ios/web/navigation/navigation_item_storage_test_util.mm
new file mode 100644
index 0000000..af2b118
--- /dev/null
+++ b/ios/web/navigation/navigation_item_storage_test_util.mm
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/navigation/navigation_item_storage_test_util.h"
+
+#import "ios/web/public/crw_navigation_item_storage.h"
+
+namespace web {
+
+BOOL ItemStoragesAreEqual(CRWNavigationItemStorage* item1,
+                          CRWNavigationItemStorage* item2) {
+  return item1.virtualURL == item2.virtualURL &&
+         item1.referrer.url == item2.referrer.url &&
+         item1.referrer.policy == item2.referrer.policy &&
+         item1.timestamp == item2.timestamp && item1.title == item2.title &&
+         item1.displayState == item2.displayState &&
+         item1.shouldSkipRepostFormConfirmation ==
+             item2.shouldSkipRepostFormConfirmation &&
+         item1.overridingUserAgent == item2.overridingUserAgent &&
+         [item1.POSTData isEqualToData:item2.POSTData] &&
+         [item1.HTTPRequestHeaders
+             isEqualToDictionary:item2.HTTPRequestHeaders];
+}
+
+}  // namespace web
diff --git a/ios/web/navigation/session_storage_builder.mm b/ios/web/navigation/session_storage_builder.mm
index ba44f37..ca9c3b1 100644
--- a/ios/web/navigation/session_storage_builder.mm
+++ b/ios/web/navigation/session_storage_builder.mm
@@ -59,7 +59,8 @@
   NSMutableArray* item_storages = [[NSMutableArray alloc] init];
   NavigationItemStorageBuilder item_storage_builder;
   for (size_t index = 0; index < session_controller.items.size(); ++index) {
-    web::NavigationItemImpl* item = session_controller.items[index].get();
+    web::NavigationItemImpl* item =
+        static_cast<web::NavigationItemImpl*>(session_controller.items[index]);
     [item_storages addObject:item_storage_builder.BuildStorage(item)];
   }
   serialized_navigation_manager.itemStorages = item_storages;
diff --git a/ios/web/public/crw_session_storage.mm b/ios/web/public/crw_session_storage.mm
index c10d885c..7351a852 100644
--- a/ios/web/public/crw_session_storage.mm
+++ b/ios/web/public/crw_session_storage.mm
@@ -107,7 +107,6 @@
                forKey:kCertificatePolicyManagerKey];
   if (_userData)
     _userData->Encode(coder);
-  // rendererInitiated is deliberately not preserved, as upstream.
 }
 
 @end
diff --git a/ios/web/public/navigation_item_list.h b/ios/web/public/navigation_item_list.h
index ed8a28a..c922a13 100644
--- a/ios/web/public/navigation_item_list.h
+++ b/ios/web/public/navigation_item_list.h
@@ -19,6 +19,11 @@
 // Convenience typedef for a list of scoped NavigationItem pointers.
 typedef std::vector<std::unique_ptr<NavigationItem>> ScopedNavigationItemList;
 
+// Returns a NavigationItemList populated with raw pointer values from
+// |scoped_list|.
+NavigationItemList CreateRawNavigationItemList(
+    const ScopedNavigationItemList& scoped_list);
+
 }  // namespace web
 
 #endif  // IOS_WEB_PUBLIC_NAVIGATION_ITEM_LIST_H_
diff --git a/ios/web/public/navigation_item_list.mm b/ios/web/public/navigation_item_list.mm
new file mode 100644
index 0000000..27a6ca7
--- /dev/null
+++ b/ios/web/public/navigation_item_list.mm
@@ -0,0 +1,17 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/public/navigation_item_list.h"
+
+namespace web {
+
+NavigationItemList CreateRawNavigationItemList(
+    const ScopedNavigationItemList& scoped_list) {
+  NavigationItemList list(scoped_list.size());
+  for (size_t index = 0; index < scoped_list.size(); ++index)
+    list[index] = scoped_list[index].get();
+  return list;
+}
+
+}  // namespace web
diff --git a/ios/web/public/web_state/web_state_observer.h b/ios/web/public/web_state/web_state_observer.h
index f54e88b..6fb99f35 100644
--- a/ios/web/public/web_state/web_state_observer.h
+++ b/ios/web/public/web_state/web_state_observer.h
@@ -58,7 +58,7 @@
   virtual void PageLoaded(PageLoadCompletionStatus load_completion_status) {}
 
   // Called when the interstitial is dismissed by the user.
-  virtual void InsterstitialDismissed() {}
+  virtual void InterstitialDismissed() {}
 
   // Called on URL hash change events.
   virtual void UrlHashChanged() {}
diff --git a/ios/web/public/web_state/web_state_observer_bridge.h b/ios/web/public/web_state/web_state_observer_bridge.h
index bdaf397..9ee95c4 100644
--- a/ios/web/public/web_state/web_state_observer_bridge.h
+++ b/ios/web/public/web_state/web_state_observer_bridge.h
@@ -99,7 +99,7 @@
       const LoadCommittedDetails& load_details) override;
   void PageLoaded(
       web::PageLoadCompletionStatus load_completion_status) override;
-  void InsterstitialDismissed() override;
+  void InterstitialDismissed() override;
   void UrlHashChanged() override;
   void HistoryStateChanged() override;
   void LoadProgressChanged(double progress) override;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index c695bf7..371ef69 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1502,8 +1502,7 @@
 }
 
 - (UIView*)viewForPrinting {
-  // TODO(ios): crbug.com/227944. Printing is not supported for native
-  // controllers.
+  // Printing is not supported for native controllers.
   return _webView;
 }
 
@@ -2154,6 +2153,8 @@
 
   NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
   if (![userDefaults boolForKey:@"PendingIndexNavigationDisabled"]) {
+    [self clearTransientContentView];
+
     BOOL sameDocumentNavigation = [sessionController
         isSameDocumentNavigationBetweenItem:fromEntry.navigationItem
                                     andItem:toEntry.navigationItem];
@@ -2164,14 +2165,6 @@
       [self webWillFinishHistoryNavigationFromEntry:fromEntry];
       [self updateHTML5HistoryState];
     } else {
-      // TODO(crbug.com/691492): After discardNonCommittedItems, the item
-      // pointed by |fromEntry| may not be valid anymore.
-      // Set |fromEntry| to nil to avoid crash whan using the item.
-      // Remove when the fix is not needed anymore.
-      if ([fromEntry isEqual:sessionController.transientEntry] ||
-          [fromEntry isEqual:sessionController.pendingEntry]) {
-        fromEntry = nil;
-      }
       [sessionController discardNonCommittedItems];
       [sessionController setPendingItemIndex:index];
 
@@ -2409,10 +2402,7 @@
 }
 
 - (void)webWillFinishHistoryNavigationFromEntry:(CRWSessionEntry*)fromEntry {
-  // TODO(crbug.com/691492): Removing the DCHECK as |fromEntry| may be nil if
-  // the pending entry was discarded.
-  // Remove when the fix is not needed anymore.
-  // DCHECK(fromEntry);
+  DCHECK(fromEntry);
   [self updateDesktopUserAgentForEntry:self.currentSessionEntry
                              fromEntry:fromEntry];
   [_delegate webWillFinishHistoryNavigationFromEntry:fromEntry];
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 44638df..749b5b6c 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -674,19 +674,19 @@
 typedef web::WebTestWithWebController CRWWebControllerNavigationTest;
 
 // Tests navigation between 2 URLs which differ only by fragment.
-TEST_F(CRWWebControllerNavigationTest, GoToItemWithoutDocumentChange) {
+TEST_F(CRWWebControllerNavigationTest, GoToEntryWithoutDocumentChange) {
   LoadHtml(@"<html><body></body></html>", GURL("https://chromium.test"));
   LoadHtml(@"<html><body></body></html>", GURL("https://chromium.test#hash"));
   NavigationManagerImpl& nav_manager =
       web_controller().webStateImpl->GetNavigationManagerImpl();
   CRWSessionController* session_controller = nav_manager.GetSessionController();
-  EXPECT_EQ(2U, session_controller.items.size());
-  EXPECT_EQ(session_controller.items.back().get(),
-            session_controller.currentItem);
+  EXPECT_EQ(2U, session_controller.entries.count);
+  EXPECT_NSEQ(session_controller.entries.lastObject,
+              session_controller.currentEntry);
 
   [web_controller() goToItemAtIndex:0];
-  EXPECT_EQ(session_controller.items.front().get(),
-            session_controller.currentItem);
+  EXPECT_NSEQ(session_controller.entries.firstObject,
+              session_controller.currentEntry);
 }
 
 // Tests that didShowPasswordInputOnHTTP updates the SSLStatus to indicate that
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 99a3dfb..05fb07a 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -463,7 +463,7 @@
     // Don't access |interstitial| after calling |DontProceed()|, as it triggers
     // deletion.
     for (auto& observer : observers_)
-      observer.InsterstitialDismissed();
+      observer.InterstitialDismissed();
   }
   [web_controller_ clearTransientContentView];
 }
diff --git a/ios/web/web_state/web_state_observer_bridge.mm b/ios/web/web_state/web_state_observer_bridge.mm
index 198ba0d8..13fbde3 100644
--- a/ios/web/web_state/web_state_observer_bridge.mm
+++ b/ios/web/web_state/web_state_observer_bridge.mm
@@ -61,7 +61,7 @@
   }
 }
 
-void WebStateObserverBridge::InsterstitialDismissed() {
+void WebStateObserverBridge::InterstitialDismissed() {
   SEL selector = @selector(webStateDidDismissInterstitial:);
   if ([observer_ respondsToSelector:selector])
     [observer_ webStateDidDismissInterstitial:web_state()];
diff --git a/ios/web/web_state/web_state_observer_bridge_unittest.mm b/ios/web/web_state/web_state_observer_bridge_unittest.mm
index a8dad229..4e20088 100644
--- a/ios/web/web_state/web_state_observer_bridge_unittest.mm
+++ b/ios/web/web_state/web_state_observer_bridge_unittest.mm
@@ -85,8 +85,7 @@
 TEST_F(WebStateObserverBridgeTest, InterstitialDismissed) {
   ASSERT_FALSE([observer_ dismissInterstitialInfo]);
 
-  // TODO(crbug.com/687735): Fix this method name.
-  bridge_->InsterstitialDismissed();
+  bridge_->InterstitialDismissed();
   ASSERT_TRUE([observer_ dismissInterstitialInfo]);
   EXPECT_EQ(&test_web_state_, [observer_ dismissInterstitialInfo]->web_state);
 }
diff --git a/ios/web_view/internal/BUILD.gn b/ios/web_view/internal/BUILD.gn
index 851617b..2fc1eb42 100644
--- a/ios/web_view/internal/BUILD.gn
+++ b/ios/web_view/internal/BUILD.gn
@@ -22,10 +22,10 @@
     "criwv_web_main_delegate.mm",
     "criwv_web_main_parts.h",
     "criwv_web_main_parts.mm",
-    "criwv_web_view.mm",
     "criwv_web_view_configuration.mm",
-    "criwv_website_data_store.mm",
-    "criwv_website_data_store_internal.h",
+    "cwv_web_view.mm",
+    "cwv_website_data_store.mm",
+    "cwv_website_data_store_internal.h",
     "pref_names.cc",
     "pref_names.h",
   ]
diff --git a/ios/web_view/internal/criwv.mm b/ios/web_view/internal/criwv.mm
index bef570e..af4ce4a 100644
--- a/ios/web_view/internal/criwv.mm
+++ b/ios/web_view/internal/criwv.mm
@@ -13,9 +13,9 @@
 #include "ios/web/public/web_thread.h"
 #import "ios/web_view/internal/criwv_web_main_delegate.h"
 #import "ios/web_view/public/criwv_delegate.h"
-#import "ios/web_view/public/criwv_web_view.h"
 #import "ios/web_view/public/criwv_web_view_configuration.h"
-#import "ios/web_view/public/criwv_website_data_store.h"
+#import "ios/web_view/public/cwv_web_view.h"
+#import "ios/web_view/public/cwv_website_data_store.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -47,12 +47,12 @@
   g_criwv = nil;
 }
 
-+ (CRIWVWebView*)webViewWithFrame:(CGRect)frame {
++ (CWVWebView*)webViewWithFrame:(CGRect)frame {
   CRIWVWebViewConfiguration* configuration =
       [[CRIWVWebViewConfiguration alloc] init];
-  configuration.websiteDataStore = [CRIWVWebsiteDataStore defaultDataStore];
+  configuration.websiteDataStore = [CWVWebsiteDataStore defaultDataStore];
 
-  return [[CRIWVWebView alloc] initWithFrame:frame configuration:configuration];
+  return [[CWVWebView alloc] initWithFrame:frame configuration:configuration];
 }
 
 - (instancetype)initWithDelegate:(id<CRIWVDelegate>)delegate {
diff --git a/ios/web_view/internal/criwv_web_view_configuration.mm b/ios/web_view/internal/criwv_web_view_configuration.mm
index 8e9ee21..e70045a 100644
--- a/ios/web_view/internal/criwv_web_view_configuration.mm
+++ b/ios/web_view/internal/criwv_web_view_configuration.mm
@@ -4,7 +4,7 @@
 
 #import "ios/web_view/public/criwv_web_view_configuration.h"
 
-#import "ios/web_view/public/criwv_website_data_store.h"
+#import "ios/web_view/public/cwv_website_data_store.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -12,7 +12,7 @@
 
 @interface CRIWVWebViewConfiguration ()
 // Initialize configuration with specified data store.
-- (instancetype)initWithDataStore:(CRIWVWebsiteDataStore*)dataStore;
+- (instancetype)initWithDataStore:(CWVWebsiteDataStore*)dataStore;
 @end
 
 @implementation CRIWVWebViewConfiguration
@@ -20,10 +20,10 @@
 @synthesize websiteDataStore = _websiteDataStore;
 
 - (instancetype)init {
-  return [self initWithDataStore:[CRIWVWebsiteDataStore defaultDataStore]];
+  return [self initWithDataStore:[CWVWebsiteDataStore defaultDataStore]];
 }
 
-- (instancetype)initWithDataStore:(CRIWVWebsiteDataStore*)dataStore {
+- (instancetype)initWithDataStore:(CWVWebsiteDataStore*)dataStore {
   self = [super init];
   if (self) {
     _websiteDataStore = dataStore;
diff --git a/ios/web_view/internal/criwv_website_data_store_internal.h b/ios/web_view/internal/criwv_website_data_store_internal.h
deleted file mode 100644
index 045b514..0000000
--- a/ios/web_view/internal/criwv_website_data_store_internal.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_VIEW_INTERNAL_CRIWV_WEBSITE_DATA_STORE_INTERNAL_H_
-#define IOS_WEB_VIEW_INTERNAL_CRIWV_WEBSITE_DATA_STORE_INTERNAL_H_
-
-#import "ios/web_view/public/criwv_website_data_store.h"
-
-namespace ios_web_view {
-class CRIWVBrowserState;
-}  // namespace ios_web_view
-
-@interface CRIWVWebsiteDataStore ()
-
-// The browser state associated with this website data store.
-@property(nonatomic, readonly, nonnull)
-    ios_web_view::CRIWVBrowserState* browserState;
-
-@end
-
-#endif  // IOS_WEB_VIEW_INTERNAL_CRIWV_WEBSITE_DATA_STORE_INTERNAL_H_
diff --git a/ios/web_view/internal/criwv_web_view.mm b/ios/web_view/internal/cwv_web_view.mm
similarity index 95%
rename from ios/web_view/internal/criwv_web_view.mm
rename to ios/web_view/internal/cwv_web_view.mm
index df2e9ea..af3ef6c 100644
--- a/ios/web_view/internal/criwv_web_view.mm
+++ b/ios/web_view/internal/cwv_web_view.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/web_view/public/criwv_web_view.h"
+#import "ios/web_view/public/cwv_web_view.h"
 
 #include <memory>
 #include <utility>
@@ -18,11 +18,11 @@
 #import "ios/web/public/web_state/web_state_delegate_bridge.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "ios/web_view/internal/criwv_browser_state.h"
-#import "ios/web_view/internal/criwv_website_data_store_internal.h"
+#import "ios/web_view/internal/cwv_website_data_store_internal.h"
 #import "ios/web_view/internal/translate/criwv_translate_client.h"
 #import "ios/web_view/public/criwv_web_view_configuration.h"
 #import "ios/web_view/public/criwv_web_view_delegate.h"
-#import "ios/web_view/public/criwv_website_data_store.h"
+#import "ios/web_view/public/cwv_website_data_store.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/page_transition_types.h"
 #include "url/gurl.h"
@@ -31,7 +31,7 @@
 #error "This file requires ARC support."
 #endif
 
-@interface CRIWVWebView ()<CRWWebStateDelegate, CRWWebStateObserver> {
+@interface CWVWebView ()<CRWWebStateDelegate, CRWWebStateObserver> {
   CRIWVWebViewConfiguration* _configuration;
   std::unique_ptr<web::WebState> _webState;
   std::unique_ptr<web::WebStateDelegateBridge> _webStateDelegate;
@@ -41,7 +41,7 @@
 
 @end
 
-@implementation CRIWVWebView
+@implementation CWVWebView
 
 @synthesize delegate = _delegate;
 @synthesize loadProgress = _loadProgress;
diff --git a/ios/web_view/internal/criwv_website_data_store.mm b/ios/web_view/internal/cwv_website_data_store.mm
similarity index 78%
rename from ios/web_view/internal/criwv_website_data_store.mm
rename to ios/web_view/internal/cwv_website_data_store.mm
index af9f59f1..520da83 100644
--- a/ios/web_view/internal/criwv_website_data_store.mm
+++ b/ios/web_view/internal/cwv_website_data_store.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/web_view/internal/criwv_website_data_store_internal.h"
+#import "ios/web_view/internal/cwv_website_data_store_internal.h"
 
 #include <memory.h>
 
@@ -13,8 +13,8 @@
 #error "This file requires ARC support."
 #endif
 
-@implementation CRIWVWebsiteDataStore
-// TODO(crbug.com/690182): CRIWVWebsiteDataStore should own _browserState.
+@implementation CWVWebsiteDataStore
+// TODO(crbug.com/690182): CWVWebsiteDataStore should own _browserState.
 ios_web_view::CRIWVBrowserState* _browserState;
 
 - (BOOL)isPersistent {
@@ -31,7 +31,7 @@
 }
 
 + (instancetype)defaultDataStore {
-  CRIWVWebsiteDataStore* dataStore = [[CRIWVWebsiteDataStore alloc] init];
+  CWVWebsiteDataStore* dataStore = [[CWVWebsiteDataStore alloc] init];
 
   ios_web_view::CRIWVWebClient* client =
       static_cast<ios_web_view::CRIWVWebClient*>(web::GetWebClient());
@@ -41,7 +41,7 @@
 }
 
 + (instancetype)nonPersistentDataStore {
-  CRIWVWebsiteDataStore* dataStore = [[CRIWVWebsiteDataStore alloc] init];
+  CWVWebsiteDataStore* dataStore = [[CWVWebsiteDataStore alloc] init];
 
   ios_web_view::CRIWVWebClient* client =
       static_cast<ios_web_view::CRIWVWebClient*>(web::GetWebClient());
diff --git a/ios/web_view/internal/cwv_website_data_store_internal.h b/ios/web_view/internal/cwv_website_data_store_internal.h
new file mode 100644
index 0000000..e826994f
--- /dev/null
+++ b/ios/web_view/internal/cwv_website_data_store_internal.h
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_VIEW_INTERNAL_CWV_WEBSITE_DATA_STORE_INTERNAL_H_
+#define IOS_WEB_VIEW_INTERNAL_CWV_WEBSITE_DATA_STORE_INTERNAL_H_
+
+#import "ios/web_view/public/cwv_website_data_store.h"
+
+namespace ios_web_view {
+class CRIWVBrowserState;
+}  // namespace ios_web_view
+
+@interface CWVWebsiteDataStore ()
+
+// The browser state associated with this website data store.
+@property(nonatomic, readonly, nonnull)
+    ios_web_view::CRIWVBrowserState* browserState;
+
+@end
+
+#endif  // IOS_WEB_VIEW_INTERNAL_CWV_WEBSITE_DATA_STORE_INTERNAL_H_
diff --git a/ios/web_view/public/BUILD.gn b/ios/web_view/public/BUILD.gn
index 33fc8d9..c558402f 100644
--- a/ios/web_view/public/BUILD.gn
+++ b/ios/web_view/public/BUILD.gn
@@ -13,10 +13,10 @@
     "criwv_delegate.h",
     "criwv_translate_delegate.h",
     "criwv_translate_manager.h",
-    "criwv_web_view.h",
     "criwv_web_view_configuration.h",
     "criwv_web_view_delegate.h",
-    "criwv_website_data_store.h",
+    "cwv_web_view.h",
+    "cwv_website_data_store.h",
   ]
 
   libs = [ "UIKit.framework" ]
diff --git a/ios/web_view/public/criwv.h b/ios/web_view/public/criwv.h
index 1f999e9..d5f119e6 100644
--- a/ios/web_view/public/criwv.h
+++ b/ios/web_view/public/criwv.h
@@ -9,7 +9,7 @@
 #import <Foundation/Foundation.h>
 
 @protocol CRIWVDelegate;
-@class CRIWVWebView;
+@class CWVWebView;
 
 // Main interface for the CRIWV library.
 __attribute__((visibility("default")))
@@ -24,7 +24,7 @@
 + (void)shutDown;
 
 // Creates and returns a web view.
-+ (CRIWVWebView*)webViewWithFrame:(CGRect)frame;
++ (CWVWebView*)webViewWithFrame:(CGRect)frame;
 
 @end
 
diff --git a/ios/web_view/public/criwv_web_view_configuration.h b/ios/web_view/public/criwv_web_view_configuration.h
index 54a55b9..d96591e8 100644
--- a/ios/web_view/public/criwv_web_view_configuration.h
+++ b/ios/web_view/public/criwv_web_view_configuration.h
@@ -7,14 +7,14 @@
 
 #import <Foundation/Foundation.h>
 
-@class CRIWVWebsiteDataStore;
+@class CWVWebsiteDataStore;
 
-// Configuration used for creation of a CRIWVWebView.
+// Configuration used for creation of a CWVWebView.
 @interface CRIWVWebViewConfiguration : NSObject<NSCopying>
 
 // Data store defining persistance of website data. Default is
-// [CRIWVWebsiteDataStore defaultDataStore].
-@property(nonatomic, strong, nonnull) CRIWVWebsiteDataStore* websiteDataStore;
+// [CWVWebsiteDataStore defaultDataStore].
+@property(nonatomic, strong, nonnull) CWVWebsiteDataStore* websiteDataStore;
 
 @end
 
diff --git a/ios/web_view/public/criwv_web_view_delegate.h b/ios/web_view/public/criwv_web_view_delegate.h
index 34b2bcd..52d59e20 100644
--- a/ios/web_view/public/criwv_web_view_delegate.h
+++ b/ios/web_view/public/criwv_web_view_delegate.h
@@ -8,7 +8,7 @@
 #import <Foundation/Foundation.h>
 
 @protocol CRIWVTranslateDelegate;
-@class CRIWVWebView;
+@class CWVWebView;
 
 typedef NS_OPTIONS(NSUInteger, CRIWVWebViewUpdateType) {
   CRIWVWebViewUpdateTypeProgress = 1 << 0,
@@ -22,11 +22,11 @@
 
 @optional
 
-- (void)webView:(CRIWVWebView*)webView
+- (void)webView:(CWVWebView*)webView
     didFinishLoadingWithURL:(NSURL*)url
                 loadSuccess:(BOOL)loadSuccess;
 
-- (void)webView:(CRIWVWebView*)webView
+- (void)webView:(CWVWebView*)webView
     didUpdateWithChanges:(CRIWVWebViewUpdateType)changes;
 
 - (id<CRIWVTranslateDelegate>)translateDelegate;
diff --git a/ios/web_view/public/criwv_web_view.h b/ios/web_view/public/cwv_web_view.h
similarity index 92%
rename from ios/web_view/public/criwv_web_view.h
rename to ios/web_view/public/cwv_web_view.h
index 02510d1..be3822d 100644
--- a/ios/web_view/public/criwv_web_view.h
+++ b/ios/web_view/public/cwv_web_view.h
@@ -1,8 +1,8 @@
 // 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 IOS_WEB_VIEW_PUBLIC_CRIWV_WEB_VIEW_H_
-#define IOS_WEB_VIEW_PUBLIC_CRIWV_WEB_VIEW_H_
+#ifndef IOS_WEB_VIEW_PUBLIC_CWV_WEB_VIEW_H_
+#define IOS_WEB_VIEW_PUBLIC_CWV_WEB_VIEW_H_
 
 #import <UIKit/UIKit.h>
 
@@ -16,7 +16,7 @@
 // Customizable Context Menus, and maybe more.
 //
 // Concrete instances can be created through CRIWV.
-@interface CRIWVWebView : UIView
+@interface CWVWebView : UIView
 
 // The view used to display web content.
 @property(nonatomic, readonly) UIView* view;
@@ -71,4 +71,4 @@
 
 @end
 
-#endif  // IOS_WEB_VIEW_PUBLIC_CRIWV_WEB_VIEW_H_
+#endif  // IOS_WEB_VIEW_PUBLIC_CWV_WEB_VIEW_H_
diff --git a/ios/web_view/public/criwv_website_data_store.h b/ios/web_view/public/cwv_website_data_store.h
similarity index 73%
rename from ios/web_view/public/criwv_website_data_store.h
rename to ios/web_view/public/cwv_website_data_store.h
index 7bb06dc..c6359b5 100644
--- a/ios/web_view/public/criwv_website_data_store.h
+++ b/ios/web_view/public/cwv_website_data_store.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_WEB_VIEW_PUBLIC_CRIWV_WEBSITE_DATA_STORE_H_
-#define IOS_WEB_VIEW_PUBLIC_CRIWV_WEBSITE_DATA_STORE_H_
+#ifndef IOS_WEB_VIEW_PUBLIC_CWV_WEBSITE_DATA_STORE_H_
+#define IOS_WEB_VIEW_PUBLIC_CWV_WEBSITE_DATA_STORE_H_
 
 #import <Foundation/Foundation.h>
 
 // Controls persistence of website data such as cookies, caches, and local
 // storage.
-@interface CRIWVWebsiteDataStore : NSObject
+@interface CWVWebsiteDataStore : NSObject
 
 // Whether or not this data store persists data to disk.
 @property(readonly, getter=isPersistent) BOOL persistent;
@@ -21,4 +21,4 @@
 
 @end
 
-#endif  // IOS_WEB_VIEW_PUBLIC_CRIWV_WEBSITE_DATA_STORE_H_
+#endif  // IOS_WEB_VIEW_PUBLIC_CWV_WEBSITE_DATA_STORE_H_
diff --git a/ios/web_view/shell/shell_view_controller.m b/ios/web_view/shell/shell_view_controller.m
index 60c0bba..bc04126 100644
--- a/ios/web_view/shell/shell_view_controller.m
+++ b/ios/web_view/shell/shell_view_controller.m
@@ -5,7 +5,7 @@
 #import "ios/web_view/shell/shell_view_controller.h"
 
 #import "ios/web_view/public/criwv.h"
-#import "ios/web_view/public/criwv_web_view.h"
+#import "ios/web_view/public/cwv_web_view.h"
 #import "ios/web_view/shell/translate_controller.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -20,7 +20,7 @@
 // Toolbar containing navigation buttons and |field|.
 @property(nonatomic, strong) UIToolbar* toolbar;
 // CRIWV view which renders the web page.
-@property(nonatomic, strong) CRIWVWebView* webView;
+@property(nonatomic, strong) CWVWebView* webView;
 // Handles the translation of the content displayed in |webView|.
 @property(nonatomic, strong) TranslateController* translateController;
 
@@ -174,7 +174,7 @@
 
 #pragma mark CRIWVWebViewDelegate methods
 
-- (void)webView:(CRIWVWebView*)webView
+- (void)webView:(CWVWebView*)webView
     didFinishLoadingWithURL:(NSURL*)url
                 loadSuccess:(BOOL)loadSuccess {
   // TODO(crbug.com/679895): Add some visual indication that the page load has
@@ -182,7 +182,7 @@
   [self updateToolbar];
 }
 
-- (void)webView:(CRIWVWebView*)webView
+- (void)webView:(CWVWebView*)webView
     didUpdateWithChanges:(CRIWVWebViewUpdateType)changes {
   if (changes & CRIWVWebViewUpdateTypeProgress) {
     // TODO(crbug.com/679895): Add a progress indicator.
diff --git a/ipc/ipc_channel_nacl.cc b/ipc/ipc_channel_nacl.cc
index 1fa8e69..17b680ed 100644
--- a/ipc/ipc_channel_nacl.cc
+++ b/ipc/ipc_channel_nacl.cc
@@ -207,7 +207,7 @@
                          "ChannelNacl::Send",
                          message->header()->flags,
                          TRACE_EVENT_FLAG_FLOW_OUT);
-  output_queue_.push_back(linked_ptr<Message>(message_ptr.release()));
+  output_queue_.push_back(std::move(message_ptr));
   if (!waiting_connect_)
     return ProcessOutgoingMessages();
 
@@ -220,9 +220,9 @@
   if (pipe_ == -1)
     return;
 
-  linked_ptr<std::vector<char> > data(new std::vector<char>);
+  auto data = base::MakeUnique<std::vector<char>>();
   data->swap(contents->data);
-  read_queue_.push_back(data);
+  read_queue_.push_back(std::move(data));
 
   input_attachments_.reserve(contents->fds.size());
   for (int fd : contents->fds) {
@@ -273,7 +273,7 @@
   // Write out all the messages. The trusted implementation is guaranteed to not
   // block. See NaClIPCAdapter::Send for the implementation of imc_sendmsg.
   while (!output_queue_.empty()) {
-    linked_ptr<Message> msg = output_queue_.front();
+    std::unique_ptr<Message> msg = std::move(output_queue_.front());
     output_queue_.pop_front();
 
     const size_t num_fds = msg->attachment_set()->size();
@@ -330,7 +330,7 @@
   if (read_queue_.empty())
     return READ_PENDING;
   while (!read_queue_.empty() && *bytes_read < buffer_len) {
-    linked_ptr<std::vector<char> > vec(read_queue_.front());
+    std::vector<char>* vec = read_queue_.front().get();
     size_t bytes_to_read = buffer_len - *bytes_read;
     if (vec->size() <= bytes_to_read) {
       // We can read and discard the entire vector.
@@ -386,7 +386,7 @@
     const IPC::ChannelHandle& channel_handle,
     Mode mode,
     Listener* listener) {
-  return base::WrapUnique(new ChannelNacl(channel_handle, mode, listener));
+  return base::MakeUnique<ChannelNacl>(channel_handle, mode, listener);
 }
 
 }  // namespace IPC
diff --git a/ipc/ipc_channel_nacl.h b/ipc/ipc_channel_nacl.h
index 1860922..e989f128 100644
--- a/ipc/ipc_channel_nacl.h
+++ b/ipc/ipc_channel_nacl.h
@@ -10,7 +10,6 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process/process.h"
 #include "base/threading/simple_thread.h"
@@ -97,13 +96,13 @@
   //                 the trouble given that we probably want to implement 1 and
   //                 2 above in NaCl eventually.
   // When ReadData is called, it pulls the bytes out of this queue in order.
-  std::deque<linked_ptr<std::vector<char> > > read_queue_;
+  std::deque<std::unique_ptr<std::vector<char>>> read_queue_;
   // Queue of file descriptor attachments extracted from imc_recvmsg messages.
   std::vector<scoped_refptr<MessageAttachment>> input_attachments_;
 
   // This queue is used when a message is sent prior to Connect having been
   // called. Normally after we're connected, the queue is empty.
-  std::deque<linked_ptr<Message> > output_queue_;
+  std::deque<std::unique_ptr<Message>> output_queue_;
 
   base::WeakPtrFactory<ChannelNacl> weak_ptr_factory_;
 
diff --git a/jingle/notifier/communicator/login.cc b/jingle/notifier/communicator/login.cc
index ce7f85a..14139281 100644
--- a/jingle/notifier/communicator/login.cc
+++ b/jingle/notifier/communicator/login.cc
@@ -16,7 +16,6 @@
 #include "third_party/libjingle_xmpp/xmpp/xmppclient.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppclientsettings.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
-#include "webrtc/base/common.h"
 #include "webrtc/base/firewallsocketserver.h"
 #include "webrtc/base/logging.h"
 #include "webrtc/base/physicalsocketserver.h"
diff --git a/jingle/notifier/communicator/login_settings.cc b/jingle/notifier/communicator/login_settings.cc
index 0c665d10..055febb 100644
--- a/jingle/notifier/communicator/login_settings.cc
+++ b/jingle/notifier/communicator/login_settings.cc
@@ -9,7 +9,6 @@
 #include "base/logging.h"
 #include "jingle/notifier/base/server_information.h"
 #include "net/cert/cert_verifier.h"
-#include "webrtc/base/common.h"
 #include "webrtc/base/socketaddress.h"
 
 namespace notifier {
diff --git a/media/OWNERS b/media/OWNERS
index 683ae0d..ceeec91 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -23,3 +23,5 @@
 per-file *.isolate=maruel@chromium.org
 per-file *.isolate=tandrii@chromium.org
 per-file *.isolate=vadimsh@chromium.org
+
+# COMPONENT: Internals>Media
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 8a67938..5cd4fff 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -215,12 +215,6 @@
     "serial_runner.h",
     "silent_sink_suspender.cc",
     "silent_sink_suspender.h",
-    "simd/convert_rgb_to_yuv.h",
-    "simd/convert_rgb_to_yuv_c.cc",
-    "simd/convert_yuv_to_rgb.h",
-    "simd/convert_yuv_to_rgb_c.cc",
-    "simd/filter_yuv.h",
-    "simd/filter_yuv_c.cc",
     "sinc_resampler.cc",
     "sinc_resampler.h",
     "stream_parser.cc",
@@ -265,8 +259,6 @@
     "video_util.h",
     "wall_clock_time_source.cc",
     "wall_clock_time_source.h",
-    "yuv_convert.cc",
-    "yuv_convert.h",
   ]
 
   allow_circular_includes_from = []
@@ -337,16 +329,6 @@
     defines += [ "DISABLE_USER_INPUT_MONITOR" ]
   }
 
-  if (current_cpu == "x86" || current_cpu == "x64") {
-    sources += [
-      "simd/convert_rgb_to_yuv_sse2.cc",
-      "simd/convert_rgb_to_yuv_ssse3.cc",
-      "simd/convert_yuv_to_rgb_x86.cc",
-      "simd/filter_yuv_sse2.cc",
-    ]
-    deps += [ ":media_yasm" ]
-  }
-
   if (is_linux || is_win) {
     sources += [
       "keyboard_event_counter.cc",
@@ -457,7 +439,6 @@
     "video_frame_unittest.cc",
     "video_util_unittest.cc",
     "wall_clock_time_source_unittest.cc",
-    "yuv_convert_unittest.cc",
   ]
   configs += [
     "//build/config/compiler:no_size_t_to_int_warning",
@@ -473,6 +454,7 @@
     "//skia",
     "//testing/gmock",
     "//testing/gtest",
+    "//third_party/libyuv",
   ]
 
   # Even if FFmpeg is enabled on Android we don't want these.
@@ -491,9 +473,6 @@
     ]
   }
 
-  if (current_cpu == "x86" || current_cpu == "x64") {
-    sources += [ "simd/convert_rgb_to_yuv_unittest.cc" ]
-  }
   if (is_linux || is_win) {
     sources += [ "keyboard_event_counter_unittest.cc" ]
   }
@@ -523,7 +502,6 @@
     "run_all_perftests.cc",
     "sinc_resampler_perftest.cc",
     "vector_math_perftest.cc",
-    "yuv_convert_perftest.cc",
   ]
   configs += [ "//media:media_config" ]
   deps = [
@@ -534,7 +512,6 @@
     "//testing/gmock",
     "//testing/gtest",
     "//testing/perf",
-    "//third_party/libyuv",
   ]
 
   if (media_use_ffmpeg) {
@@ -542,70 +519,6 @@
   }
 }
 
-if (current_cpu == "x86" || current_cpu == "x64") {
-  import("//third_party/yasm/yasm_assemble.gni")
-  yasm_assemble("media_yasm") {
-    sources = [
-      "simd/convert_rgb_to_yuv_ssse3.asm",
-      "simd/convert_yuv_to_rgb_sse.asm",
-      "simd/convert_yuva_to_argb_mmx.asm",
-      "simd/empty_register_state_mmx.asm",
-      "simd/linear_scale_yuv_to_rgb_mmx.asm",
-      "simd/linear_scale_yuv_to_rgb_sse.asm",
-      "simd/scale_yuv_to_rgb_mmx.asm",
-      "simd/scale_yuv_to_rgb_sse.asm",
-    ]
-
-    yasm_flags = [
-      "-DCHROMIUM",
-
-      # In addition to the same path as source asm, let yasm %include
-      # search path be relative to src/ per Chromium policy.
-      "-I",
-      rebase_path("..", root_build_dir),
-    ]
-
-    if (is_component_build) {
-      yasm_flags += [ "-DEXPORT_SYMBOLS" ]
-    }
-
-    inputs = [
-      "//third_party/x86inc/x86inc.asm",
-      "simd/convert_rgb_to_yuv_ssse3.inc",
-      "simd/convert_yuv_to_rgb_mmx.inc",
-      "simd/convert_yuva_to_argb_mmx.inc",
-      "simd/linear_scale_yuv_to_rgb_mmx.inc",
-      "simd/media_export.asm",
-      "simd/scale_yuv_to_rgb_mmx.inc",
-    ]
-
-    if (current_cpu == "x86") {
-      yasm_flags += [ "-DARCH_X86_32" ]
-    } else if (current_cpu == "x64") {
-      yasm_flags += [ "-DARCH_X86_64" ]
-      sources += [
-        "simd/linear_scale_yuv_to_rgb_mmx_x64.asm",
-        "simd/scale_yuv_to_rgb_sse2_x64.asm",
-      ]
-    }
-
-    if (is_mac || is_ios) {
-      yasm_flags += [
-        "-DPREFIX",
-        "-DMACHO",
-      ]
-    } else {
-      if (is_posix) {
-        yasm_flags += [ "-DELF" ]
-        if (current_cpu == "x64") {
-          # TODO(ajwong): Why isn't this true in mac?
-          yasm_flags += [ "-DPIC" ]
-        }
-      }
-    }
-  }
-}
-
 fuzzer_test("media_bit_reader_fuzzer") {
   sources = [
     "bit_reader_fuzzertest.cc",
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn
index 48883cf..db4937f 100644
--- a/media/base/android/BUILD.gn
+++ b/media/base/android/BUILD.gn
@@ -105,6 +105,7 @@
   source_set("unit_tests") {
     testonly = true
     sources = [
+      "media_codec_util_unittest.cc",
       "media_drm_bridge_unittest.cc",
       "media_player_bridge_unittest.cc",
       "media_service_throttler_unittest.cc",
diff --git a/media/base/android/OWNERS b/media/base/android/OWNERS
deleted file mode 100644
index 4a94f86..0000000
--- a/media/base/android/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Preferred reviewers.
-qinmin@chromium.org
diff --git a/media/base/android/media_codec_util.cc b/media/base/android/media_codec_util.cc
index b2d5f82..1949b72 100644
--- a/media/base/android/media_codec_util.cc
+++ b/media/base/android/media_codec_util.cc
@@ -7,12 +7,14 @@
 #include <stddef.h>
 
 #include <algorithm>
+#include <vector>
 
 #include "base/android/build_info.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/logging.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "jni/CodecProfileLevelList_jni.h"
 #include "jni/MediaCodecUtil_jni.h"
@@ -26,6 +28,9 @@
 using base::android::JavaIntArrayToIntVector;
 using base::android::JavaRef;
 using base::android::ScopedJavaLocalRef;
+using base::android::SDK_VERSION_JELLY_BEAN_MR2;
+using base::android::SDK_VERSION_KITKAT;
+using base::android::SDK_VERSION_LOLLIPOP_MR1;
 
 namespace media {
 
@@ -133,26 +138,57 @@
 
 // static
 bool MediaCodecUtil::IsMediaCodecAvailable() {
-  // Blacklist some devices on Jellybean as MediaCodec is buggy.
-  // http://crbug.com/365494, http://crbug.com/615872
-  // Blacklist Lenovo A6600 / A6800 on KitKat, which tends to crash a lot.
-  // See crbug.com/628059 .  We include < K since they don't exist.
-  // Blacklist Samsung Galaxy Star Pro (GT-S7262) (crbug.com/634920).
-  // GT-S5282 and GT-I8552 are for crbug.com/634920 .
-  if (base::android::BuildInfo::GetInstance()->sdk_int() <= 19) {
-    std::string model(base::android::BuildInfo::GetInstance()->model());
-    return model != "GT-I9100" && model != "GT-I9300" && model != "GT-N7000" &&
-           model != "GT-N7100" && model != "A6600" && model != "A6800" &&
-           model != "GT-S7262" && model != "GT-S5282" && model != "GT-I8552";
-  } else if (base::android::BuildInfo::GetInstance()->sdk_int() < 19) {
-    // For JB, these tend to fail often (crbug.com/654905), but not with K+.
-    std::string model(base::android::BuildInfo::GetInstance()->model());
-    return model != "GT-P3113" && model != "GT-P5110" && model != "GT-P5100" &&
-           model != "GT-P5113" && model != "GT-P3110" && model != "GT-N5110" &&
-           model != "e-tab4" && model != "GT-I8200Q";
-  }
+  return IsMediaCodecAvailableFor(
+      base::android::BuildInfo::GetInstance()->sdk_int(),
+      base::android::BuildInfo::GetInstance()->model());
+}
 
-  return true;
+// static
+bool MediaCodecUtil::IsMediaCodecAvailableFor(int sdk, const char* model) {
+  // We will blacklist the model on any sdk that is as old or older than
+  // |last_bad_sdk| for the given model.
+  struct BlacklistEntry {
+    BlacklistEntry(const char* m, int s) : model(m), last_bad_sdk(s) {}
+    base::StringPiece model;
+    int last_bad_sdk;
+    bool operator==(const BlacklistEntry& other) const {
+      // Search on name only.  Ignore |last_bad_sdk|.
+      return model == other.model;
+    }
+  };
+  static const std::vector<BlacklistEntry> blacklist = {
+      // crbug.com/653905
+      {"LGMS330", SDK_VERSION_LOLLIPOP_MR1},
+
+      // crbug.com/615872
+      {"GT-I9100", SDK_VERSION_KITKAT},
+      {"GT-I9300", SDK_VERSION_KITKAT},
+      {"GT-N7000", SDK_VERSION_KITKAT},
+      {"GT-N7100", SDK_VERSION_KITKAT},
+
+      // crbug.com/628509
+      {"A6600", SDK_VERSION_KITKAT},
+      {"A6800", SDK_VERSION_KITKAT},
+
+      // crbug.com/634920
+      {"GT-S7262", SDK_VERSION_KITKAT},
+      {"GT-S5282", SDK_VERSION_KITKAT},
+      {"GT-I8552", SDK_VERSION_KITKAT},
+
+      // crbug.com/365494, crbug.com/615872
+      {"GT-P3113", SDK_VERSION_JELLY_BEAN_MR2},
+      {"GT-P5110", SDK_VERSION_JELLY_BEAN_MR2},
+      {"GT-P5100", SDK_VERSION_JELLY_BEAN_MR2},
+      {"GT-P5113", SDK_VERSION_JELLY_BEAN_MR2},
+      {"GT-P3110", SDK_VERSION_JELLY_BEAN_MR2},
+      {"GT-N5110", SDK_VERSION_JELLY_BEAN_MR2},
+      {"e-tab4", SDK_VERSION_JELLY_BEAN_MR2},
+      {"GT-I8200Q", SDK_VERSION_JELLY_BEAN_MR2},
+  };
+
+  const auto iter =
+      std::find(blacklist.begin(), blacklist.end(), BlacklistEntry(model, 0));
+  return iter == blacklist.end() || sdk > iter->last_bad_sdk;
 }
 
 // static
diff --git a/media/base/android/media_codec_util.h b/media/base/android/media_codec_util.h
index 3bf0e537..43650235 100644
--- a/media/base/android/media_codec_util.h
+++ b/media/base/android/media_codec_util.h
@@ -47,6 +47,13 @@
   // to check IsAvailable() explicitly before calling them.
   static bool IsMediaCodecAvailable();
 
+  // Returns true if MediaCodec is available, with |sdk| as the sdk version and
+  // |model| as the model.  This is provided for unit tests; you probably want
+  // IsMediaCodecAvailable() otherwise.
+  // TODO(liberato): merge this with IsMediaCodecAvailable, and provide a way
+  // to mock BuildInfo instead.
+  static bool IsMediaCodecAvailableFor(int sdk, const char* model);
+
   // Returns true if MediaCodec.setParameters() is available on the device.
   static bool SupportsSetParameters();
 
diff --git a/media/base/android/media_codec_util_unittest.cc b/media/base/android/media_codec_util_unittest.cc
new file mode 100644
index 0000000..879180df
--- /dev/null
+++ b/media/base/android/media_codec_util_unittest.cc
@@ -0,0 +1,76 @@
+// 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 "media/base/android/media_codec_util.h"
+#include "base/android/build_info.h"
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+// These will come from mockable BuildInfo, once it exists.
+using base::android::SDK_VERSION_JELLY_BEAN;
+using base::android::SDK_VERSION_JELLY_BEAN_MR1;
+using base::android::SDK_VERSION_JELLY_BEAN_MR2;
+using base::android::SDK_VERSION_KITKAT;
+using base::android::SDK_VERSION_LOLLIPOP;
+using base::android::SDK_VERSION_LOLLIPOP_MR1;
+using base::android::SDK_VERSION_MARSHMALLOW;
+using base::android::SDK_VERSION_NOUGAT;
+
+class MediaCodecUtilTest : public testing::Test {
+ public:
+  MediaCodecUtilTest() {}
+  ~MediaCodecUtilTest() override {}
+
+ public:
+  DISALLOW_COPY_AND_ASSIGN(MediaCodecUtilTest);
+};
+
+TEST_F(MediaCodecUtilTest, TestCodecAvailableIfNewerVersion) {
+  // Test models that should be available above some sdk level.
+  // We probably don't need to test them all; we're more concerned that the
+  // blacklist code is doing the right thing with the entries it has rather than
+  // the map contents are right.
+  struct {
+    const char* model;
+    int last_bad_sdk;
+  } devices[] = {{"LGMS330", SDK_VERSION_LOLLIPOP_MR1},
+
+                 {"GT-I9100", SDK_VERSION_KITKAT},
+                 {"GT-I9300", SDK_VERSION_KITKAT},
+                 {"GT-N7000", SDK_VERSION_KITKAT},
+                 {"GT-N7100", SDK_VERSION_KITKAT},
+                 {"A6600", SDK_VERSION_KITKAT},
+                 {"A6800", SDK_VERSION_KITKAT},
+                 {"GT-S7262", SDK_VERSION_KITKAT},
+                 {"GT-S5282", SDK_VERSION_KITKAT},
+                 {"GT-I8552", SDK_VERSION_KITKAT},
+
+                 {"GT-P3113", SDK_VERSION_JELLY_BEAN_MR2},
+                 {"GT-P5110", SDK_VERSION_JELLY_BEAN_MR2},
+                 {"GT-P5100", SDK_VERSION_JELLY_BEAN_MR2},
+                 {"GT-P5113", SDK_VERSION_JELLY_BEAN_MR2},
+                 {"GT-P3110", SDK_VERSION_JELLY_BEAN_MR2},
+                 {"GT-N5110", SDK_VERSION_JELLY_BEAN_MR2},
+                 {"e-tab4", SDK_VERSION_JELLY_BEAN_MR2},
+                 {"GT-I8200Q", SDK_VERSION_JELLY_BEAN_MR2},
+
+                 {"always_works", 0},  // Some codec that works everywhere.
+                 {nullptr, 0}};
+
+  for (int sdk = SDK_VERSION_JELLY_BEAN; sdk <= SDK_VERSION_NOUGAT; sdk++) {
+    for (int i = 0; devices[i].model; i++) {
+      bool supported =
+          MediaCodecUtil::IsMediaCodecAvailableFor(sdk, devices[i].model);
+
+      // Make sure that this model is supported if and only if |sdk| is
+      // newer than |last_bad_sdk|.
+      ASSERT_TRUE(supported == (sdk > devices[i].last_bad_sdk))
+          << " model: " << devices[i].model << " sdk: " << sdk;
+    }
+  }
+}
+
+}  // namespace media
diff --git a/media/base/media.cc b/media/base/media.cc
index 01b1d914..77720b4 100644
--- a/media/base/media.cc
+++ b/media/base/media.cc
@@ -9,7 +9,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/trace_event/trace_event.h"
 #include "media/base/media_switches.h"
-#include "media/base/yuv_convert.h"
+#include "third_party/libyuv/include/libyuv.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/build_info.h"
@@ -29,8 +29,7 @@
     TRACE_EVENT_WARMUP_CATEGORY("audio");
     TRACE_EVENT_WARMUP_CATEGORY("media");
 
-    // Perform initialization of libraries which require runtime CPU detection.
-    InitializeCPUSpecificYUVConversions();
+    libyuv::InitCpuFlags();
 
 #if !defined(MEDIA_DISABLE_FFMPEG)
     // Initialize CPU flags outside of the sandbox as this may query /proc for
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index aaf6c6a5..bbaaada 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -57,6 +57,7 @@
   MOCK_METHOD0(OnWaitingForDecryptionKey, void());
   MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
   MOCK_METHOD1(OnVideoOpacityChange, void(bool));
+  MOCK_METHOD0(OnVideoAverageKeyframeDistanceUpdate, void());
 };
 
 class MockPipeline : public Pipeline {
diff --git a/media/base/pipeline.h b/media/base/pipeline.h
index b7e2e1a..cf3c69e 100644
--- a/media/base/pipeline.h
+++ b/media/base/pipeline.h
@@ -62,6 +62,9 @@
 
     // Executed for the first video frame and whenever opacity changes.
     virtual void OnVideoOpacityChange(bool opaque) = 0;
+
+    // Executed when the average keyframe distance for the video changes.
+    virtual void OnVideoAverageKeyframeDistanceUpdate() = 0;
   };
 
   virtual ~Pipeline() {}
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc
index 0ec81f9..61c904e 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -648,10 +648,19 @@
   shared_state_.statistics.audio_memory_usage += stats.audio_memory_usage;
   shared_state_.statistics.video_memory_usage += stats.video_memory_usage;
 
+  base::TimeDelta old_average =
+      shared_state_.statistics.video_keyframe_distance_average;
   if (stats.video_keyframe_distance_average != kNoTimestamp) {
     shared_state_.statistics.video_keyframe_distance_average =
         stats.video_keyframe_distance_average;
   }
+
+  if (shared_state_.statistics.video_keyframe_distance_average != old_average) {
+    main_task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&PipelineImpl::OnVideoAverageKeyframeDistanceUpdate,
+                   weak_pipeline_));
+  }
 }
 
 void PipelineImpl::RendererWrapper::OnBufferingStateChange(
@@ -1324,6 +1333,15 @@
   client_->OnVideoOpacityChange(opaque);
 }
 
+void PipelineImpl::OnVideoAverageKeyframeDistanceUpdate() {
+  DVLOG(2) << __func__;
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(IsRunning());
+
+  DCHECK(client_);
+  client_->OnVideoAverageKeyframeDistanceUpdate();
+}
+
 void PipelineImpl::OnSeekDone() {
   DVLOG(3) << __func__;
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/media/base/pipeline_impl.h b/media/base/pipeline_impl.h
index 0e6d929..b5f5699e 100644
--- a/media/base/pipeline_impl.h
+++ b/media/base/pipeline_impl.h
@@ -135,6 +135,7 @@
   void OnWaitingForDecryptionKey();
   void OnVideoNaturalSizeChange(const gfx::Size& size);
   void OnVideoOpacityChange(bool opaque);
+  void OnVideoAverageKeyframeDistanceUpdate();
 
   // Task completion callbacks from RendererWrapper.
   void OnSeekDone();
diff --git a/media/base/simd/convert_rgb_to_yuv.h b/media/base/simd/convert_rgb_to_yuv.h
deleted file mode 100644
index 0634540..0000000
--- a/media/base/simd/convert_rgb_to_yuv.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_BASE_SIMD_CONVERT_RGB_TO_YUV_H_
-#define MEDIA_BASE_SIMD_CONVERT_RGB_TO_YUV_H_
-
-#include <stdint.h>
-
-#include "media/base/yuv_convert.h"
-
-namespace media {
-
-// These methods are exported for testing purposes only.  Library users should
-// only call the methods listed in yuv_convert.h.
-
-MEDIA_EXPORT void ConvertRGB32ToYUV_SSSE3(const uint8_t* rgbframe,
-                                          uint8_t* yplane,
-                                          uint8_t* uplane,
-                                          uint8_t* vplane,
-                                          int width,
-                                          int height,
-                                          int rgbstride,
-                                          int ystride,
-                                          int uvstride);
-
-MEDIA_EXPORT void ConvertRGB24ToYUV_SSSE3(const uint8_t* rgbframe,
-                                          uint8_t* yplane,
-                                          uint8_t* uplane,
-                                          uint8_t* vplane,
-                                          int width,
-                                          int height,
-                                          int rgbstride,
-                                          int ystride,
-                                          int uvstride);
-
-MEDIA_EXPORT void ConvertRGB32ToYUV_SSE2(const uint8_t* rgbframe,
-                                         uint8_t* yplane,
-                                         uint8_t* uplane,
-                                         uint8_t* vplane,
-                                         int width,
-                                         int height,
-                                         int rgbstride,
-                                         int ystride,
-                                         int uvstride);
-
-MEDIA_EXPORT void ConvertRGB32ToYUV_SSE2_Reference(const uint8_t* rgbframe,
-                                                   uint8_t* yplane,
-                                                   uint8_t* uplane,
-                                                   uint8_t* vplane,
-                                                   int width,
-                                                   int height,
-                                                   int rgbstride,
-                                                   int ystride,
-                                                   int uvstride);
-
-MEDIA_EXPORT void ConvertRGB32ToYUV_C(const uint8_t* rgbframe,
-                                      uint8_t* yplane,
-                                      uint8_t* uplane,
-                                      uint8_t* vplane,
-                                      int width,
-                                      int height,
-                                      int rgbstride,
-                                      int ystride,
-                                      int uvstride);
-
-MEDIA_EXPORT void ConvertRGB24ToYUV_C(const uint8_t* rgbframe,
-                                      uint8_t* yplane,
-                                      uint8_t* uplane,
-                                      uint8_t* vplane,
-                                      int width,
-                                      int height,
-                                      int rgbstride,
-                                      int ystride,
-                                      int uvstride);
-
-}  // namespace media
-
-#endif  // MEDIA_BASE_SIMD_CONVERT_RGB_TO_YUV_H_
diff --git a/media/base/simd/convert_rgb_to_yuv_c.cc b/media/base/simd/convert_rgb_to_yuv_c.cc
deleted file mode 100644
index a43e431..0000000
--- a/media/base/simd/convert_rgb_to_yuv_c.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdint.h>
-
-#include "build/build_config.h"
-#include "media/base/simd/convert_rgb_to_yuv.h"
-
-namespace media {
-
-static int clip_byte(int x) {
-  if (x > 255)
-    return 255;
-  else if (x < 0)
-    return 0;
-  else
-    return x;
-}
-
-void ConvertRGB32ToYUV_C(const uint8_t* rgbframe,
-                         uint8_t* yplane,
-                         uint8_t* uplane,
-                         uint8_t* vplane,
-                         int width,
-                         int height,
-                         int rgbstride,
-                         int ystride,
-                         int uvstride) {
-#if defined(OS_ANDROID)
-  const int r = 0;
-  const int g = 1;
-  const int b = 2;
-#else
-  const int r = 2;
-  const int g = 1;
-  const int b = 0;
-#endif
-
-  for (int i = 0; i < height; ++i) {
-    for (int j = 0; j < width; ++j) {
-      // Since the input pixel format is RGB32, there are 4 bytes per pixel.
-      const uint8_t* pixel = rgbframe + 4 * j;
-      yplane[j] = clip_byte(((pixel[r] * 66 + pixel[g] * 129 +
-                             pixel[b] * 25 + 128) >> 8) + 16);
-      if (i % 2 == 0 && j % 2 == 0) {
-        uplane[j / 2] = clip_byte(((pixel[r] * -38 + pixel[g] * -74 +
-                                   pixel[b] * 112 + 128) >> 8) + 128);
-        vplane[j / 2] = clip_byte(((pixel[r] * 112 + pixel[g] * -94 +
-                                    pixel[b] * -18 + 128) >> 8) + 128);
-      }
-    }
-    rgbframe += rgbstride;
-    yplane += ystride;
-    if (i % 2 == 0) {
-      uplane += uvstride;
-      vplane += uvstride;
-    }
-  }
-}
-
-void ConvertRGB24ToYUV_C(const uint8_t* rgbframe,
-                         uint8_t* yplane,
-                         uint8_t* uplane,
-                         uint8_t* vplane,
-                         int width,
-                         int height,
-                         int rgbstride,
-                         int ystride,
-                         int uvstride) {
-  for (int i = 0; i < height; ++i) {
-    for (int j = 0; j < width; ++j) {
-      // Since the input pixel format is RGB24, there are 3 bytes per pixel.
-      const uint8_t* pixel = rgbframe + 3 * j;
-      yplane[j] = clip_byte(((pixel[2] * 66 + pixel[1] * 129 +
-                              pixel[0] * 25 + 128) >> 8) + 16);
-      if (i % 2 == 0 && j % 2 == 0) {
-        uplane[j / 2] = clip_byte(((pixel[2] * -38 + pixel[1] * -74 +
-                                    pixel[0] * 112 + 128) >> 8) + 128);
-        vplane[j / 2] = clip_byte(((pixel[2] * 112 + pixel[1] * -94 +
-                                    pixel[0] * -18 + 128) >> 8) + 128);
-      }
-    }
-
-    rgbframe += rgbstride;
-    yplane += ystride;
-    if (i % 2 == 0) {
-      uplane += uvstride;
-      vplane += uvstride;
-    }
-  }
-}
-
-}  // namespace media
diff --git a/media/base/simd/convert_rgb_to_yuv_sse2.cc b/media/base/simd/convert_rgb_to_yuv_sse2.cc
deleted file mode 100644
index a8732f9..0000000
--- a/media/base/simd/convert_rgb_to_yuv_sse2.cc
+++ /dev/null
@@ -1,419 +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 <stdint.h>
-
-#include "build/build_config.h"
-#include "media/base/simd/convert_rgb_to_yuv.h"
-
-#if defined(COMPILER_MSVC)
-#include <intrin.h>
-#else
-#include <mmintrin.h>
-#include <emmintrin.h>
-#endif
-
-#if defined(COMPILER_MSVC)
-#define SIMD_ALIGNED(var) __declspec(align(16)) var
-#else
-#define SIMD_ALIGNED(var) var __attribute__((aligned(16)))
-#endif
-
-namespace media {
-
-#define FIX_SHIFT 12
-#define FIX(x) ((x) * (1 << FIX_SHIFT))
-
-// Define a convenient macro to do static cast.
-#define INT16_FIX(x) static_cast<int16_t>(FIX(x))
-
-// Android's pixel layout is RGBA, while other platforms
-// are BGRA.
-#if defined(OS_ANDROID)
-SIMD_ALIGNED(const int16_t ConvertRGBAToYUV_kTable[8 * 3]) = {
-    INT16_FIX(0.257),  INT16_FIX(0.504),  INT16_FIX(0.098),  0,
-    INT16_FIX(0.257),  INT16_FIX(0.504),  INT16_FIX(0.098),  0,
-    -INT16_FIX(0.148), -INT16_FIX(0.291), INT16_FIX(0.439),  0,
-    -INT16_FIX(0.148), -INT16_FIX(0.291), INT16_FIX(0.439),  0,
-    INT16_FIX(0.439),  -INT16_FIX(0.368), -INT16_FIX(0.071), 0,
-    INT16_FIX(0.439),  -INT16_FIX(0.368), -INT16_FIX(0.071), 0,
-};
-#else
-SIMD_ALIGNED(const int16_t ConvertRGBAToYUV_kTable[8 * 3]) = {
-    INT16_FIX(0.098),  INT16_FIX(0.504),  INT16_FIX(0.257),  0,
-    INT16_FIX(0.098),  INT16_FIX(0.504),  INT16_FIX(0.257),  0,
-    INT16_FIX(0.439),  -INT16_FIX(0.291), -INT16_FIX(0.148), 0,
-    INT16_FIX(0.439),  -INT16_FIX(0.291), -INT16_FIX(0.148), 0,
-    -INT16_FIX(0.071), -INT16_FIX(0.368), INT16_FIX(0.439),  0,
-    -INT16_FIX(0.071), -INT16_FIX(0.368), INT16_FIX(0.439),  0,
-};
-#endif
-
-#undef INT16_FIX
-
-// This is the final offset for the conversion from signed yuv values to
-// unsigned values. It is arranged so that offset of 16 is applied to Y
-// components and 128 is added to UV components for 2 pixels.
-SIMD_ALIGNED(const int32_t kYOffset[4]) = {16, 16, 16, 16};
-
-static inline uint8_t Clamp(int value) {
-  if (value < 0)
-    return 0;
-  if (value > 255)
-    return 255;
-  return static_cast<uint8_t>(value);
-}
-
-static inline uint8_t RGBToY(int r, int g, int b) {
-  int y = ConvertRGBAToYUV_kTable[0] * b +
-      ConvertRGBAToYUV_kTable[1] * g +
-      ConvertRGBAToYUV_kTable[2] * r;
-  y >>= FIX_SHIFT;
-  return Clamp(y + 16);
-}
-
-static inline uint8_t RGBToU(int r, int g, int b, int shift) {
-  int u = ConvertRGBAToYUV_kTable[8] * b +
-      ConvertRGBAToYUV_kTable[9] * g +
-      ConvertRGBAToYUV_kTable[10] * r;
-  u >>= FIX_SHIFT + shift;
-  return Clamp(u + 128);
-}
-
-static inline uint8_t RGBToV(int r, int g, int b, int shift) {
-  int v = ConvertRGBAToYUV_kTable[16] * b +
-      ConvertRGBAToYUV_kTable[17] * g +
-      ConvertRGBAToYUV_kTable[18] * r;
-  v >>= FIX_SHIFT + shift;
-  return Clamp(v + 128);
-}
-
-#define CONVERT_Y(rgb_buf, y_buf) \
-  b = *rgb_buf++; \
-  g = *rgb_buf++; \
-  r = *rgb_buf++; \
-  ++rgb_buf;      \
-  sum_b += b;     \
-  sum_g += g;     \
-  sum_r += r;     \
-  *y_buf++ = RGBToY(r, g, b);
-
-static inline void ConvertRGBToYUV_V2H2(const uint8_t* rgb_buf_1,
-                                        const uint8_t* rgb_buf_2,
-                                        uint8_t* y_buf_1,
-                                        uint8_t* y_buf_2,
-                                        uint8_t* u_buf,
-                                        uint8_t* v_buf) {
-  int sum_b = 0;
-  int sum_g = 0;
-  int sum_r = 0;
-  int r, g, b;
-
-
-
-  CONVERT_Y(rgb_buf_1, y_buf_1);
-  CONVERT_Y(rgb_buf_1, y_buf_1);
-  CONVERT_Y(rgb_buf_2, y_buf_2);
-  CONVERT_Y(rgb_buf_2, y_buf_2);
-  *u_buf++ = RGBToU(sum_r, sum_g, sum_b, 2);
-  *v_buf++ = RGBToV(sum_r, sum_g, sum_b, 2);
-}
-
-static inline void ConvertRGBToYUV_V2H1(const uint8_t* rgb_buf_1,
-                                        const uint8_t* rgb_buf_2,
-                                        uint8_t* y_buf_1,
-                                        uint8_t* y_buf_2,
-                                        uint8_t* u_buf,
-                                        uint8_t* v_buf) {
-  int sum_b = 0;
-  int sum_g = 0;
-  int sum_r = 0;
-  int r, g, b;
-
-  CONVERT_Y(rgb_buf_1, y_buf_1);
-  CONVERT_Y(rgb_buf_2, y_buf_2);
-  *u_buf++ = RGBToU(sum_r, sum_g, sum_b, 1);
-  *v_buf++ = RGBToV(sum_r, sum_g, sum_b, 1);
-}
-
-static inline void ConvertRGBToYUV_V1H2(const uint8_t* rgb_buf,
-                                        uint8_t* y_buf,
-                                        uint8_t* u_buf,
-                                        uint8_t* v_buf) {
-  int sum_b = 0;
-  int sum_g = 0;
-  int sum_r = 0;
-  int r, g, b;
-
-  CONVERT_Y(rgb_buf, y_buf);
-  CONVERT_Y(rgb_buf, y_buf);
-  *u_buf++ = RGBToU(sum_r, sum_g, sum_b, 1);
-  *v_buf++ = RGBToV(sum_r, sum_g, sum_b, 1);
-}
-
-static inline void ConvertRGBToYUV_V1H1(const uint8_t* rgb_buf,
-                                        uint8_t* y_buf,
-                                        uint8_t* u_buf,
-                                        uint8_t* v_buf) {
-  int sum_b = 0;
-  int sum_g = 0;
-  int sum_r = 0;
-  int r, g, b;
-
-  CONVERT_Y(rgb_buf, y_buf);
-  *u_buf++ = RGBToU(r, g, b, 0);
-  *v_buf++ = RGBToV(r, g, b, 0);
-}
-
-static void ConvertRGB32ToYUVRow_SSE2(const uint8_t* rgb_buf_1,
-                                      const uint8_t* rgb_buf_2,
-                                      uint8_t* y_buf_1,
-                                      uint8_t* y_buf_2,
-                                      uint8_t* u_buf,
-                                      uint8_t* v_buf,
-                                      int width) {
-  while (width >= 4) {
-    // Name for the Y pixels:
-    // Row 1: a b c d
-    // Row 2: e f g h
-    //
-    // First row 4 pixels.
-    __m128i rgb_row_1 = _mm_loadu_si128(
-        reinterpret_cast<const __m128i*>(rgb_buf_1));
-    __m128i zero_1 = _mm_xor_si128(rgb_row_1, rgb_row_1);
-
-    __m128i y_table = _mm_load_si128(
-        reinterpret_cast<const __m128i*>(ConvertRGBAToYUV_kTable));
-
-    __m128i rgb_a_b = _mm_unpackhi_epi8(rgb_row_1, zero_1);
-    rgb_a_b = _mm_madd_epi16(rgb_a_b, y_table);
-
-    __m128i rgb_c_d = _mm_unpacklo_epi8(rgb_row_1, zero_1);
-    rgb_c_d = _mm_madd_epi16(rgb_c_d, y_table);
-
-    // Do a crazh shuffle so that we get:
-    //  v------------ Multiply Add
-    // BG: a b c d
-    // A0: a b c d
-    __m128i bg_abcd = _mm_castps_si128(
-        _mm_shuffle_ps(
-            _mm_castsi128_ps(rgb_c_d),
-            _mm_castsi128_ps(rgb_a_b),
-            (3 << 6) | (1 << 4) | (3 << 2) | 1));
-    __m128i r_abcd = _mm_castps_si128(
-        _mm_shuffle_ps(
-            _mm_castsi128_ps(rgb_c_d),
-            _mm_castsi128_ps(rgb_a_b),
-            (2 << 6) | (2 << 2)));
-    __m128i y_abcd = _mm_add_epi32(bg_abcd, r_abcd);
-
-    // Down shift back to 8bits range.
-    __m128i y_offset = _mm_load_si128(
-        reinterpret_cast<const __m128i*>(kYOffset));
-    y_abcd = _mm_srai_epi32(y_abcd, FIX_SHIFT);
-    y_abcd = _mm_add_epi32(y_abcd, y_offset);
-    y_abcd = _mm_packs_epi32(y_abcd, y_abcd);
-    y_abcd = _mm_packus_epi16(y_abcd, y_abcd);
-    *reinterpret_cast<uint32_t*>(y_buf_1) = _mm_cvtsi128_si32(y_abcd);
-    y_buf_1 += 4;
-
-    // Second row 4 pixels.
-    __m128i rgb_row_2 = _mm_loadu_si128(
-        reinterpret_cast<const __m128i*>(rgb_buf_2));
-    __m128i zero_2 = _mm_xor_si128(rgb_row_2, rgb_row_2);
-    __m128i rgb_e_f = _mm_unpackhi_epi8(rgb_row_2, zero_2);
-    __m128i rgb_g_h = _mm_unpacklo_epi8(rgb_row_2, zero_2);
-
-    // Add two rows together.
-    __m128i rgb_ae_bf =
-        _mm_add_epi16(_mm_unpackhi_epi8(rgb_row_1, zero_2), rgb_e_f);
-    __m128i rgb_cg_dh =
-        _mm_add_epi16(_mm_unpacklo_epi8(rgb_row_1, zero_2), rgb_g_h);
-
-    // Multiply add like the previous row.
-    rgb_e_f = _mm_madd_epi16(rgb_e_f, y_table);
-    rgb_g_h = _mm_madd_epi16(rgb_g_h, y_table);
-
-    __m128i bg_efgh = _mm_castps_si128(
-        _mm_shuffle_ps(_mm_castsi128_ps(rgb_g_h),
-                       _mm_castsi128_ps(rgb_e_f),
-                       (3 << 6) | (1 << 4) | (3 << 2) | 1));
-    __m128i r_efgh = _mm_castps_si128(
-        _mm_shuffle_ps(_mm_castsi128_ps(rgb_g_h),
-                       _mm_castsi128_ps(rgb_e_f),
-                       (2 << 6) | (2 << 2)));
-    __m128i y_efgh = _mm_add_epi32(bg_efgh, r_efgh);
-    y_efgh = _mm_srai_epi32(y_efgh, FIX_SHIFT);
-    y_efgh = _mm_add_epi32(y_efgh, y_offset);
-    y_efgh = _mm_packs_epi32(y_efgh, y_efgh);
-    y_efgh = _mm_packus_epi16(y_efgh, y_efgh);
-    *reinterpret_cast<uint32_t*>(y_buf_2) = _mm_cvtsi128_si32(y_efgh);
-    y_buf_2 += 4;
-
-    __m128i rgb_ae_cg = _mm_castps_si128(
-        _mm_shuffle_ps(_mm_castsi128_ps(rgb_cg_dh),
-                       _mm_castsi128_ps(rgb_ae_bf),
-                       (3 << 6) | (2 << 4) | (3 << 2) | 2));
-    __m128i rgb_bf_dh = _mm_castps_si128(
-        _mm_shuffle_ps(_mm_castsi128_ps(rgb_cg_dh),
-                       _mm_castsi128_ps(rgb_ae_bf),
-                       (1 << 6) | (1 << 2)));
-
-    // This is a 2x2 subsampling for 2 pixels.
-    __m128i rgb_abef_cdgh = _mm_add_epi16(rgb_ae_cg, rgb_bf_dh);
-
-    // Do a multiply add with U table.
-    __m128i u_a_b = _mm_madd_epi16(
-        rgb_abef_cdgh,
-        _mm_load_si128(
-            reinterpret_cast<const __m128i*>(ConvertRGBAToYUV_kTable + 8)));
-    u_a_b = _mm_add_epi32(_mm_shuffle_epi32(u_a_b, ((3 << 2) | 1)),
-                          _mm_shuffle_epi32(u_a_b, (2 << 2)));
-    // Right shift 14 because of 12 from fixed point and 2 from subsampling.
-    u_a_b = _mm_srai_epi32(u_a_b, FIX_SHIFT + 2);
-    __m128i uv_offset = _mm_slli_epi32(y_offset, 3);
-    u_a_b = _mm_add_epi32(u_a_b, uv_offset);
-    u_a_b = _mm_packs_epi32(u_a_b, u_a_b);
-    u_a_b = _mm_packus_epi16(u_a_b, u_a_b);
-    *reinterpret_cast<uint16_t*>(u_buf) =
-        static_cast<uint16_t>(_mm_extract_epi16(u_a_b, 0));
-    u_buf += 2;
-
-    __m128i v_a_b = _mm_madd_epi16(
-        rgb_abef_cdgh,
-        _mm_load_si128(
-            reinterpret_cast<const __m128i*>(ConvertRGBAToYUV_kTable + 16)));
-    v_a_b = _mm_add_epi32(_mm_shuffle_epi32(v_a_b, ((3 << 2) | 1)),
-                          _mm_shuffle_epi32(v_a_b, (2 << 2)));
-    v_a_b = _mm_srai_epi32(v_a_b, FIX_SHIFT + 2);
-    v_a_b = _mm_add_epi32(v_a_b, uv_offset);
-    v_a_b = _mm_packs_epi32(v_a_b, v_a_b);
-    v_a_b = _mm_packus_epi16(v_a_b, v_a_b);
-    *reinterpret_cast<uint16_t*>(v_buf) =
-        static_cast<uint16_t>(_mm_extract_epi16(v_a_b, 0));
-    v_buf += 2;
-
-    rgb_buf_1 += 16;
-    rgb_buf_2 += 16;
-
-    // Move forward by 4 pixels.
-    width -= 4;
-  }
-
-  // Just use C code to convert the remaining pixels.
-  if (width >= 2) {
-    ConvertRGBToYUV_V2H2(rgb_buf_1, rgb_buf_2, y_buf_1, y_buf_2, u_buf, v_buf);
-    rgb_buf_1 += 8;
-    rgb_buf_2 += 8;
-    y_buf_1 += 2;
-    y_buf_2 += 2;
-    ++u_buf;
-    ++v_buf;
-    width -= 2;
-  }
-
-  if (width)
-    ConvertRGBToYUV_V2H1(rgb_buf_1, rgb_buf_2, y_buf_1, y_buf_2, u_buf, v_buf);
-}
-
-extern void ConvertRGB32ToYUV_SSE2(const uint8_t* rgbframe,
-                                   uint8_t* yplane,
-                                   uint8_t* uplane,
-                                   uint8_t* vplane,
-                                   int width,
-                                   int height,
-                                   int rgbstride,
-                                   int ystride,
-                                   int uvstride) {
-  while (height >= 2) {
-    ConvertRGB32ToYUVRow_SSE2(rgbframe,
-                              rgbframe + rgbstride,
-                              yplane,
-                              yplane + ystride,
-                              uplane,
-                              vplane,
-                              width);
-    rgbframe += 2 * rgbstride;
-    yplane += 2 * ystride;
-    uplane += uvstride;
-    vplane += uvstride;
-    height -= 2;
-  }
-
-  if (!height)
-    return;
-
-  // Handle the last row.
-  while (width >= 2) {
-    ConvertRGBToYUV_V1H2(rgbframe, yplane, uplane, vplane);
-    rgbframe += 8;
-    yplane += 2;
-    ++uplane;
-    ++vplane;
-    width -= 2;
-  }
-
-  if (width)
-    ConvertRGBToYUV_V1H1(rgbframe, yplane, uplane, vplane);
-}
-
-void ConvertRGB32ToYUV_SSE2_Reference(const uint8_t* rgbframe,
-                                      uint8_t* yplane,
-                                      uint8_t* uplane,
-                                      uint8_t* vplane,
-                                      int width,
-                                      int height,
-                                      int rgbstride,
-                                      int ystride,
-                                      int uvstride) {
-  while (height >= 2) {
-    int i = 0;
-
-    // Convert a 2x2 block.
-    while (i + 2 <= width) {
-      ConvertRGBToYUV_V2H2(rgbframe + i * 4,
-                           rgbframe + rgbstride + i * 4,
-                           yplane + i,
-                           yplane + ystride + i,
-                           uplane + i / 2,
-                           vplane + i / 2);
-      i += 2;
-    }
-
-    // Convert the last pixel of two rows.
-    if (i < width) {
-      ConvertRGBToYUV_V2H1(rgbframe + i * 4,
-                           rgbframe + rgbstride + i * 4,
-                           yplane + i,
-                           yplane + ystride + i,
-                           uplane + i / 2,
-                           vplane + i / 2);
-    }
-
-    rgbframe += 2 * rgbstride;
-    yplane += 2 * ystride;
-    uplane += uvstride;
-    vplane += uvstride;
-    height -= 2;
-  }
-
-  if (!height)
-    return;
-
-  // Handle the last row.
-  while (width >= 2) {
-    ConvertRGBToYUV_V1H2(rgbframe, yplane, uplane, vplane);
-    rgbframe += 8;
-    yplane += 2;
-    ++uplane;
-    ++vplane;
-    width -= 2;
-  }
-
-  // Handle the last pixel in the last row.
-  if (width)
-    ConvertRGBToYUV_V1H1(rgbframe, yplane, uplane, vplane);
-}
-
-}  // namespace media
diff --git a/media/base/simd/convert_rgb_to_yuv_ssse3.asm b/media/base/simd/convert_rgb_to_yuv_ssse3.asm
deleted file mode 100644
index 6b86ff2..0000000
--- a/media/base/simd/convert_rgb_to_yuv_ssse3.asm
+++ /dev/null
@@ -1,318 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "media/base/simd/media_export.asm"
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses SSE, SSE2, SSE3, and SSSE3, which are supported by all ATOM
-; processors.
-;
-  SECTION_TEXT
-  CPU       SSE, SSE3, SSE3, SSSE3
-
-;
-; XMM registers representing constants. We must not use these registers as
-; destination operands.
-; for (int i = 0; i < 16; i += 4) {
-;   xmm7.b[i] = 25;  xmm7.b[i+1] = 2;   xmm7.b[i+2] = 66;  xmm7.b[i+3] = 0;
-;   xmm6.b[i] = 0;   xmm6.b[i+1] = 127; xmm6.b[i+2] = 0;   xmm6.b[i+3] = 0;
-;   xmm5.b[i] = 112; xmm5.b[i+1] = -74; xmm5.b[i+2] = -38; xmm5.b[i+3] = 0;
-;   xmm4.b[i] = -18; xmm4.b[i+1] = -94; xmm4.b[i+2] = 112; xmm4.b[i+3] = 0;
-; }
-;
-%define XMM_CONST_Y0    xmm7
-%define XMM_CONST_Y1    xmm6
-%define XMM_CONST_U     xmm5
-%define XMM_CONST_V     xmm4
-%define XMM_CONST_128   xmm3
-
-;
-; LOAD_XMM %1 (xmm), %2 (imm32)
-; Loads an immediate value to an XMM register.
-;   %1.d[0] = %1.d[1] =  %1.d[2] =  %1.d[3] = %2;
-;
-%macro LOAD_XMM 2
-  mov       TEMPd, %2
-  movd      %1, TEMPd
-  pshufd    %1, %1, 00000000B
-%endmacro
-
-;
-; UNPACKRGB %1 (xmm), %2 (imm8)
-; Unpacks one RGB pixel in the specified XMM register.
-;   for (int i = 15; i > %2; --i) %1.b[i] = %1.b[i - 1];
-;   %1.b[%2] = 0;
-;   for (int i = %2 - 1; i >= 0; --i) %1.b[i] = %1.b[i];
-;
-%macro UNPACKRGB 2
-  movdqa    xmm1, %1
-  psrldq    xmm1, %2
-  pslldq    xmm1, %2
-  pxor      %1, xmm1
-  pslldq    xmm1, 1
-  por       %1, xmm1
-%endmacro
-
-;
-; READ_ARGB %1 (xmm), %2 (imm)
-; Read the specified number of ARGB (or RGB) pixels from the source and store
-; them to the destination xmm register. If the input format is RGB, we read RGB
-; pixels and convert them to ARGB pixels. (For this case, the alpha values of
-; the output pixels become 0.)
-;
-%macro READ_ARGB 2
-
-%if PIXELSIZE == 4
-
-  ; Read ARGB pixels from the source. (This macro assumes the input buffer may
-  ; not be aligned to a 16-byte boundary.)
-%if %2 == 1
-  movd      %1, DWORD [ARGBq + WIDTHq * 4 * 2]
-%elif %2 == 2
-  movq      %1, QWORD [ARGBq + WIDTHq * 4 * 2]
-%elif %2 == 4
-  movdqu    %1, DQWORD [ARGBq + WIDTHq * 4 * 2]
-%else
-%error unsupported number of pixels.
-%endif
-
-%elif PIXELSIZE == 3
-
-  ; Read RGB pixels from the source and convert them to ARGB pixels.
-%if %2 == 1
-  ; Read one RGB pixel and convert it to one ARGB pixel.
-  ; Save the WIDTH register to xmm1. (This macro needs to break it.)
-  MOVq      xmm1, WIDTHq
-
-  ; Once read three bytes from the source to TEMPd, and copy it to the
-  ; destination xmm register.
-  lea       WIDTHq, [WIDTHq + WIDTHq * 2]
-  movzx     TEMPd, BYTE [ARGBq + WIDTHq * 2 + 2]
-  shl       TEMPd, 16
-  mov       TEMPw, WORD [ARGBq + WIDTHq * 2]
-  movd      %1, TEMPd
-
-  ; Restore the WIDTH register.
-  MOVq      WIDTHq, xmm1
-%elif %2 == 2
-  ; Read two RGB pixels and convert them to two ARGB pixels.
-  ; Read six bytes from the source to the destination xmm register.
-  mov       TEMPq, WIDTHq
-  lea       TEMPq, [TEMPq + TEMPq * 2]
-  movd      %1, DWORD [ARGBq + TEMPq * 2]
-  pinsrw    %1, WORD [ARGBq + TEMPq * 2 + 4], 3
-
-  ; Fill the alpha values of these RGB pixels with 0 and convert them to two
-  ; ARGB pixels.
-  UNPACKRGB %1, 3
-%elif %2 == 4
-  ; Read four RGB pixels and convert them to four ARGB pixels.
-  ; Read twelve bytes from the source to the destination xmm register.
-  mov       TEMPq, WIDTHq
-  lea       TEMPq, [TEMPq + TEMPq * 2]
-  movq      %1, QWORD [ARGBq + TEMPq * 2]
-  movd      xmm1, DWORD [ARGBq + TEMPq * 2 + 8]
-  shufps    %1, xmm1, 01000100B
-
-  ; Fill the alpha values of these RGB pixels with 0 and convert them to four
-  ; ARGB pixels.
-  UNPACKRGB %1, 3
-  UNPACKRGB %1, 4 + 3
-  UNPACKRGB %1, 4 + 4 + 3
-%else
-%error unsupported number of pixels.
-%endif
-
-%else
-%error unsupported PIXELSIZE value.
-%endif
-
-%endmacro
-
-;
-; CALC_Y %1 (xmm), %2 (xmm)
-; Calculates four Y values from four ARGB pixels stored in %2.
-;   %1.b[0] = ToByte((25 * B(0) + 129 * G(0) + 66 * R(0) + 128) / 256 + 16);
-;   %1.b[1] = ToByte((25 * B(1) + 129 * G(1) + 66 * R(1) + 128) / 256 + 16);
-;   %1.b[2] = ToByte((25 * B(2) + 129 * G(2) + 66 * R(2) + 128) / 256 + 16);
-;   %1.b[3] = ToByte((25 * B(3) + 129 * G(3) + 66 * R(3) + 128) / 256 + 16);
-;
-%macro CALC_Y 2
-  ; To avoid signed saturation, we divide this conversion formula into two
-  ; formulae and store their results into two XMM registers %1 and xmm2.
-  ; %1.w[0]   = 25  * %2.b[0]  + 2   * %2.b[1]  + 66  * %2.b[2]  + 0 * %2.b[3];
-  ; %1.w[1]   = 25  * %2.b[4]  + 2   * %2.b[5]  + 66  * %2.b[6]  + 0 * %2.b[7];
-  ; %1.w[2]   = 25  * %2.b[8]  + 2   * %2.b[9]  + 66  * %2.b[10] + 0 * %2.b[11];
-  ; %1.w[3]   = 25  * %2.b[12] + 2   * %2.b[13] + 66  * %2.b[14] + 0 * %2.b[15];
-  ; xmm2.w[0] = 0   * %2.b[0]  + 127 * %2.b[1]  + 0   * %2.b[2]  + 0 * %2.b[3];
-  ; xmm2.w[1] = 0   * %2.b[4]  + 127 * %2.b[5]  + 0   * %2.b[6]  + 0 * %2.b[7];
-  ; xmm2.w[2] = 0   * %2.b[8]  + 127 * %2.b[9]  + 0   * %2.b[10] + 0 * %2.b[11];
-  ; xmm2.w[3] = 0   * %2.b[12] + 127 * %2.b[13] + 0   * %2.b[14] + 0 * %2.b[15];
-  movdqa    %1, %2
-  pmaddubsw %1, XMM_CONST_Y0
-  phaddsw   %1, %1
-  movdqa    xmm2, %2
-  pmaddubsw xmm2, XMM_CONST_Y1
-  phaddsw   xmm2, xmm2
-
-  ; %1.b[0] = ToByte((%1.w[0] + xmm2.w[0] + 128) / 256 + 16);
-  ; %1.b[1] = ToByte((%1.w[1] + xmm2.w[1] + 128) / 256 + 16);
-  ; %1.b[2] = ToByte((%1.w[2] + xmm2.w[2] + 128) / 256 + 16);
-  ; %1.b[3] = ToByte((%1.w[3] + xmm2.w[3] + 128) / 256 + 16);
-  paddw     %1, xmm2
-  movdqa    xmm2, XMM_CONST_128
-  paddw     %1, xmm2
-  psrlw     %1, 8
-  psrlw     xmm2, 3
-  paddw     %1, xmm2
-  packuswb  %1, %1
-%endmacro
-
-;
-; INIT_UV %1 (r32), %2 (reg) %3 (imm)
-;
-%macro INIT_UV 3
-
-%if SUBSAMPLING == 1 && LINE == 1
-%if %3 == 1 || %3 == 2
-  movzx     %1, BYTE [%2 + WIDTHq]
-%elif %3 == 4
-  movzx     %1, WORD [%2 + WIDTHq]
-%else
-%error unsupported number of pixels.
-%endif
-%endif
-
-%endmacro
-
-;
-; CALC_UV %1 (xmm), %2 (xmm), %3 (xmm), %4 (r32)
-; Calculates two U (or V) values from four ARGB pixels stored in %2.
-; if %3 == XMM_CONST_U
-; if (SUBSAMPLING) {
-;   %1.b[0] = ToByte((112 * B(0) - 74 * G(0) - 38 * R(0) + 128) / 256 + 128);
-;   %1.b[0] = ToByte((112 * B(0) - 74 * G(0) - 38 * R(0) + 128) / 256 + 128);
-;   %1.b[1] = ToByte((112 * B(2) - 74 * G(2) - 38 * R(2) + 128) / 256 + 128);
-;   %1.b[1] = ToByte((112 * B(2) - 74 * G(2) - 38 * R(2) + 128) / 256 + 128);
-; } else {
-;   %1.b[0] = ToByte((112 * B(0) - 74 * G(0) - 38 * R(0) + 128) / 256 + 128);
-;   %1.b[1] = ToByte((112 * B(2) - 74 * G(2) - 38 * R(2) + 128) / 256 + 128);
-; }
-; if %3 == XMM_CONST_V
-;   %1.b[0] = ToByte((-18 * B(0) - 94 * G(0) + 112 * R(0) + 128) / 256 + 128);
-;   %1.b[1] = ToByte((-18 * B(2) - 94 * G(2) + 112 * R(2) + 128) / 256 + 128);
-;
-%macro CALC_UV 4
-  ; for (int i = 0; i < 4; ++i) {
-  ;   %1.w[i] = 0;
-  ;   for (int j = 0; j < 4; ++j)
-  ;     %1.w[i] += %3.b[i * 4 + j] + %2.b[i * 4 + j];
-  ; }
-  movdqa    %1, %2
-  pmaddubsw %1, %3
-  phaddsw   %1, %1
-
-%if SUBSAMPLING == 1
-  ; %1.w[0] = (%1.w[0] + %1.w[1] + 1) / 2;
-  ; %1.w[1] = (%1.w[1] + %1.w[0] + 1) / 2;
-  ; %1.w[2] = (%1.w[2] + %1.w[3] + 1) / 2;
-  ; %1.w[3] = (%1.w[3] + %1.w[2] + 1) / 2;
-  pshuflw   xmm2, %1, 10110001B
-  pavgw     %1, xmm2
-%endif
-
-  ; %1.b[0] = ToByte((%1.w[0] + 128) / 256 + 128);
-  ; %1.b[1] = ToByte((%1.w[2] + 128) / 256 + 128);
-  pshuflw   %1, %1, 10001000B
-  paddw     %1, XMM_CONST_128
-  psraw     %1, 8
-  paddw     %1, XMM_CONST_128
-  packuswb  %1, %1
-
-%if SUBSAMPLING == 1 && LINE == 1
-  ; %1.b[0] = (%1.b[0] + %3.b[0] + 1) / 2;
-  ; %1.b[1] = (%1.b[1] + %3.b[1] + 1) / 2;
-  movd      xmm2, %4
-  pavgb     %1, xmm2
-%endif
-%endmacro
-
-;
-; extern "C" void ConvertARGBToYUVRow_SSSE3(const uint8_t* argb,
-;                                           uint8_t* y,
-;                                           uint8_t* u,
-;                                           uint8_t* v,
-;                                           ptrdiff_t width);
-;
-%define SYMBOL          ConvertARGBToYUVRow_SSSE3
-%define PIXELSIZE       4
-%define SUBSAMPLING     0
-%define LINE            0
-%include "convert_rgb_to_yuv_ssse3.inc"
-
-;
-; extern "C" void ConvertRGBToYUVRow_SSSE3(const uint8_t* rgb,
-;                                          uint8_t* y,
-;                                          uint8_t* u,
-;                                          uint8_t* v,
-;                                          ptrdiff_t width);
-;
-%define SYMBOL          ConvertRGBToYUVRow_SSSE3
-%define PIXELSIZE       3
-%define SUBSAMPLING     0
-%define LINE            0
-%include "convert_rgb_to_yuv_ssse3.inc"
-
-;
-; extern "C" void ConvertARGBToYUVEven_SSSE3(const uint8_t* argb,
-;                                            uint8_t* y,
-;                                            uint8_t* u,
-;                                            uint8_t* v,
-;                                            ptrdiff_t width);
-;
-%define SYMBOL          ConvertARGBToYUVEven_SSSE3
-%define PIXELSIZE       4
-%define SUBSAMPLING     1
-%define LINE            0
-%include "convert_rgb_to_yuv_ssse3.inc"
-
-;
-; extern "C" void ConvertARGBToYUVOdd_SSSE3(const uint8_t* argb,
-;                                           uint8_t* y,
-;                                           uint8_t* u,
-;                                           uint8_t* v,
-;                                           ptrdiff_t width);
-;
-%define SYMBOL          ConvertARGBToYUVOdd_SSSE3
-%define PIXELSIZE       4
-%define SUBSAMPLING     1
-%define LINE            1
-%include "convert_rgb_to_yuv_ssse3.inc"
-
-;
-; extern "C" void ConvertRGBToYUVEven_SSSE3(const uint8_t* rgb,
-;                                           uint8_t* y,
-;                                           uint8_t* u,
-;                                           uint8_t* v,
-;                                           ptrdiff_t width);
-;
-%define SYMBOL          ConvertRGBToYUVEven_SSSE3
-%define PIXELSIZE       3
-%define SUBSAMPLING     1
-%define LINE            0
-%include "convert_rgb_to_yuv_ssse3.inc"
-
-;
-; extern "C" void ConvertRGBToYUVOdd_SSSE3(const uint8_t* rgb,
-;                                          uint8_t* y,
-;                                          uint8_t* u,
-;                                          uint8_t* v,
-;                                          ptrdiff_t width);
-;
-%define SYMBOL          ConvertRGBToYUVOdd_SSSE3
-%define PIXELSIZE       3
-%define SUBSAMPLING     1
-%define LINE            1
-%include "convert_rgb_to_yuv_ssse3.inc"
diff --git a/media/base/simd/convert_rgb_to_yuv_ssse3.cc b/media/base/simd/convert_rgb_to_yuv_ssse3.cc
deleted file mode 100644
index 2ab2b989..0000000
--- a/media/base/simd/convert_rgb_to_yuv_ssse3.cc
+++ /dev/null
@@ -1,64 +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 "media/base/simd/convert_rgb_to_yuv.h"
-
-#include "build/build_config.h"
-#include "media/base/simd/convert_rgb_to_yuv_ssse3.h"
-
-namespace media {
-
-void ConvertRGB32ToYUV_SSSE3(const uint8_t* rgbframe,
-                             uint8_t* yplane,
-                             uint8_t* uplane,
-                             uint8_t* vplane,
-                             int width,
-                             int height,
-                             int rgbstride,
-                             int ystride,
-                             int uvstride) {
-  for (; height >= 2; height -= 2) {
-    ConvertARGBToYUVRow_SSSE3(rgbframe, yplane, uplane, vplane, width);
-    rgbframe += rgbstride;
-    yplane += ystride;
-
-    ConvertARGBToYUVRow_SSSE3(rgbframe, yplane, NULL, NULL, width);
-    rgbframe += rgbstride;
-    yplane += ystride;
-
-    uplane += uvstride;
-    vplane += uvstride;
-  }
-
-  if (height)
-    ConvertARGBToYUVRow_SSSE3(rgbframe, yplane, uplane, vplane, width);
-}
-
-void ConvertRGB24ToYUV_SSSE3(const uint8_t* rgbframe,
-                             uint8_t* yplane,
-                             uint8_t* uplane,
-                             uint8_t* vplane,
-                             int width,
-                             int height,
-                             int rgbstride,
-                             int ystride,
-                             int uvstride) {
-  for (; height >= 2; height -= 2) {
-    ConvertRGBToYUVRow_SSSE3(rgbframe, yplane, uplane, vplane, width);
-    rgbframe += rgbstride;
-    yplane += ystride;
-
-    ConvertRGBToYUVRow_SSSE3(rgbframe, yplane, NULL, NULL, width);
-    rgbframe += rgbstride;
-    yplane += ystride;
-
-    uplane += uvstride;
-    vplane += uvstride;
-  }
-
-  if (height)
-    ConvertRGBToYUVRow_SSSE3(rgbframe, yplane, uplane, vplane, width);
-}
-
-}  // namespace media
diff --git a/media/base/simd/convert_rgb_to_yuv_ssse3.h b/media/base/simd/convert_rgb_to_yuv_ssse3.h
deleted file mode 100644
index 19ece73..0000000
--- a/media/base/simd/convert_rgb_to_yuv_ssse3.h
+++ /dev/null
@@ -1,43 +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 MEDIA_BASE_SIMD_CONVERT_RGB_TO_YUV_SSSE3_H_
-#define MEDIA_BASE_SIMD_CONVERT_RGB_TO_YUV_SSSE3_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// The header file for ASM functions that convert a row of RGB pixels with SSSE3
-// instructions so we can call them from C++ code. These functions are
-// implemented in "convert_rgb_to_yuv_ssse3.asm".
-
-// We use ptrdiff_t instead of int for yasm routine parameters to portably
-// sign-extend int. On Win64, MSVC does not sign-extend the value in the stack
-// home of int function parameters, and yasm routines are unaware of this lack
-// of extension and fault.  ptrdiff_t is portably sign-extended and fixes this
-// issue on at least Win64.
-
-// Convert a row of 24-bit RGB pixels to YV12 pixels.
-void ConvertRGBToYUVRow_SSSE3(const uint8_t* rgb,
-                              uint8_t* y,
-                              uint8_t* u,
-                              uint8_t* v,
-                              ptrdiff_t width);
-
-// Convert a row of 32-bit RGB pixels to YV12 pixels.
-void ConvertARGBToYUVRow_SSSE3(const uint8_t* argb,
-                               uint8_t* y,
-                               uint8_t* u,
-                               uint8_t* v,
-                               ptrdiff_t width);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif  // MEDIA_BASE_SIMD_CONVERT_RGB_TO_YUV_SSSE3_H_
diff --git a/media/base/simd/convert_rgb_to_yuv_ssse3.inc b/media/base/simd/convert_rgb_to_yuv_ssse3.inc
deleted file mode 100644
index 5217c69b..0000000
--- a/media/base/simd/convert_rgb_to_yuv_ssse3.inc
+++ /dev/null
@@ -1,200 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-;
-; void SYMBOL(const uint8_t* argb, uint8_t* y, uint8_t* u, uint8_t* v, int width);
-;
-; The main code that converts RGB pixels to YUV pixels. This function roughly
-; consists of three parts: converting one ARGB pixel to YUV pixels, converting
-; two ARGB pixels to YUV pixels, and converting four ARGB pixels to YUV pixels.
-; To write the structure of this function in C, it becomes the snippet listed
-; below.
-;
-;   if (width & 1) {
-;     --width;
-;     // Convert one ARGB pixel to one Y pixel, one U pixel, and one V pixel.
-;   }
-;
-;   if (width & 2) {
-;     width -= 2;
-;     // Convert two ARGB pixels to two Y pixels, one U pixel, and one V pixel.
-;   }
-;
-;   while (width) {
-;     width -= 4;
-;     // Convert four ARGB pixels to four Y pixels, two U pixels, and two V
-;     // pixels.
-;   }
-;
-  EXPORT    SYMBOL
-  align     function_align
-
-mangle(SYMBOL):
-  %assign stack_offset 0
-  PROLOGUE 5, 6, 8, ARGB, Y, U, V, WIDTH, TEMP
-
-  ; Initialize constants used in this function. (We use immediates to avoid
-  ; dependency onto GOT.)
-  LOAD_XMM  XMM_CONST_Y0, 0x00420219
-  LOAD_XMM  XMM_CONST_Y1, 0x00007F00
-  LOAD_XMM  XMM_CONST_U, 0x00DAB670
-  LOAD_XMM  XMM_CONST_V, 0x0070A2EE
-  LOAD_XMM  XMM_CONST_128, 0x00800080
-
-.convert_one_pixel:
-  ; Divide the input width by two so it represents the offsets for u[] and v[].
-  ; When the width is odd, We read the rightmost ARGB pixel and convert its
-  ; colorspace to YUV. This code stores one Y pixel, one U pixel, and one V
-  ; pixel.
-  sar       WIDTHq, 1
-  jnc       .convert_two_pixels
-
-  ; Read one ARGB (or RGB) pixel.
-  READ_ARGB xmm0, 1
-
-  ; Calculate y[0] from one RGB pixel read above.
-  CALC_Y    xmm1, xmm0
-  movd      TEMPd, xmm1
-  mov       BYTE [Yq + WIDTHq * 2], TEMPb
-
-  ; Calculate u[0] from one RGB pixel read above. If this is an odd line, the
-  ; output pixel contains the U value calculated in the previous call. We also
-  ; read this pixel and calculate their average.
-  INIT_UV   TEMPd, Uq, 4
-  CALC_UV   xmm1, xmm0, XMM_CONST_U, TEMPd
-  movd      TEMPd, xmm1
-  mov       BYTE [Uq + WIDTHq], TEMPb
-
-  ; Calculate v[0] from one RGB pixel. Same as u[0], we read the result of the
-  ; previous call and get their average.
-  INIT_UV   TEMPd, Uq, 4
-  CALC_UV   xmm1, xmm0, XMM_CONST_V, TEMPd
-  movd      TEMPd, xmm1
-  mov       BYTE [Vq + WIDTHq], TEMPb
-
-.convert_two_pixels:
-  ; If the input width is not a multiple of four, read the rightmost two ARGB
-  ; pixels and convert their colorspace to YUV. This code stores two Y pixels,
-  ; one U pixel, and one V pixel.
-  test      WIDTHb, 2 / 2
-  jz        .convert_four_pixels
-  sub       WIDTHb, 2 / 2
-
-  ; Read two ARGB (or RGB) pixels.
-  READ_ARGB xmm0, 2
-
-  ; Calculate r[0] and r[1] from two RGB pixels read above.
-  CALC_Y    xmm1, xmm0
-  movd      TEMPd, xmm1
-  mov       WORD [Yq + WIDTHq * 2], TEMPw
-
-  ; Skip calculating u and v if the output buffer is NULL.
-  test      Uq, Uq
-  jz        .convert_four_pixels
-
-  ; Calculate u[0] from two RGB pixels read above. (For details, read the above
-  ; comment in .convert_one_pixel).
-  INIT_UV   TEMPd, Uq, 2
-  CALC_UV   xmm1, xmm0, XMM_CONST_U, TEMPd
-  movd      TEMPd, xmm1
-  mov       BYTE [Uq + WIDTHq], TEMPb
-
-  ; Calculate v[0] from two RGB pixels read above.
-  INIT_UV   TEMPd, Vq, 2
-  CALC_UV   xmm1, xmm0, XMM_CONST_V, TEMPd
-  movd      TEMPd, xmm1
-  mov       BYTE [Vq + WIDTHq], TEMPb
-
-.convert_four_pixels:
-  ; Read four ARGB pixels and convert their colorspace to YUV. This code stores
-  ; four Y pixels, two U pixels, and two V pixels.
-  test      WIDTHq, WIDTHq
-  jz        .convert_finish
-
-%if PIXELSIZE == 4
-  ; Check if the input buffer is aligned to a 16-byte boundary and use movdqa
-  ; for reading the ARGB pixels.
-  test      ARGBw, 15
-  jnz       .convert_four_pixels_unaligned
-
-.convert_four_pixels_aligned:
-  sub       WIDTHq, 4 / 2
-
-  ; Read four ARGB pixels. (We can use movdqa here since we have checked if the
-  ; source address is aligned.)
-  movdqa    xmm0, DQWORD [ARGBq + WIDTHq * 4 * 2]
-
-  ; Calculate y[0], y[1], y[2],and, y[3] from the input ARGB pixels.
-  CALC_Y    xmm1, xmm0
-  movd      DWORD [Yq + WIDTHq * 2], xmm1
-
-%if SUBSAMPLING == 0
-  ; Skip calculating u and v if the output buffer is NULL, which means we are
-  ; converting an odd line. (When we enable subsampling, these buffers must
-  ; contain the u and v values for the previous call, i.e. these variables must
-  ; not be NULL.)
-  test      Uq, Uq
-  jz        .convert_four_pixels_aligned_next
-%endif
-
-  ; Calculate u[0] and u[1] from four ARGB pixels read above.
-  INIT_UV   TEMPd, Uq, 4
-  CALC_UV   xmm1, xmm0, XMM_CONST_U, TEMPd
-  movd      TEMPd, xmm1
-  mov       WORD [Uq + WIDTHq], TEMPw
-
-  ; Calculate v[0] and v[1] from four ARGB pixels read above.
-  INIT_UV   TEMPd, Vq, 4
-  CALC_UV   xmm1, xmm0, XMM_CONST_V, TEMPd
-  movd      TEMPd, xmm1
-  mov       WORD [Vq + WIDTHq], TEMPw
-
-%if SUBSAMPLING == 0
-.convert_four_pixels_aligned_next:
-%endif
-
-  test      WIDTHq, WIDTHq
-  jnz       .convert_four_pixels_aligned
-
-  jmp       .convert_finish
-%endif
-
-.convert_four_pixels_unaligned:
-  sub       WIDTHq, 4 / 2
-
-  ; Read four ARGB (or RGB) pixels.
-  READ_ARGB xmm0, 4
-
-  ; Calculate y[0], y[1], y[2],and, y[3] from the input ARGB pixels.
-  CALC_Y    xmm1, xmm0
-  movd      DWORD [Yq + WIDTHq * 2], xmm1
-
-%if SUBSAMPLING == 0
-  ; Skip calculating u and v if the output buffer is NULL.
-  test      Uq, Uq
-  jz        .convert_four_pixels_unaligned_next
-%endif
-
-  ; Calculate u[0] and u[1] from the input ARGB pixels.
-  INIT_UV   TEMPd, Uq, 4
-  CALC_UV   xmm1, xmm0, XMM_CONST_U, TEMPd
-  movd      TEMPd, xmm1
-  mov       WORD [Uq + WIDTHq], TEMPw
-
-  ; Calculate v[0] and v[1] from the input ARGB pixels.
-  INIT_UV   TEMPd, Vq, 4
-  CALC_UV   xmm1, xmm0, XMM_CONST_V, TEMPd
-  movd      TEMPd, xmm1
-  mov       WORD [Vq + WIDTHq], TEMPw
-
-%if SUBSAMPLING == 0
-.convert_four_pixels_unaligned_next:
-%endif
-
-  test      WIDTHq, WIDTHq
-  jnz       .convert_four_pixels_unaligned
-
-.convert_finish:
-  ; Just exit this function since this is a void function.
-  RET
diff --git a/media/base/simd/convert_rgb_to_yuv_unittest.cc b/media/base/simd/convert_rgb_to_yuv_unittest.cc
deleted file mode 100644
index d10de30b..0000000
--- a/media/base/simd/convert_rgb_to_yuv_unittest.cc
+++ /dev/null
@@ -1,118 +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 "media/base/simd/convert_rgb_to_yuv.h"
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/cpu.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace {
-
-// Reference code that converts RGB pixels to YUV pixels.
-int ConvertRGBToY(const uint8_t* rgb) {
-  int y = 25 * rgb[0] + 129 * rgb[1] + 66 * rgb[2];
-  y = ((y + 128) >> 8) + 16;
-  return std::max(0, std::min(255, y));
-}
-
-int ConvertRGBToU(const uint8_t* rgb, int size) {
-  int u = 112 * rgb[0] - 74 * rgb[1] - 38 * rgb[2];
-  u = ((u + 128) >> 8) + 128;
-  return std::max(0, std::min(255, u));
-}
-
-int ConvertRGBToV(const uint8_t* rgb, int size) {
-  int v = -18 * rgb[0] - 94 * rgb[1] + 112 * rgb[2];
-  v = ((v + 128) >> 8) + 128;
-  return std::max(0, std::min(255, v));
-}
-
-}  // namespace
-
-// Assembly code confuses MemorySanitizer. Do not run it in MSan builds.
-#if defined(MEMORY_SANITIZER)
-#define MAYBE_SideBySideRGB DISABLED_SideBySideRGB
-#else
-#define MAYBE_SideBySideRGB SideBySideRGB
-#endif
-
-// A side-by-side test that verifies our ASM functions that convert RGB pixels
-// to YUV pixels can output the expected results. This test converts RGB pixels
-// to YUV pixels with our ASM functions (which use SSE, SSE2, SSE3, and SSSE3)
-// and compare the output YUV pixels with the ones calculated with out reference
-// functions implemented in C++.
-TEST(YUVConvertTest, MAYBE_SideBySideRGB) {
-  // We skip this test on PCs which does not support SSE3 because this test
-  // needs it.
-  base::CPU cpu;
-  if (!cpu.has_ssse3())
-    return;
-
-  // This test checks a subset of all RGB values so this test does not take so
-  // long time.
-  const int kStep = 8;
-  const int kWidth = 256 / kStep;
-
-  for (int size = 3; size <= 4; ++size) {
-    // Create the output buffers.
-    std::unique_ptr<uint8_t[]> rgb(new uint8_t[kWidth * size]);
-    std::unique_ptr<uint8_t[]> y(new uint8_t[kWidth]);
-    std::unique_ptr<uint8_t[]> u(new uint8_t[kWidth / 2]);
-    std::unique_ptr<uint8_t[]> v(new uint8_t[kWidth / 2]);
-
-    // Choose the function that converts from RGB pixels to YUV ones.
-    void (*convert)(const uint8_t*, uint8_t*, uint8_t*, uint8_t*, int, int, int,
-                    int, int) = NULL;
-    if (size == 3)
-      convert = media::ConvertRGB24ToYUV_SSSE3;
-    else
-      convert = media::ConvertRGB32ToYUV_SSSE3;
-
-    int total_error = 0;
-    for (int r = 0; r < kWidth; ++r) {
-      for (int g = 0; g < kWidth; ++g) {
-
-        // Fill the input pixels.
-        for (int b = 0; b < kWidth; ++b) {
-          rgb[b * size + 0] = b * kStep;
-          rgb[b * size + 1] = g * kStep;
-          rgb[b * size + 2] = r * kStep;
-          if (size == 4)
-            rgb[b * size + 3] = 255;
-        }
-
-        // Convert the input RGB pixels to YUV ones.
-        convert(rgb.get(), y.get(), u.get(), v.get(), kWidth, 1, kWidth * size,
-                kWidth, kWidth / 2);
-
-        // Check the output Y pixels.
-        for (int i = 0; i < kWidth; ++i) {
-          const uint8_t* p = &rgb[i * size];
-          int error = ConvertRGBToY(p) - y[i];
-          total_error += error > 0 ? error : -error;
-        }
-
-        // Check the output U pixels.
-        for (int i = 0; i < kWidth / 2; ++i) {
-          const uint8_t* p = &rgb[i * 2 * size];
-          int error = ConvertRGBToU(p, size) - u[i];
-          total_error += error > 0 ? error : -error;
-        }
-
-        // Check the output V pixels.
-        for (int i = 0; i < kWidth / 2; ++i) {
-          const uint8_t* p = &rgb[i * 2 * size];
-          int error = ConvertRGBToV(p, size) - v[i];
-          total_error += error > 0 ? error : -error;
-        }
-      }
-    }
-
-    EXPECT_EQ(0, total_error);
-  }
-}
diff --git a/media/base/simd/convert_yuv_to_rgb.h b/media/base/simd/convert_yuv_to_rgb.h
deleted file mode 100644
index a421ff56..0000000
--- a/media/base/simd/convert_yuv_to_rgb.h
+++ /dev/null
@@ -1,169 +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 MEDIA_BASE_SIMD_CONVERT_YUV_TO_RGB_H_
-#define MEDIA_BASE_SIMD_CONVERT_YUV_TO_RGB_H_
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "media/base/yuv_convert.h"
-
-namespace media {
-
-// These methods are exported for testing purposes only.  Library users should
-// only call the methods listed in yuv_convert.h.
-
-MEDIA_EXPORT void ConvertYUVToRGB32_C(const uint8_t* yplane,
-                                      const uint8_t* uplane,
-                                      const uint8_t* vplane,
-                                      uint8_t* rgbframe,
-                                      int width,
-                                      int height,
-                                      int ystride,
-                                      int uvstride,
-                                      int rgbstride,
-                                      YUVType yuv_type);
-
-MEDIA_EXPORT void ConvertYUVToRGB32Row_C(const uint8_t* yplane,
-                                         const uint8_t* uplane,
-                                         const uint8_t* vplane,
-                                         uint8_t* rgbframe,
-                                         ptrdiff_t width,
-                                         const int16_t* convert_table);
-
-MEDIA_EXPORT void ConvertYUVAToARGB_C(const uint8_t* yplane,
-                                      const uint8_t* uplane,
-                                      const uint8_t* vplane,
-                                      const uint8_t* aplane,
-                                      uint8_t* rgbframe,
-                                      int width,
-                                      int height,
-                                      int ystride,
-                                      int uvstride,
-                                      int avstride,
-                                      int rgbstride,
-                                      YUVType yuv_type);
-
-MEDIA_EXPORT void ConvertYUVAToARGBRow_C(const uint8_t* yplane,
-                                         const uint8_t* uplane,
-                                         const uint8_t* vplane,
-                                         const uint8_t* aplane,
-                                         uint8_t* rgbframe,
-                                         ptrdiff_t width,
-                                         const int16_t* convert_table);
-
-MEDIA_EXPORT void ConvertYUVToRGB32_SSE(const uint8_t* yplane,
-                                        const uint8_t* uplane,
-                                        const uint8_t* vplane,
-                                        uint8_t* rgbframe,
-                                        int width,
-                                        int height,
-                                        int ystride,
-                                        int uvstride,
-                                        int rgbstride,
-                                        YUVType yuv_type);
-
-MEDIA_EXPORT void ConvertYUVAToARGB_MMX(const uint8_t* yplane,
-                                        const uint8_t* uplane,
-                                        const uint8_t* vplane,
-                                        const uint8_t* aplane,
-                                        uint8_t* rgbframe,
-                                        int width,
-                                        int height,
-                                        int ystride,
-                                        int uvstride,
-                                        int avstride,
-                                        int rgbstride,
-                                        YUVType yuv_type);
-
-MEDIA_EXPORT void ScaleYUVToRGB32Row_C(const uint8_t* y_buf,
-                                       const uint8_t* u_buf,
-                                       const uint8_t* v_buf,
-                                       uint8_t* rgb_buf,
-                                       ptrdiff_t width,
-                                       ptrdiff_t source_dx,
-                                       const int16_t* convert_table);
-
-MEDIA_EXPORT void LinearScaleYUVToRGB32Row_C(const uint8_t* y_buf,
-                                             const uint8_t* u_buf,
-                                             const uint8_t* v_buf,
-                                             uint8_t* rgb_buf,
-                                             ptrdiff_t width,
-                                             ptrdiff_t source_dx,
-                                             const int16_t* convert_table);
-
-MEDIA_EXPORT void LinearScaleYUVToRGB32RowWithRange_C(
-    const uint8_t* y_buf,
-    const uint8_t* u_buf,
-    const uint8_t* v_buf,
-    uint8_t* rgb_buf,
-    int dest_width,
-    int source_x,
-    int source_dx,
-    const int16_t* convert_table);
-
-}  // namespace media
-
-// Assembly functions are declared without namespace.
-extern "C" {
-
-// We use ptrdiff_t instead of int for yasm routine parameters to portably
-// sign-extend int. On Win64, MSVC does not sign-extend the value in the stack
-// home of int function parameters, and yasm routines are unaware of this lack
-// of extension and fault.  ptrdiff_t is portably sign-extended and fixes this
-// issue on at least Win64.  The C-equivalent RowProc versions' prototypes
-// include the same change to ptrdiff_t to reuse the typedefs.
-
-MEDIA_EXPORT void ConvertYUVAToARGBRow_MMX(const uint8_t* yplane,
-                                           const uint8_t* uplane,
-                                           const uint8_t* vplane,
-                                           const uint8_t* aplane,
-                                           uint8_t* rgbframe,
-                                           ptrdiff_t width,
-                                           const int16_t* convert_table);
-
-MEDIA_EXPORT void ConvertYUVToRGB32Row_SSE(const uint8_t* yplane,
-                                           const uint8_t* uplane,
-                                           const uint8_t* vplane,
-                                           uint8_t* rgbframe,
-                                           ptrdiff_t width,
-                                           const int16_t* convert_table);
-
-MEDIA_EXPORT void ScaleYUVToRGB32Row_SSE(const uint8_t* y_buf,
-                                         const uint8_t* u_buf,
-                                         const uint8_t* v_buf,
-                                         uint8_t* rgb_buf,
-                                         ptrdiff_t width,
-                                         ptrdiff_t source_dx,
-                                         const int16_t* convert_table);
-
-MEDIA_EXPORT void ScaleYUVToRGB32Row_SSE2_X64(const uint8_t* y_buf,
-                                              const uint8_t* u_buf,
-                                              const uint8_t* v_buf,
-                                              uint8_t* rgb_buf,
-                                              ptrdiff_t width,
-                                              ptrdiff_t source_dx,
-                                              const int16_t* convert_table);
-
-MEDIA_EXPORT void LinearScaleYUVToRGB32Row_SSE(const uint8_t* y_buf,
-                                               const uint8_t* u_buf,
-                                               const uint8_t* v_buf,
-                                               uint8_t* rgb_buf,
-                                               ptrdiff_t width,
-                                               ptrdiff_t source_dx,
-                                               const int16_t* convert_table);
-
-MEDIA_EXPORT void LinearScaleYUVToRGB32Row_MMX_X64(
-    const uint8_t* y_buf,
-    const uint8_t* u_buf,
-    const uint8_t* v_buf,
-    uint8_t* rgb_buf,
-    ptrdiff_t width,
-    ptrdiff_t source_dx,
-    const int16_t* convert_table);
-
-}  // extern "C"
-
-#endif  // MEDIA_BASE_SIMD_CONVERT_YUV_TO_RGB_H_
diff --git a/media/base/simd/convert_yuv_to_rgb_c.cc b/media/base/simd/convert_yuv_to_rgb_c.cc
deleted file mode 100644
index f4345df3..0000000
--- a/media/base/simd/convert_yuv_to_rgb_c.cc
+++ /dev/null
@@ -1,277 +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 <stddef.h>
-#include <stdint.h>
-
-#include "build/build_config.h"
-#include "media/base/simd/convert_yuv_to_rgb.h"
-
-namespace media {
-
-#define packuswb(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x)))
-#define paddsw(x, y) (((x) + (y)) < -32768 ? -32768 : \
-    (((x) + (y)) > 32767 ? 32767 : ((x) + (y))))
-
-// On Android, pixel layout is RGBA (see skia/include/core/SkColorPriv.h);
-// however, other Chrome platforms use BGRA (see skia/config/SkUserConfig.h).
-// Ideally, android should not use the functions here due to performance issue
-// (http://crbug.com/249980).
-#if defined(OS_ANDROID)
-#define SK_R32_SHIFT    0
-#define SK_G32_SHIFT    8
-#define SK_B32_SHIFT    16
-#define SK_A32_SHIFT    24
-#define R_INDEX         0
-#define G_INDEX         1
-#define B_INDEX         2
-#define A_INDEX         3
-#else
-#define SK_B32_SHIFT    0
-#define SK_G32_SHIFT    8
-#define SK_R32_SHIFT    16
-#define SK_A32_SHIFT    24
-#define B_INDEX         0
-#define G_INDEX         1
-#define R_INDEX         2
-#define A_INDEX         3
-#endif
-
-static inline void ConvertYUVToRGB32_C(uint8_t y,
-                                       uint8_t u,
-                                       uint8_t v,
-                                       uint8_t* rgb_buf,
-                                       const int16_t* convert_table) {
-  int b = convert_table[4 * (256 + u) + B_INDEX];
-  int g = convert_table[4 * (256 + u) + G_INDEX];
-  int r = convert_table[4 * (256 + u) + R_INDEX];
-  int a = convert_table[4 * (256 + u) + A_INDEX];
-
-  b = paddsw(b, convert_table[4 * (512 + v) + B_INDEX]);
-  g = paddsw(g, convert_table[4 * (512 + v) + G_INDEX]);
-  r = paddsw(r, convert_table[4 * (512 + v) + R_INDEX]);
-  a = paddsw(a, convert_table[4 * (512 + v) + A_INDEX]);
-
-  b = paddsw(b, convert_table[4 * y + B_INDEX]);
-  g = paddsw(g, convert_table[4 * y + G_INDEX]);
-  r = paddsw(r, convert_table[4 * y + R_INDEX]);
-  a = paddsw(a, convert_table[4 * y + A_INDEX]);
-
-  b >>= 6;
-  g >>= 6;
-  r >>= 6;
-  a >>= 6;
-
-  *reinterpret_cast<uint32_t*>(rgb_buf) =
-      (packuswb(b) << SK_B32_SHIFT) | (packuswb(g) << SK_G32_SHIFT) |
-      (packuswb(r) << SK_R32_SHIFT) | (packuswb(a) << SK_A32_SHIFT);
-}
-
-static inline void ConvertYUVAToARGB_C(uint8_t y,
-                                       uint8_t u,
-                                       uint8_t v,
-                                       uint8_t a,
-                                       uint8_t* rgb_buf,
-                                       const int16_t* convert_table) {
-  int b = convert_table[4 * (256 + u) + 0];
-  int g = convert_table[4 * (256 + u) + 1];
-  int r = convert_table[4 * (256 + u) + 2];
-
-  b = paddsw(b, convert_table[4 * (512 + v) + 0]);
-  g = paddsw(g, convert_table[4 * (512 + v) + 1]);
-  r = paddsw(r, convert_table[4 * (512 + v) + 2]);
-
-  b = paddsw(b, convert_table[4 * y + 0]);
-  g = paddsw(g, convert_table[4 * y + 1]);
-  r = paddsw(r, convert_table[4 * y + 2]);
-
-  b >>= 6;
-  g >>= 6;
-  r >>= 6;
-
-  b = packuswb(b) * a >> 8;
-  g = packuswb(g) * a >> 8;
-  r = packuswb(r) * a >> 8;
-
-  *reinterpret_cast<uint32_t*>(rgb_buf) =
-      (b << SK_B32_SHIFT) | (g << SK_G32_SHIFT) | (r << SK_R32_SHIFT) |
-      (a << SK_A32_SHIFT);
-}
-
-void ConvertYUVToRGB32Row_C(const uint8_t* y_buf,
-                            const uint8_t* u_buf,
-                            const uint8_t* v_buf,
-                            uint8_t* rgb_buf,
-                            ptrdiff_t width,
-                            const int16_t* convert_table) {
-  for (int x = 0; x < width; x += 2) {
-    uint8_t u = u_buf[x >> 1];
-    uint8_t v = v_buf[x >> 1];
-    uint8_t y0 = y_buf[x];
-    ConvertYUVToRGB32_C(y0, u, v, rgb_buf, convert_table);
-    if ((x + 1) < width) {
-      uint8_t y1 = y_buf[x + 1];
-      ConvertYUVToRGB32_C(y1, u, v, rgb_buf + 4, convert_table);
-    }
-    rgb_buf += 8;  // Advance 2 pixels.
-  }
-}
-
-void ConvertYUVAToARGBRow_C(const uint8_t* y_buf,
-                            const uint8_t* u_buf,
-                            const uint8_t* v_buf,
-                            const uint8_t* a_buf,
-                            uint8_t* rgba_buf,
-                            ptrdiff_t width,
-                            const int16_t* convert_table) {
-  for (int x = 0; x < width; x += 2) {
-    uint8_t u = u_buf[x >> 1];
-    uint8_t v = v_buf[x >> 1];
-    uint8_t y0 = y_buf[x];
-    uint8_t a0 = a_buf[x];
-    ConvertYUVAToARGB_C(y0, u, v, a0, rgba_buf, convert_table);
-    if ((x + 1) < width) {
-      uint8_t y1 = y_buf[x + 1];
-      uint8_t a1 = a_buf[x + 1];
-      ConvertYUVAToARGB_C(y1, u, v, a1, rgba_buf + 4, convert_table);
-    }
-    rgba_buf += 8;  // Advance 2 pixels.
-  }
-}
-
-// 16.16 fixed point is used.  A shift by 16 isolates the integer.
-// A shift by 17 is used to further subsample the chrominence channels.
-// & 0xffff isolates the fixed point fraction.  >> 2 to get the upper 2 bits,
-// for 1/65536 pixel accurate interpolation.
-void ScaleYUVToRGB32Row_C(const uint8_t* y_buf,
-                          const uint8_t* u_buf,
-                          const uint8_t* v_buf,
-                          uint8_t* rgb_buf,
-                          ptrdiff_t width,
-                          ptrdiff_t source_dx,
-                          const int16_t* convert_table) {
-  int x = 0;
-  for (int i = 0; i < width; i += 2) {
-    int y = y_buf[x >> 16];
-    int u = u_buf[(x >> 17)];
-    int v = v_buf[(x >> 17)];
-    ConvertYUVToRGB32_C(y, u, v, rgb_buf, convert_table);
-    x += source_dx;
-    if ((i + 1) < width) {
-      y = y_buf[x >> 16];
-      ConvertYUVToRGB32_C(y, u, v, rgb_buf+4, convert_table);
-      x += source_dx;
-    }
-    rgb_buf += 8;
-  }
-}
-
-void LinearScaleYUVToRGB32Row_C(const uint8_t* y_buf,
-                                const uint8_t* u_buf,
-                                const uint8_t* v_buf,
-                                uint8_t* rgb_buf,
-                                ptrdiff_t width,
-                                ptrdiff_t source_dx,
-                                const int16_t* convert_table) {
-  // Avoid point-sampling for down-scaling by > 2:1.
-  int source_x = 0;
-  if (source_dx >= 0x20000)
-    source_x += 0x8000;
-  LinearScaleYUVToRGB32RowWithRange_C(y_buf, u_buf, v_buf, rgb_buf, width,
-                                      source_x, source_dx, convert_table);
-}
-
-void LinearScaleYUVToRGB32RowWithRange_C(const uint8_t* y_buf,
-                                         const uint8_t* u_buf,
-                                         const uint8_t* v_buf,
-                                         uint8_t* rgb_buf,
-                                         int dest_width,
-                                         int x,
-                                         int source_dx,
-                                         const int16_t* convert_table) {
-  for (int i = 0; i < dest_width; i += 2) {
-    int y0 = y_buf[x >> 16];
-    int y1 = y_buf[(x >> 16) + 1];
-    int u0 = u_buf[(x >> 17)];
-    int u1 = u_buf[(x >> 17) + 1];
-    int v0 = v_buf[(x >> 17)];
-    int v1 = v_buf[(x >> 17) + 1];
-    int y_frac = (x & 65535);
-    int uv_frac = ((x >> 1) & 65535);
-    int y = (y_frac * y1 + (y_frac ^ 65535) * y0) >> 16;
-    int u = (uv_frac * u1 + (uv_frac ^ 65535) * u0) >> 16;
-    int v = (uv_frac * v1 + (uv_frac ^ 65535) * v0) >> 16;
-    ConvertYUVToRGB32_C(y, u, v, rgb_buf, convert_table);
-    x += source_dx;
-    if ((i + 1) < dest_width) {
-      y0 = y_buf[x >> 16];
-      y1 = y_buf[(x >> 16) + 1];
-      y_frac = (x & 65535);
-      y = (y_frac * y1 + (y_frac ^ 65535) * y0) >> 16;
-      ConvertYUVToRGB32_C(y, u, v, rgb_buf+4, convert_table);
-      x += source_dx;
-    }
-    rgb_buf += 8;
-  }
-}
-
-void ConvertYUVToRGB32_C(const uint8_t* yplane,
-                         const uint8_t* uplane,
-                         const uint8_t* vplane,
-                         uint8_t* rgbframe,
-                         int width,
-                         int height,
-                         int ystride,
-                         int uvstride,
-                         int rgbstride,
-                         YUVType yuv_type) {
-  unsigned int y_shift = GetVerticalShift(yuv_type);
-  const int16_t* lookup_table = GetLookupTable(yuv_type);
-  for (int y = 0; y < height; ++y) {
-    uint8_t* rgb_row = rgbframe + y * rgbstride;
-    const uint8_t* y_ptr = yplane + y * ystride;
-    const uint8_t* u_ptr = uplane + (y >> y_shift) * uvstride;
-    const uint8_t* v_ptr = vplane + (y >> y_shift) * uvstride;
-
-    ConvertYUVToRGB32Row_C(y_ptr,
-                           u_ptr,
-                           v_ptr,
-                           rgb_row,
-                           width,
-                           lookup_table);
-  }
-}
-
-void ConvertYUVAToARGB_C(const uint8_t* yplane,
-                         const uint8_t* uplane,
-                         const uint8_t* vplane,
-                         const uint8_t* aplane,
-                         uint8_t* rgbaframe,
-                         int width,
-                         int height,
-                         int ystride,
-                         int uvstride,
-                         int astride,
-                         int rgbastride,
-                         YUVType yuv_type) {
-  unsigned int y_shift = GetVerticalShift(yuv_type);
-  const int16_t* lookup_table = GetLookupTable(yuv_type);
-  for (int y = 0; y < height; y++) {
-    uint8_t* rgba_row = rgbaframe + y * rgbastride;
-    const uint8_t* y_ptr = yplane + y * ystride;
-    const uint8_t* u_ptr = uplane + (y >> y_shift) * uvstride;
-    const uint8_t* v_ptr = vplane + (y >> y_shift) * uvstride;
-    const uint8_t* a_ptr = aplane + y * astride;
-
-    ConvertYUVAToARGBRow_C(y_ptr,
-                           u_ptr,
-                           v_ptr,
-                           a_ptr,
-                           rgba_row,
-                           width,
-                           lookup_table);
-  }
-}
-
-}  // namespace media
diff --git a/media/base/simd/convert_yuv_to_rgb_mmx.inc b/media/base/simd/convert_yuv_to_rgb_mmx.inc
deleted file mode 100644
index 4b69d1b1..0000000
--- a/media/base/simd/convert_yuv_to_rgb_mmx.inc
+++ /dev/null
@@ -1,63 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "media/base/simd/media_export.asm"
-
-  EXPORT    SYMBOL
-  align     function_align
-
-mangle(SYMBOL):
-  %assign   stack_offset 0
-  PROLOGUE  6, 7, 3, Y, U, V, ARGB, WIDTH, TABLE, TEMP
-
-  jmp       .convertend
-
-.convertloop:
-  movzx     TEMPd, BYTE [Uq]
-  movq      mm0, [TABLEq + 2048 + 8 * TEMPq]
-  add       Uq, 1
-
-  movzx     TEMPd, BYTE [Vq]
-  paddsw    mm0, [TABLEq + 4096 + 8 * TEMPq]
-  add       Vq, 1
-
-  movzx     TEMPd, BYTE [Yq]
-  movq      mm1, [TABLEq + 8 * TEMPq]
-
-  movzx     TEMPd, BYTE [Yq + 1]
-  movq      mm2, [TABLEq + 8 * TEMPq]
-  add       Yq, 2
-
-  ; Add UV components to Y component.
-  paddsw    mm1, mm0
-  paddsw    mm2, mm0
-
-  ; Down shift and then pack.
-  psraw     mm1, 6
-  psraw     mm2, 6
-  packuswb  mm1, mm2
-  MOVQ      [ARGBq], mm1
-  add       ARGBq, 8
-
-.convertend:
-  sub       WIDTHq, 2
-  jns       .convertloop
-
-  ; If number of pixels is odd then compute it.
-  and       WIDTHq, 1
-  jz        .convertdone
-
-  movzx     TEMPd, BYTE [Uq]
-  movq      mm0, [TABLEq + 2048 + 8 * TEMPq]
-  movzx     TEMPd, BYTE [Vq]
-  paddsw    mm0, [TABLEq + 4096 + 8 * TEMPq]
-  movzx     TEMPd, BYTE [Yq]
-  movq      mm1, [TABLEq + 8 * TEMPq]
-  paddsw    mm1, mm0
-  psraw     mm1, 6
-  packuswb  mm1, mm1
-  movd      [ARGBq], mm1
-
-.convertdone:
-  RET
diff --git a/media/base/simd/convert_yuv_to_rgb_sse.asm b/media/base/simd/convert_yuv_to_rgb_sse.asm
deleted file mode 100644
index f666243..0000000
--- a/media/base/simd/convert_yuv_to_rgb_sse.asm
+++ /dev/null
@@ -1,24 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX and SSE instructions.
-;
-  SECTION_TEXT
-  CPU       MMX, SSE
-
-; Use SSE instruction movntq can write faster.
-%define MOVQ movntq
-
-;
-; extern "C" void ConvertYUVToRGB32Row_SSE(const uint8_t* y_buf,
-;                                          const uint8_t* u_buf,
-;                                          const uint8_t* v_buf,
-;                                          uint8_t* rgb_buf,
-;                                          ptrdiff_t width);
-;                                          const int16_t* convert_table);
-%define SYMBOL ConvertYUVToRGB32Row_SSE
-%include "convert_yuv_to_rgb_mmx.inc"
diff --git a/media/base/simd/convert_yuv_to_rgb_x86.cc b/media/base/simd/convert_yuv_to_rgb_x86.cc
deleted file mode 100644
index a06799bf..0000000
--- a/media/base/simd/convert_yuv_to_rgb_x86.cc
+++ /dev/null
@@ -1,78 +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 <stdint.h>
-
-#if defined(_MSC_VER)
-#include <intrin.h>
-#else
-#include <mmintrin.h>
-#endif
-
-#include "media/base/simd/convert_yuv_to_rgb.h"
-#include "media/base/yuv_convert.h"
-
-namespace media {
-
-void ConvertYUVAToARGB_MMX(const uint8_t* yplane,
-                           const uint8_t* uplane,
-                           const uint8_t* vplane,
-                           const uint8_t* aplane,
-                           uint8_t* rgbframe,
-                           int width,
-                           int height,
-                           int ystride,
-                           int uvstride,
-                           int astride,
-                           int rgbstride,
-                           YUVType yuv_type) {
-  unsigned int y_shift = GetVerticalShift(yuv_type);
-  for (int y = 0; y < height; ++y) {
-    uint8_t* rgb_row = rgbframe + y * rgbstride;
-    const uint8_t* y_ptr = yplane + y * ystride;
-    const uint8_t* u_ptr = uplane + (y >> y_shift) * uvstride;
-    const uint8_t* v_ptr = vplane + (y >> y_shift) * uvstride;
-    const uint8_t* a_ptr = aplane + y * astride;
-
-    ConvertYUVAToARGBRow_MMX(y_ptr,
-                             u_ptr,
-                             v_ptr,
-                             a_ptr,
-                             rgb_row,
-                             width,
-                             GetLookupTable(yuv_type));
-  }
-
-  EmptyRegisterState();
-}
-
-void ConvertYUVToRGB32_SSE(const uint8_t* yplane,
-                           const uint8_t* uplane,
-                           const uint8_t* vplane,
-                           uint8_t* rgbframe,
-                           int width,
-                           int height,
-                           int ystride,
-                           int uvstride,
-                           int rgbstride,
-                           YUVType yuv_type) {
-  unsigned int y_shift = GetVerticalShift(yuv_type);
-  for (int y = 0; y < height; ++y) {
-    uint8_t* rgb_row = rgbframe + y * rgbstride;
-    const uint8_t* y_ptr = yplane + y * ystride;
-    const uint8_t* u_ptr = uplane + (y >> y_shift) * uvstride;
-    const uint8_t* v_ptr = vplane + (y >> y_shift) * uvstride;
-
-    ConvertYUVToRGB32Row_SSE(y_ptr,
-                             u_ptr,
-                             v_ptr,
-                             rgb_row,
-                             width,
-                             GetLookupTable(yuv_type));
-  }
-
-  EmptyRegisterState();
-}
-
-}  // namespace media
diff --git a/media/base/simd/convert_yuva_to_argb_mmx.asm b/media/base/simd/convert_yuva_to_argb_mmx.asm
deleted file mode 100644
index 28a147e..0000000
--- a/media/base/simd/convert_yuva_to_argb_mmx.asm
+++ /dev/null
@@ -1,24 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX instructions.
-;
-  SECTION_TEXT
-  CPU       MMX
-
-; Use movq to save the output.
-%define MOVQ movq
-
-; extern "C" void ConvertYUVAToARGBRow_MMX(const uint8_t* y_buf,
-;                                          const uint8_t* u_buf,
-;                                          const uint8_t* v_buf,
-;                                          const uint8_t* a_buf,
-;                                          uint8_t* rgb_buf,
-;                                          ptrdiff_t width);
-;                                          const int16_t* convert_table);
-%define SYMBOL ConvertYUVAToARGBRow_MMX
-%include "convert_yuva_to_argb_mmx.inc"
diff --git a/media/base/simd/convert_yuva_to_argb_mmx.inc b/media/base/simd/convert_yuva_to_argb_mmx.inc
deleted file mode 100644
index d4933836..0000000
--- a/media/base/simd/convert_yuva_to_argb_mmx.inc
+++ /dev/null
@@ -1,114 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "media/base/simd/media_export.asm"
-
-  EXPORT    SYMBOL
-  align     function_align
-
-mangle(SYMBOL):
-  %assign   stack_offset 0
-  PROLOGUE  7, 7, 3, Y, U, V, A, ARGB, WIDTH, TABLE
-  PUSH      WIDTHq
-  DEFINE_ARGS Y, U, V, A, ARGB, TABLE, TEMP
-  mov       TABLEq, TEMPq
-  jmp       .convertend
-
-.convertloop:
-  movzx     TEMPd, BYTE [Uq]
-  movq      mm0, [TABLEq + 2048 + 8 * TEMPq]
-  add       Uq, 1
-
-  movzx     TEMPd, BYTE [Vq]
-  paddsw    mm0, [TABLEq + 4096 + 8 * TEMPq]
-  add       Vq, 1
-
-  movzx     TEMPd, BYTE [Yq]
-  movq      mm1, [TABLEq + 8 * TEMPq]
-
-  movzx     TEMPd, BYTE [Yq + 1]
-  movq      mm2, [TABLEq + 8 * TEMPq]
-  add       Yq, 2
-
-  ; Add UV components to Y component.
-  paddsw    mm1, mm0
-  paddsw    mm2, mm0
-
-  ; Down shift and then pack.
-  psraw     mm1, 6
-  psraw     mm2, 6
-  packuswb  mm1, mm2
-
-  ; Unpack
-  movq      mm0, mm1
-  pxor      mm2, mm2
-  punpcklbw mm0, mm2
-  punpckhbw mm1, mm2
-
-  ; Add one to our alpha values, this is a somewhat unfortunate hack; while
-  ; the pack/unpack above handle saturating any negative numbers to 0, they also
-  ; truncate the alpha value to 255. The math ahead wants to produce the same
-  ; ARGB alpha value as the source pixel in YUVA, but this depends on the alpha
-  ; value in |mm0| and |mm1| being 256, (let A be the source image alpha,
-  ; 256 * A >> 8 == A, whereas 255 * A >> 8 is off by one except at 0).
-  mov       TEMPq, 0x00010000
-  movd      mm2, TEMPd
-  psllq     mm2, 32
-  paddsw    mm0, mm2
-  paddsw    mm1, mm2
-
-  ; Multiply by alpha value, then repack high bytes of words.
-  movzx     TEMPd, BYTE [Aq]
-  movq      mm2, [TABLEq + 6144 + 8 * TEMPq]
-  pmullw    mm0, mm2
-  psrlw     mm0, 8
-  movzx     TEMPd, BYTE [Aq + 1]
-  movq      mm2, [TABLEq + 6144 + 8 * TEMPq]
-  add       Aq, 2
-  pmullw    mm1, mm2
-  psrlw     mm1, 8
-  packuswb  mm0, mm1
-
-  MOVQ      [ARGBq], mm0
-  add       ARGBq, 8
-
-.convertend:
-  sub       dword [rsp], 2
-  jns       .convertloop
-
-  ; If number of pixels is odd then compute it.
-  and       dword [rsp], 1
-  jz        .convertdone
-
-  movzx     TEMPd, BYTE [Uq]
-  movq      mm0, [TABLEq + 2048 + 8 * TEMPq]
-  movzx     TEMPd, BYTE [Vq]
-  paddsw    mm0, [TABLEq + 4096 + 8 * TEMPq]
-  movzx     TEMPd, BYTE [Yq]
-  movq      mm1, [TABLEq + 8 * TEMPq]
-  paddsw    mm1, mm0
-  psraw     mm1, 6
-  packuswb  mm1, mm1
-
-  ; Multiply ARGB by alpha value.
-  pxor      mm0, mm0
-  punpcklbw mm1, mm0
-
-  ; See above note about this hack.
-  mov       TEMPq, 0x00010000
-  movd      mm0, TEMPd
-  psllq     mm0, 32
-  paddsw    mm1, mm0
-
-  movzx     TEMPd, BYTE [Aq]
-  movq      mm0, [TABLEq + 6144 + 8 * TEMPq]
-  pmullw    mm1, mm0
-  psrlw     mm1, 8
-  packuswb  mm1, mm1
-
-  movd      [ARGBq], mm1
-
-.convertdone:
-  POP       TABLEq
-  RET
diff --git a/media/base/simd/empty_register_state_mmx.asm b/media/base/simd/empty_register_state_mmx.asm
deleted file mode 100644
index d0028b51..0000000
--- a/media/base/simd/empty_register_state_mmx.asm
+++ /dev/null
@@ -1,24 +0,0 @@
-; Copyright (c) 2013 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "media/base/simd/media_export.asm"
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX instructions as an alternative to _mm_empty() which
-; is not supported in Visual Studio 2010 on x64.
-; TODO(wolenetz): Use MMX intrinsics when compiling win64 with Visual
-; Studio 2012? http://crbug.com/173450
-;
-  SECTION_TEXT
-  CPU       MMX
-
-%define SYMBOL EmptyRegisterState_MMX
-  EXPORT    SYMBOL
-  align     function_align
-
-mangle(SYMBOL):
-  emms
-  ret
-
diff --git a/media/base/simd/filter_yuv.h b/media/base/simd/filter_yuv.h
deleted file mode 100644
index af30bd133..0000000
--- a/media/base/simd/filter_yuv.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_BASE_SIMD_FILTER_YUV_H_
-#define MEDIA_BASE_SIMD_FILTER_YUV_H_
-
-#include <stdint.h>
-
-#include "media/base/media_export.h"
-
-namespace media {
-
-// These methods are exported for testing purposes only.  Library users should
-// only call the methods listed in yuv_convert.h.
-
-MEDIA_EXPORT void FilterYUVRows_C(uint8_t* ybuf,
-                                  const uint8_t* y0_ptr,
-                                  const uint8_t* y1_ptr,
-                                  int source_width,
-                                  uint8_t source_y_fraction);
-
-MEDIA_EXPORT void FilterYUVRows_SSE2(uint8_t* ybuf,
-                                     const uint8_t* y0_ptr,
-                                     const uint8_t* y1_ptr,
-                                     int source_width,
-                                     uint8_t source_y_fraction);
-
-}  // namespace media
-
-#endif  // MEDIA_BASE_SIMD_FILTER_YUV_H_
diff --git a/media/base/simd/filter_yuv_c.cc b/media/base/simd/filter_yuv_c.cc
deleted file mode 100644
index 7f60676..0000000
--- a/media/base/simd/filter_yuv_c.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdint.h>
-
-#include "media/base/simd/filter_yuv.h"
-
-namespace media {
-
-void FilterYUVRows_C(uint8_t* ybuf,
-                     const uint8_t* y0_ptr,
-                     const uint8_t* y1_ptr,
-                     int source_width,
-                     uint8_t source_y_fraction) {
-  uint8_t y1_fraction = source_y_fraction;
-  uint16_t y0_fraction = 256 - y1_fraction;
-  uint8_t* end = ybuf + source_width;
-  uint8_t* rounded_end = ybuf + (source_width & ~7);
-
-  while (ybuf < rounded_end) {
-    ybuf[0] = (y0_ptr[0] * y0_fraction + y1_ptr[0] * y1_fraction) >> 8;
-    ybuf[1] = (y0_ptr[1] * y0_fraction + y1_ptr[1] * y1_fraction) >> 8;
-    ybuf[2] = (y0_ptr[2] * y0_fraction + y1_ptr[2] * y1_fraction) >> 8;
-    ybuf[3] = (y0_ptr[3] * y0_fraction + y1_ptr[3] * y1_fraction) >> 8;
-    ybuf[4] = (y0_ptr[4] * y0_fraction + y1_ptr[4] * y1_fraction) >> 8;
-    ybuf[5] = (y0_ptr[5] * y0_fraction + y1_ptr[5] * y1_fraction) >> 8;
-    ybuf[6] = (y0_ptr[6] * y0_fraction + y1_ptr[6] * y1_fraction) >> 8;
-    ybuf[7] = (y0_ptr[7] * y0_fraction + y1_ptr[7] * y1_fraction) >> 8;
-    y0_ptr += 8;
-    y1_ptr += 8;
-    ybuf += 8;
-  }
-
-  while (ybuf < end) {
-    ybuf[0] = (y0_ptr[0] * y0_fraction + y1_ptr[0] * y1_fraction) >> 8;
-    ++ybuf;
-    ++y0_ptr;
-    ++y1_ptr;
-  }
-}
-
-}  // namespace media
diff --git a/media/base/simd/filter_yuv_sse2.cc b/media/base/simd/filter_yuv_sse2.cc
deleted file mode 100644
index 85ee5a7..0000000
--- a/media/base/simd/filter_yuv_sse2.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdint.h>
-
-#if defined(_MSC_VER)
-#include <intrin.h>
-#else
-#include <mmintrin.h>
-#include <emmintrin.h>
-#endif
-
-#include "media/base/simd/filter_yuv.h"
-
-namespace media {
-
-void FilterYUVRows_SSE2(uint8_t* dest,
-                        const uint8_t* src0,
-                        const uint8_t* src1,
-                        int width,
-                        uint8_t fraction) {
-  int pixel = 0;
-
-  // Process the unaligned bytes first.
-  int unaligned_width =
-      (16 - (reinterpret_cast<uintptr_t>(dest) & 15)) & 15;
-  while (pixel < width && pixel < unaligned_width) {
-    dest[pixel] = (src0[pixel] * (256 - fraction) +
-                   src1[pixel] * fraction) >> 8;
-    ++pixel;
-  }
-
-  __m128i zero = _mm_setzero_si128();
-  __m128i src1_fraction = _mm_set1_epi16(fraction);
-  __m128i src0_fraction = _mm_set1_epi16(256 - fraction);
-  const __m128i* src0_128 =
-      reinterpret_cast<const __m128i*>(src0 + pixel);
-  const __m128i* src1_128 =
-      reinterpret_cast<const __m128i*>(src1 + pixel);
-  __m128i* dest128 = reinterpret_cast<__m128i*>(dest + pixel);
-  __m128i* end128 = reinterpret_cast<__m128i*>(
-      reinterpret_cast<uintptr_t>(dest + width) & ~15);
-
-  while (dest128 < end128) {
-    __m128i src0 = _mm_loadu_si128(src0_128);
-    __m128i src1 = _mm_loadu_si128(src1_128);
-    __m128i src2 = _mm_unpackhi_epi8(src0, zero);
-    __m128i src3 = _mm_unpackhi_epi8(src1, zero);
-    src0 = _mm_unpacklo_epi8(src0, zero);
-    src1 = _mm_unpacklo_epi8(src1, zero);
-    src0 = _mm_mullo_epi16(src0, src0_fraction);
-    src1 = _mm_mullo_epi16(src1, src1_fraction);
-    src2 = _mm_mullo_epi16(src2, src0_fraction);
-    src3 = _mm_mullo_epi16(src3, src1_fraction);
-    src0 = _mm_add_epi16(src0, src1);
-    src2 = _mm_add_epi16(src2, src3);
-    src0 = _mm_srli_epi16(src0, 8);
-    src2 = _mm_srli_epi16(src2, 8);
-    src0 = _mm_packus_epi16(src0, src2);
-    *dest128++ = src0;
-    ++src0_128;
-    ++src1_128;
-    pixel += 16;
-  }
-
-  while (pixel < width) {
-    dest[pixel] = (src0[pixel] * (256 - fraction) +
-                   src1[pixel] * fraction) >> 8;
-    ++pixel;
-  }
-}
-
-}  // namespace media
diff --git a/media/base/simd/linear_scale_yuv_to_rgb_mmx.asm b/media/base/simd/linear_scale_yuv_to_rgb_mmx.asm
deleted file mode 100644
index f2e4f95d..0000000
--- a/media/base/simd/linear_scale_yuv_to_rgb_mmx.asm
+++ /dev/null
@@ -1,24 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX instructions.
-;
-  SECTION_TEXT
-  CPU       MMX
-
-; Use movq to save the output.
-%define MOVQ movq
-
-; void LinearScaleYUVToRGB32Row_MMX(const uint8_t* y_buf,
-;                                   const uint8_t* u_buf,
-;                                   const uint8_t* v_buf,
-;                                   uint8_t* rgb_buf,
-;                                   ptrdiff_t width,
-;                                   ptrdiff_t source_dx);
-;                                   const int16_t* convert_table);
-%define SYMBOL LinearScaleYUVToRGB32Row_MMX
-%include "linear_scale_yuv_to_rgb_mmx.inc"
diff --git a/media/base/simd/linear_scale_yuv_to_rgb_mmx.inc b/media/base/simd/linear_scale_yuv_to_rgb_mmx.inc
deleted file mode 100644
index 48f62ac..0000000
--- a/media/base/simd/linear_scale_yuv_to_rgb_mmx.inc
+++ /dev/null
@@ -1,135 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "media/base/simd/media_export.asm"
-
-  EXPORT    SYMBOL
-  align     function_align
-
-mangle(SYMBOL):
-  %assign   stack_offset 0
-
-; Parameters are in the following order:
-; 1. Y plane
-; 2. U plane
-; 3. V plane
-; 4. ARGB frame
-; 5. Width
-; 6. Source dx
-; 7. Conversion lookup table
-
-PROLOGUE  7, 7, 3, Y, R0, R1, ARGB, R2, TEMP, R3
-
-%if gprsize == 8
-%define     WORD_SIZE   QWORD
-%else
-%define     WORD_SIZE   DWORD
-%endif
-
-; Define register aliases.
-%define     Xq                  R1q     ; Current X position
-%define     COMPLq              R2q     ; Component A value
-%define     COMPLd              R2d     ; Component A value
-%define     U_ARG_REGq          R0q     ; U plane address argument
-%define     V_ARG_REGq          R1q     ; V plane address argument
-%define     SOURCE_DX_ARG_REGq  TEMPq   ; Source dx argument
-%define     WIDTH_ARG_REGq      R2q     ; Width argument
-
-%define     COMPRq              R0q     ; Component B value
-%define     COMPRd              R0d     ; Component B value
-%define     Uq                  R0q     ; U plane address
-%define     Vq                  R0q     ; V plane address
-%define     U_PLANE             WORD_SIZE [rsp + 3 * gprsize]
-%define     TABLE               R3q     ; Address of the table
-
-; Defines for stack variables.
-%define     V_PLANE             WORD_SIZE [rsp + 2 * gprsize]
-%define     SOURCE_DX           WORD_SIZE [rsp + gprsize]
-%define     SOURCE_WIDTH        WORD_SIZE [rsp]
-
-; Define stack usage.
-  PUSH      U_ARG_REGq
-  PUSH      V_ARG_REGq
-  PUSH      SOURCE_DX_ARG_REGq
-  imul      WIDTH_ARG_REGq, SOURCE_DX_ARG_REGq  ; source_width = width * source_dx
-  PUSH      WIDTH_ARG_REGq
-
-%macro EPILOGUE 0
-  ADD       rsp, 4 * gprsize
-%endmacro
-
-  xor       Xq, Xq                       ; x = 0
-  cmp       SOURCE_DX_ARG_REGq, 0x20000
-  jl        .lscaleend
-  mov       Xq, 0x8000                   ; x = 0.5 for 1/2 or less
-  jmp       .lscaleend
-
-.lscaleloop:
-  mov       Uq, U_PLANE
-
-; Define macros for scaling YUV components since they are reused.
-%macro SCALEUV 1
-  mov       TEMPq, Xq
-  sar       TEMPq, 0x11
-  movzx     COMPLd, BYTE [%1 + TEMPq]
-  movzx     COMPRd, BYTE [%1 + TEMPq + 1]
-  mov       TEMPq, Xq
-  and       TEMPq, 0x1fffe
-  imul      COMPRq, TEMPq
-  xor       TEMPq, 0x1fffe
-  imul      COMPLq, TEMPq
-  add       COMPLq, COMPRq
-  shr       COMPLq, 17
-%endmacro
-  SCALEUV   Uq                           ; Use the above macro to scale U
-  movq      mm0, [TABLE + 2048 + 8 * COMPLq]
-
-  mov       Vq, V_PLANE                  ; Read V address from stack
-  SCALEUV   Vq                           ; Use the above macro to scale V
-  paddsw    mm0, [TABLE + 4096 + 8 * COMPLq]
-
-%macro SCALEY 0
-  mov       TEMPq, Xq
-  sar       TEMPq, 0x10
-  movzx     COMPLd, BYTE [Yq + TEMPq]
-  movzx     COMPRd, BYTE [Yq + TEMPq + 1]
-  mov       TEMPq, Xq
-  add       Xq, SOURCE_DX                 ; Add source_dx from stack
-  and       TEMPq, 0xffff
-  imul      COMPRq, TEMPq
-  xor       TEMPq, 0xffff
-  imul      COMPLq, TEMPq
-  add       COMPLq, COMPRq
-  shr       COMPLq, 16
-%endmacro
-  SCALEY                                  ; Use the above macro to scale Y1
-  movq      mm1, [TABLE + 8 * COMPLq]
-
-  cmp       Xq, SOURCE_WIDTH              ; Compare source_width from stack
-  jge       .lscalelastpixel
-
-  SCALEY                                  ; Use the above macro to sacle Y2
-  movq      mm2, [TABLE + 8 * COMPLq]
-
-  paddsw    mm1, mm0
-  paddsw    mm2, mm0
-  psraw     mm1, 0x6
-  psraw     mm2, 0x6
-  packuswb  mm1, mm2
-  MOVQ      [ARGBq], mm1
-  add       ARGBq, 0x8
-
-.lscaleend:
-  cmp       Xq, SOURCE_WIDTH     ; Compare source_width from stack
-  jl        .lscaleloop
-  EPILOGUE
-  RET
-
-.lscalelastpixel:
-  paddsw    mm1, mm0
-  psraw     mm1, 6
-  packuswb  mm1, mm1
-  movd      [ARGBq], mm1
-  EPILOGUE
-  RET
diff --git a/media/base/simd/linear_scale_yuv_to_rgb_mmx_x64.asm b/media/base/simd/linear_scale_yuv_to_rgb_mmx_x64.asm
deleted file mode 100644
index 969a1fde..0000000
--- a/media/base/simd/linear_scale_yuv_to_rgb_mmx_x64.asm
+++ /dev/null
@@ -1,152 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "media/base/simd/media_export.asm"
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX instructions.
-;
-  SECTION_TEXT
-  CPU       MMX
-
-;void LinearScaleYUVToRGB32Row_MMX_X64(const uint8_t* y_buf,
-;                                      const uint8_t* u_buf,
-;                                      const uint8_t* v_buf,
-;                                      uint8_t* rgb_buf,
-;                                      ptrdiff_t width,
-;                                      ptrdiff_t source_dx);
-%define SYMBOL LinearScaleYUVToRGB32Row_MMX_X64
-  EXPORT    SYMBOL
-  align     function_align
-
-mangle(SYMBOL):
-  %assign   stack_offset 0
-
-; Parameters are in the following order:
-; 1. Y plane
-; 2. U plane
-; 3. V plane
-; 4. ARGB frame
-; 5. Width
-; 6. Source dx
-; 7. Conversion lookup table
-
-PROLOGUE  7, 7, 3, Y, U, V, ARGB, WIDTH, SOURCE_DX, R1
-
-%define     TABLEq     r10
-%define     Xq         r11
-%define     INDEXq     r12
-%define     COMPRd     r13d
-%define     COMPRq     r13
-%define     FRACTIONq  r14
-%define     COMPL      R1
-%define     COMPLq     R1q
-%define     COMPLd     R1d
-
-  PUSH      TABLEq
-  PUSH      Xq
-  PUSH      INDEXq
-  PUSH      COMPRq
-  PUSH      FRACTIONq
-
-%macro EPILOGUE 0
-  POP       FRACTIONq
-  POP       COMPRq
-  POP       INDEXq
-  POP       Xq
-  POP       TABLEq
-%endmacro
-
-  mov       TABLEq, R1q
-
-  imul      WIDTHq, SOURCE_DXq           ; source_width = width * source_dx
-  xor       Xq, Xq                       ; x = 0
-  cmp       SOURCE_DXq, 0x20000
-  jl        .lscaleend
-  mov       Xq, 0x8000                   ; x = 0.5 for 1/2 or less
-  jmp       .lscaleend
-
-.lscaleloop:
-  ; Interpolate U
-  mov       INDEXq, Xq
-  sar       INDEXq, 0x11
-  movzx     COMPLd, BYTE [Uq + INDEXq]
-  movzx     COMPRd, BYTE [Uq + INDEXq + 1]
-  mov       FRACTIONq, Xq
-  and       FRACTIONq, 0x1fffe
-  imul      COMPRq, FRACTIONq
-  xor       FRACTIONq, 0x1fffe
-  imul      COMPLq, FRACTIONq
-  add       COMPLq, COMPRq
-  shr       COMPLq, 17
-  movq      mm0, [TABLEq + 2048 + 8 * COMPLq]
-
-  ; Interpolate V
-  movzx     COMPLd, BYTE [Vq + INDEXq]
-  movzx     COMPRd, BYTE [Vq + INDEXq + 1]
-  ; Trick here to imul COMPL first then COMPR.
-  ; Saves two instruction. :)
-  imul      COMPLq, FRACTIONq
-  xor       FRACTIONq, 0x1fffe
-  imul      COMPRq, FRACTIONq
-  add       COMPLq, COMPRq
-  shr       COMPLq, 17
-  paddsw    mm0, [TABLEq + 4096 + 8 * COMPLq]
-
-  ; Interpolate first Y1.
-  lea       INDEXq, [Xq + SOURCE_DXq]   ; INDEXq now points to next pixel.
-                                        ; Xq points to current pixel.
-  mov       FRACTIONq, Xq
-  sar       Xq, 0x10
-  movzx     COMPLd, BYTE [Yq + Xq]
-  movzx     COMPRd, BYTE [Yq + Xq + 1]
-  and       FRACTIONq, 0xffff
-  imul      COMPRq, FRACTIONq
-  xor       FRACTIONq, 0xffff
-  imul      COMPLq, FRACTIONq
-  add       COMPLq, COMPRq
-  shr       COMPLq, 16
-  movq      mm1, [TABLEq + 8 * COMPLq]
-
-  ; Interpolate Y2 if available.
-  cmp       INDEXq, WIDTHq
-  jge       .lscalelastpixel
-
-  lea       Xq, [INDEXq + SOURCE_DXq]    ; Xq points to next pixel.
-                                         ; INDEXq points to current pixel.
-  mov       FRACTIONq, INDEXq
-  sar       INDEXq, 0x10
-  movzx     COMPLd, BYTE [Yq + INDEXq]
-  movzx     COMPRd, BYTE [Yq + INDEXq + 1]
-  and       FRACTIONq, 0xffff
-  imul      COMPRq, FRACTIONq
-  xor       FRACTIONq, 0xffff
-  imul      COMPLq, FRACTIONq
-  add       COMPLq, COMPRq
-  shr       COMPLq, 16
-  movq      mm2, [TABLEq + 8 * COMPLq]
-
-  paddsw    mm1, mm0
-  paddsw    mm2, mm0
-  psraw     mm1, 0x6
-  psraw     mm2, 0x6
-  packuswb  mm1, mm2
-  movntq    [ARGBq], mm1
-  add       ARGBq, 0x8
-
-.lscaleend:
-  cmp       Xq, WIDTHq
-  jl        .lscaleloop
-  jmp       .epilogue
-
-.lscalelastpixel:
-  paddsw    mm1, mm0
-  psraw     mm1, 6
-  packuswb  mm1, mm1
-  movd      [ARGBq], mm1
-
-.epilogue
-  EPILOGUE
-  RET
diff --git a/media/base/simd/linear_scale_yuv_to_rgb_sse.asm b/media/base/simd/linear_scale_yuv_to_rgb_sse.asm
deleted file mode 100644
index 62ee9ac0..0000000
--- a/media/base/simd/linear_scale_yuv_to_rgb_sse.asm
+++ /dev/null
@@ -1,23 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX and SSE instructions.
-;
-  SECTION_TEXT
-  CPU       MMX, SSE
-
-; Use movq to save the output.
-%define MOVQ movntq
-
-; void LinearScaleYUVToRGB32Row_SSE(const uint8_t* y_buf,
-;                                   const uint8_t* u_buf,
-;                                   const uint8_t* v_buf,
-;                                   uint8_t* rgb_buf,
-;                                   ptrdiff_t width,
-;                                   ptrdiff_t source_dx);
-%define SYMBOL LinearScaleYUVToRGB32Row_SSE
-%include "linear_scale_yuv_to_rgb_mmx.inc"
diff --git a/media/base/simd/media_export.asm b/media/base/simd/media_export.asm
deleted file mode 100644
index e82be8d..0000000
--- a/media/base/simd/media_export.asm
+++ /dev/null
@@ -1,48 +0,0 @@
-; Copyright 2013 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-;
-; A set of helper macros for controlling symbol visibility.
-;
-
-%ifndef MEDIA_BASE_SIMD_MEDIA_EXPORT_ASM_
-%define MEDIA_BASE_SIMD_MEDIA_EXPORT_ASM_
-
-; Necessary for the mangle() macro.
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; PRIVATE
-; A flag representing the specified symbol is a private symbol. This define adds
-; a hidden flag on Linux and a private_extern flag on Mac. (We can use this
-; private_extern flag only on the latest yasm.)
-;
-%ifdef MACHO
-%define PRIVATE :private_extern
-%elifdef ELF
-%define PRIVATE :hidden
-%else
-%define PRIVATE
-%endif
-
-;
-; EXPORT %1
-; Designates a symbol as PRIVATE if EXPORT_SYMBOLS is not set.
-;
-%macro EXPORT 1
-%ifdef EXPORT_SYMBOLS
-global mangle(%1)
-
-; Windows needs an additional export declaration.
-%ifidn __OUTPUT_FORMAT__,win32
-export mangle(%1)
-%elifidn __OUTPUT_FORMAT__,win64
-export mangle(%1)
-%endif
-
-%else
-global mangle(%1) PRIVATE
-%endif
-%endmacro
-
-%endif  ; MEDIA_BASE_SIMD_MEDIA_EXPORT_ASM_
diff --git a/media/base/simd/scale_yuv_to_rgb_mmx.asm b/media/base/simd/scale_yuv_to_rgb_mmx.asm
deleted file mode 100644
index b21c12c5a..0000000
--- a/media/base/simd/scale_yuv_to_rgb_mmx.asm
+++ /dev/null
@@ -1,24 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX instructions.
-;
-  SECTION_TEXT
-  CPU       MMX
-
-; Use movq to save the output.
-%define MOVQ movq
-
-; void ScaleYUVToRGB32Row_MMX(const uint8_t* y_buf,
-;                             const uint8_t* u_buf,
-;                             const uint8_t* v_buf,
-;                             uint8_t* rgb_buf,
-;                             ptrdiff_t width,
-;                             ptrdiff_t source_dx);
-;                             const int16_t* convert_table);
-%define SYMBOL ScaleYUVToRGB32Row_MMX
-%include "scale_yuv_to_rgb_mmx.inc"
diff --git a/media/base/simd/scale_yuv_to_rgb_mmx.inc b/media/base/simd/scale_yuv_to_rgb_mmx.inc
deleted file mode 100644
index 42782cb..0000000
--- a/media/base/simd/scale_yuv_to_rgb_mmx.inc
+++ /dev/null
@@ -1,98 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "media/base/simd/media_export.asm"
-
-  EXPORT    SYMBOL
-  align     function_align
-
-mangle(SYMBOL):
-  %assign   stack_offset 0
-
-; Parameters are in the following order:
-; 1. Y plane
-; 2. U plane
-; 3. V plane
-; 4. ARGB frame
-; 5. Width
-; 6. Source dx
-; 7. Lookup table address
-
-PROLOGUE  7, 7, 3, Y, U, V, ARGB, R1, R2, TEMP
-
-%ifdef ARCH_X86_64
-%define     WORD_SIZE   QWORD
-%else
-%define     WORD_SIZE   DWORD
-%endif
-
-  PUSH      R1q  ; Width
-  PUSH      R2q  ; Source dx
-
-%define     SOURCE_DX   WORD_SIZE [rsp]
-
-  mov       R1q, TEMPq
-
-%define     WIDTH       WORD_SIZE [rsp + gprsize]
-%define     TABLE       R1q
-%define     Xq          R2q
-
-  ; Set Xq index to 0.
-  xor       Xq, Xq
-  jmp       .scaleend
-
-.scaleloop:
-  mov       TEMPq, Xq
-  sar       TEMPq, 17
-  movzx     TEMPd, BYTE [Uq + TEMPq]
-  movq      mm0, [TABLE + 2048 + 8 * TEMPq]
-  mov       TEMPq, Xq
-  sar       TEMPq, 17
-  movzx     TEMPd, BYTE [Vq + TEMPq]
-  paddsw    mm0, [TABLE + 4096 + 8 * TEMPq]
-  mov       TEMPq, Xq
-  add       Xq, SOURCE_DX
-  sar       TEMPq, 16
-  movzx     TEMPd, BYTE [Yq + TEMPq]
-  movq      mm1, [TABLE + 8 * TEMPq]
-  mov       TEMPq, Xq
-  add       Xq, SOURCE_DX
-  sar       TEMPq, 16
-  movzx     TEMPd, BYTE [Yq + TEMPq]
-  movq      mm2, [TABLE + 8 * TEMPq]
-  paddsw    mm1, mm0
-  paddsw    mm2, mm0
-  psraw     mm1, 6
-  psraw     mm2, 6
-  packuswb  mm1, mm2
-  MOVQ      QWORD [ARGBq], mm1
-  add       ARGBq, 8
-
-.scaleend:
-  sub       WIDTH, 2
-  jns       .scaleloop
-
-  and       WIDTH, 1             ; odd number of pixels?
-  jz        .scaledone
-
-  mov       TEMPq, Xq
-  sar       TEMPq, 17
-  movzx     TEMPd, BYTE [Uq + TEMPq]
-  movq      mm0, [TABLE + 2048 + 8 * TEMPq]
-  mov       TEMPq, Xq
-  sar       TEMPq, 17
-  movzx     TEMPd, BYTE [Vq + TEMPq]
-  paddsw    mm0, [TABLE + 4096 + 8 * TEMPq]
-  mov       TEMPq, Xq
-  sar       TEMPq, 16
-  movzx     TEMPd, BYTE [Yq + TEMPq]
-  movq      mm1, [TABLE + 8 * TEMPq]
-  paddsw    mm1, mm0
-  psraw     mm1, 6
-  packuswb  mm1, mm1
-  movd      DWORD [ARGBq], mm1
-
-.scaledone:
-  ADD       rsp, 2 * gprsize
-  RET
diff --git a/media/base/simd/scale_yuv_to_rgb_sse.asm b/media/base/simd/scale_yuv_to_rgb_sse.asm
deleted file mode 100644
index 34e0112..0000000
--- a/media/base/simd/scale_yuv_to_rgb_sse.asm
+++ /dev/null
@@ -1,24 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX and SSE instructions.
-;
-  SECTION_TEXT
-  CPU       MMX, SSE
-
-; Use movq to save the output.
-%define MOVQ movntq
-
-; void ScaleYUVToRGB32Row_SSE(const uint8_t* y_buf,
-;                             const uint8_t* u_buf,
-;                             const uint8_t* v_buf,
-;                             uint8_t* rgb_buf,
-;                             ptrdiff_t width,
-;                             ptrdiff_t source_dx);
-;                             const int16_t* convert_table);
-%define SYMBOL ScaleYUVToRGB32Row_SSE
-%include "scale_yuv_to_rgb_mmx.inc"
diff --git a/media/base/simd/scale_yuv_to_rgb_sse2_x64.asm b/media/base/simd/scale_yuv_to_rgb_sse2_x64.asm
deleted file mode 100644
index 9c52b8dc..0000000
--- a/media/base/simd/scale_yuv_to_rgb_sse2_x64.asm
+++ /dev/null
@@ -1,113 +0,0 @@
-; Copyright (c) 2011 The Chromium Authors. All rights reserved.
-; Use of this source code is governed by a BSD-style license that can be
-; found in the LICENSE file.
-
-%include "media/base/simd/media_export.asm"
-%include "third_party/x86inc/x86inc.asm"
-
-;
-; This file uses MMX, SSE2 and instructions.
-;
-  SECTION_TEXT
-  CPU       SSE2
-
-; void ScaleYUVToRGB32Row_SSE2_X64(const uint8_t* y_buf,
-;                                  const uint8_t* u_buf,
-;                                  const uint8_t* v_buf,
-;                                  uint8_t* rgb_buf,
-;                                  ptrdiff_t width,
-;                                  ptrdiff_t source_dx);
-%define SYMBOL ScaleYUVToRGB32Row_SSE2_X64
-  EXPORT    SYMBOL
-  align     function_align
-
-mangle(SYMBOL):
-  %assign   stack_offset 0
-
-; Parameters are in the following order:
-; 1. Y plane
-; 2. U plane
-; 3. V plane
-; 4. ARGB frame
-; 5. Width
-; 6. Source dx
-; 7. Convert table
-
-PROLOGUE  7, 7, 3, Y, U, V, ARGB, WIDTH, SOURCE_DX, R1
-
-%define     TABLEq   r10
-%define     Xq       r11
-%define     INDEXq   r12
-%define     COMPq    R1q
-%define     COMPd    R1d
-
-  PUSH      r10
-  PUSH      r11
-  PUSH      r12
-
-  mov TABLEq, R1q
-
-  ; Set Xq index to 0.
-  xor       Xq, Xq
-  jmp       .scaleend
-
-.scaleloop:
-  ; Read UV pixels.
-  mov       INDEXq, Xq
-  sar       INDEXq, 17
-  movzx     COMPd, BYTE [Uq + INDEXq]
-  movq      xmm0, [TABLEq + 2048 + 8 * COMPq]
-  movzx     COMPd, BYTE [Vq + INDEXq]
-  movq      xmm1, [TABLEq + 4096 + 8 * COMPq]
-
-  ; Read first Y pixel.
-  lea       INDEXq, [Xq + SOURCE_DXq] ; INDEXq nows points to next pixel.
-  sar       Xq, 16
-  movzx     COMPd, BYTE [Yq + Xq]
-  paddsw    xmm0, xmm1		      ; Hide a ADD after memory load.
-  movq      xmm1, [TABLEq + 8 * COMPq]
-
-  ;  Read next Y pixel.
-  lea       Xq, [INDEXq + SOURCE_DXq] ; Xq now points to next pixel.
-  sar       INDEXq, 16
-  movzx     COMPd, BYTE [Yq + INDEXq]
-  movq      xmm2, [TABLEq + 8 * COMPq]
-  paddsw    xmm1, xmm0
-  paddsw    xmm2, xmm0
-  shufps    xmm1, xmm2, 0x44          ; Join two pixels into one XMM register
-  psraw     xmm1, 6
-  packuswb  xmm1, xmm1
-  movq      QWORD [ARGBq], xmm1
-  add       ARGBq, 8
-
-.scaleend:
-  sub       WIDTHq, 2
-  jns       .scaleloop
-
-  and       WIDTHq, 1                 ; odd number of pixels?
-  jz        .scaledone
-
-  ; Read U V components.
-  mov       INDEXq, Xq
-  sar       INDEXq, 17
-  movzx     COMPd, BYTE [Uq + INDEXq]
-  movq      xmm0, [TABLEq + 2048 + 8 * COMPq]
-  movzx     COMPd, BYTE [Vq + INDEXq]
-  movq      xmm1, [TABLEq + 4096 + 8 * COMPq]
-  paddsw    xmm0, xmm1
-
-  ; Read one Y component.
-  mov       INDEXq, Xq
-  sar       INDEXq, 16
-  movzx     COMPd, BYTE [Yq + INDEXq]
-  movq      xmm1, [TABLEq + 8 * COMPq]
-  paddsw    xmm1, xmm0
-  psraw     xmm1, 6
-  packuswb  xmm1, xmm1
-  movd      DWORD [ARGBq], xmm1
-
-.scaledone:
-  POP       r12
-  POP       r11
-  POP       r10
-  RET
diff --git a/media/base/simd/xcode_hack.c b/media/base/simd/xcode_hack.c
deleted file mode 100644
index ee0b615..0000000
--- a/media/base/simd/xcode_hack.c
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// XCode doesn't want to link a pure assembly target and will fail
-// to link when it creates an empty file list.  So add a dummy file
-// keep the linker happy.  See http://crbug.com/157073
-int xcode_sucks() {
-  return 0;
-}
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index 815b7b75..1d400f6 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -14,8 +14,8 @@
 #include "base/memory/aligned_memory.h"
 #include "base/strings/stringprintf.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
-#include "media/base/yuv_convert.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libyuv/include/libyuv.h"
 
 namespace media {
 
@@ -64,16 +64,14 @@
                              VideoFrame::kFrameSizePadding,
                          VideoFrame::kFrameAddressAlignment));
 
-  media::ConvertYUVToRGB32(yv12_frame->data(VideoFrame::kYPlane),
-                           yv12_frame->data(VideoFrame::kUPlane),
-                           yv12_frame->data(VideoFrame::kVPlane),
-                           rgb_data,
-                           yv12_frame->coded_size().width(),
-                           yv12_frame->coded_size().height(),
-                           yv12_frame->stride(VideoFrame::kYPlane),
-                           yv12_frame->stride(VideoFrame::kUPlane),
-                           bytes_per_row,
-                           media::YV12);
+  libyuv::I420ToARGB(yv12_frame->data(VideoFrame::kYPlane),
+                     yv12_frame->stride(VideoFrame::kYPlane),
+                     yv12_frame->data(VideoFrame::kUPlane),
+                     yv12_frame->stride(VideoFrame::kUPlane),
+                     yv12_frame->data(VideoFrame::kVPlane),
+                     yv12_frame->stride(VideoFrame::kVPlane), rgb_data,
+                     bytes_per_row, yv12_frame->coded_size().width(),
+                     yv12_frame->coded_size().height());
 
   for (int row = 0; row < yv12_frame->coded_size().height(); ++row) {
     uint32_t* rgb_row_data =
diff --git a/media/base/video_util.cc b/media/base/video_util.cc
index d77b0084..1617389 100644
--- a/media/base/video_util.cc
+++ b/media/base/video_util.cc
@@ -11,7 +11,6 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/numerics/safe_math.h"
 #include "media/base/video_frame.h"
-#include "media/base/yuv_convert.h"
 #include "third_party/libyuv/include/libyuv.h"
 
 namespace media {
@@ -338,20 +337,15 @@
     LetterboxYUV(frame, region_in_frame);
   }
 
-  const int y_offset = region_in_frame.x()
-                     + (region_in_frame.y() * frame->stride(kY));
-  const int uv_offset = region_in_frame.x() / 2
-                      + (region_in_frame.y() / 2 * uv_stride);
+  const int y_offset =
+      region_in_frame.x() + (region_in_frame.y() * frame->stride(kY));
+  const int uv_offset =
+      region_in_frame.x() / 2 + (region_in_frame.y() / 2 * uv_stride);
 
-  ConvertRGB32ToYUV(source,
-                    frame->data(kY) + y_offset,
-                    frame->data(kU) + uv_offset,
-                    frame->data(kV) + uv_offset,
-                    region_in_frame.width(),
-                    region_in_frame.height(),
-                    stride,
-                    frame->stride(kY),
-                    uv_stride);
+  libyuv::ARGBToI420(source, stride, frame->data(kY) + y_offset,
+                     frame->stride(kY), frame->data(kU) + uv_offset, uv_stride,
+                     frame->data(kV) + uv_offset, uv_stride,
+                     region_in_frame.width(), region_in_frame.height());
 }
 
 scoped_refptr<VideoFrame> WrapAsI420VideoFrame(
diff --git a/media/base/win/mf_helpers.cc b/media/base/win/mf_helpers.cc
index e5df966..c88f571 100644
--- a/media/base/win/mf_helpers.cc
+++ b/media/base/win/mf_helpers.cc
@@ -13,12 +13,15 @@
              << line;
 }
 
-IMFSample* CreateEmptySampleWithBuffer(uint32_t buffer_length, int align) {
+base::win::ScopedComPtr<IMFSample> CreateEmptySampleWithBuffer(
+    uint32_t buffer_length,
+    int align) {
   CHECK_GT(buffer_length, 0U);
 
   base::win::ScopedComPtr<IMFSample> sample;
   HRESULT hr = MFCreateSample(sample.Receive());
-  RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL);
+  RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed",
+                       base::win::ScopedComPtr<IMFSample>());
 
   base::win::ScopedComPtr<IMFMediaBuffer> buffer;
   if (align == 0) {
@@ -29,13 +32,15 @@
     hr =
         MFCreateAlignedMemoryBuffer(buffer_length, align - 1, buffer.Receive());
   }
-  RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample", NULL);
+  RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample",
+                       base::win::ScopedComPtr<IMFSample>());
 
   hr = sample->AddBuffer(buffer.get());
-  RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample", NULL);
+  RETURN_ON_HR_FAILURE(hr, "Failed to add buffer to sample",
+                       base::win::ScopedComPtr<IMFSample>());
 
   buffer->SetCurrentLength(0);
-  return sample.Detach();
+  return sample;
 }
 
 MediaBufferScopedPointer::MediaBufferScopedPointer(IMFMediaBuffer* media_buffer)
@@ -54,4 +59,4 @@
 
 }  // namespace mf
 
-}  // namespace media
\ No newline at end of file
+}  // namespace media
diff --git a/media/base/win/mf_helpers.h b/media/base/win/mf_helpers.h
index a99eced..4877cbe 100644
--- a/media/base/win/mf_helpers.h
+++ b/media/base/win/mf_helpers.h
@@ -47,9 +47,8 @@
 
 // Creates a Media Foundation sample with one buffer of length |buffer_length|
 // on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0.
-MF_INITIALIZER_EXPORT IMFSample* CreateEmptySampleWithBuffer(
-    uint32_t buffer_length,
-    int align);
+MF_INITIALIZER_EXPORT base::win::ScopedComPtr<IMFSample>
+CreateEmptySampleWithBuffer(uint32_t buffer_length, int align);
 
 // Provides scoped access to the underlying buffer in an IMFMediaBuffer
 // instance.
@@ -74,4 +73,4 @@
 
 }  // namespace media
 
-#endif  // MEDIA_BASE_WIN_MF_HELPERS_H_
\ No newline at end of file
+#endif  // MEDIA_BASE_WIN_MF_HELPERS_H_
diff --git a/media/base/yuv_convert.cc b/media/base/yuv_convert.cc
deleted file mode 100644
index 2b156a7b..0000000
--- a/media/base/yuv_convert.cc
+++ /dev/null
@@ -1,734 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This webpage shows layout of YV12 and other YUV formats
-// http://www.fourcc.org/yuv.php
-// The actual conversion is best described here
-// http://en.wikipedia.org/wiki/YUV
-// An article on optimizing YUV conversion using tables instead of multiplies
-// http://lestourtereaux.free.fr/papers/data/yuvrgb.pdf
-//
-// YV12 is a full plane of Y and a half height, half width chroma planes
-// YV16 is a full plane of Y and a full height, half width chroma planes
-//
-// ARGB pixel format is output, which on little endian is stored as BGRA.
-// The alpha is set to 255, allowing the application to use RGBA or RGB32.
-
-#include "media/base/yuv_convert.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-
-#include "base/cpu.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/aligned_memory.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
-#include "build/build_config.h"
-#include "media/base/simd/convert_rgb_to_yuv.h"
-#include "media/base/simd/convert_yuv_to_rgb.h"
-#include "media/base/simd/filter_yuv.h"
-
-#if defined(ARCH_CPU_X86_FAMILY)
-#if defined(COMPILER_MSVC)
-#include <intrin.h>
-#else
-#include <mmintrin.h>
-#endif
-#endif
-
-// Assembly functions are declared without namespace.
-extern "C" { void EmptyRegisterState_MMX(); }  // extern "C"
-
-namespace media {
-
-typedef void (
-    *FilterYUVRowsProc)(uint8_t*, const uint8_t*, const uint8_t*, int, uint8_t);
-
-typedef void (*ConvertRGBToYUVProc)(const uint8_t*,
-                                    uint8_t*,
-                                    uint8_t*,
-                                    uint8_t*,
-                                    int,
-                                    int,
-                                    int,
-                                    int,
-                                    int);
-
-typedef void (*ConvertYUVToRGB32Proc)(const uint8_t*,
-                                      const uint8_t*,
-                                      const uint8_t*,
-                                      uint8_t*,
-                                      int,
-                                      int,
-                                      int,
-                                      int,
-                                      int,
-                                      YUVType);
-
-typedef void (*ConvertYUVAToARGBProc)(const uint8_t*,
-                                      const uint8_t*,
-                                      const uint8_t*,
-                                      const uint8_t*,
-                                      uint8_t*,
-                                      int,
-                                      int,
-                                      int,
-                                      int,
-                                      int,
-                                      int,
-                                      YUVType);
-
-typedef void (*ConvertYUVToRGB32RowProc)(const uint8_t*,
-                                         const uint8_t*,
-                                         const uint8_t*,
-                                         uint8_t*,
-                                         ptrdiff_t,
-                                         const int16_t*);
-
-typedef void (*ConvertYUVAToARGBRowProc)(const uint8_t*,
-                                         const uint8_t*,
-                                         const uint8_t*,
-                                         const uint8_t*,
-                                         uint8_t*,
-                                         ptrdiff_t,
-                                         const int16_t*);
-
-typedef void (*ScaleYUVToRGB32RowProc)(const uint8_t*,
-                                       const uint8_t*,
-                                       const uint8_t*,
-                                       uint8_t*,
-                                       ptrdiff_t,
-                                       ptrdiff_t,
-                                       const int16_t*);
-
-static FilterYUVRowsProc g_filter_yuv_rows_proc_ = NULL;
-static ConvertYUVToRGB32RowProc g_convert_yuv_to_rgb32_row_proc_ = NULL;
-static ScaleYUVToRGB32RowProc g_scale_yuv_to_rgb32_row_proc_ = NULL;
-static ScaleYUVToRGB32RowProc g_linear_scale_yuv_to_rgb32_row_proc_ = NULL;
-static ConvertRGBToYUVProc g_convert_rgb32_to_yuv_proc_ = NULL;
-static ConvertRGBToYUVProc g_convert_rgb24_to_yuv_proc_ = NULL;
-static ConvertYUVToRGB32Proc g_convert_yuv_to_rgb32_proc_ = NULL;
-static ConvertYUVAToARGBProc g_convert_yuva_to_argb_proc_ = NULL;
-
-static const int kYUVToRGBTableSize = 256 * 4 * 4 * sizeof(int16_t);
-
-static int16_t* g_table_rec601 = NULL;
-static int16_t* g_table_jpeg = NULL;
-static int16_t* g_table_rec709 = NULL;
-
-// Empty SIMD registers state after using them.
-void EmptyRegisterStateStub() {}
-#if defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
-void EmptyRegisterStateIntrinsic() { _mm_empty(); }
-#endif
-typedef void (*EmptyRegisterStateProc)();
-static EmptyRegisterStateProc g_empty_register_state_proc_ = NULL;
-
-// Get the appropriate value to bitshift by for vertical indices.
-int GetVerticalShift(YUVType type) {
-  switch (type) {
-    case YV16:
-      return 0;
-    case YV12:
-    case YV12J:
-    case YV12HD:
-      return 1;
-  }
-  NOTREACHED();
-  return 0;
-}
-
-const int16_t* GetLookupTable(YUVType type) {
-  switch (type) {
-    case YV12:
-    case YV16:
-      return g_table_rec601;
-    case YV12J:
-      return g_table_jpeg;
-    case YV12HD:
-      return g_table_rec709;
-  }
-  NOTREACHED();
-  return NULL;
-}
-
-// Populates a pre-allocated lookup table from a YUV->RGB matrix.
-const int16_t* PopulateYUVToRGBTable(const double matrix[3][3],
-                                     bool full_range,
-                                     int16_t* table) {
-  // We'll have 4 sub-tables that lie contiguous in memory, one for each of Y,
-  // U, V and A.
-  const int kNumTables = 4;
-  // Each table has 256 rows (for all possible 8-bit values).
-  const int kNumRows = 256;
-  // Each row has 4 columns, for contributions to each of R, G, B and A.
-  const int kNumColumns = 4;
-  // Each element is a fixed-point (10.6) 16-bit signed value.
-  const int kElementSize = sizeof(int16_t);
-
-  // Sanity check that our constants here match the size of the statically
-  // allocated tables.
-  static_assert(
-      kNumTables * kNumRows * kNumColumns * kElementSize == kYUVToRGBTableSize,
-      "YUV lookup table size doesn't match expectation.");
-
-  // Y needs an offset of -16 for color ranges that ignore the lower 16 values,
-  // U and V get -128 to put them in [-128, 127] from [0, 255].
-  int offsets[3] = {(full_range ? 0 : -16), -128, -128};
-
-  for (int i = 0; i < kNumRows; ++i) {
-    // Y, U, and V contributions to each of R, G, B and A.
-    for (int j = 0; j < 3; ++j) {
-#if defined(OS_ANDROID)
-      // Android is RGBA.
-      table[(j * kNumRows + i) * kNumColumns + 0] =
-          matrix[j][0] * 64 * (i + offsets[j]) + 0.5;
-      table[(j * kNumRows + i) * kNumColumns + 1] =
-          matrix[j][1] * 64 * (i + offsets[j]) + 0.5;
-      table[(j * kNumRows + i) * kNumColumns + 2] =
-          matrix[j][2] * 64 * (i + offsets[j]) + 0.5;
-#else
-      // Other platforms are BGRA.
-      table[(j * kNumRows + i) * kNumColumns + 0] =
-          matrix[j][2] * 64 * (i + offsets[j]) + 0.5;
-      table[(j * kNumRows + i) * kNumColumns + 1] =
-          matrix[j][1] * 64 * (i + offsets[j]) + 0.5;
-      table[(j * kNumRows + i) * kNumColumns + 2] =
-          matrix[j][0] * 64 * (i + offsets[j]) + 0.5;
-#endif
-      // Alpha contributions from Y and V are always 0. U is set such that
-      // all values result in a full '255' alpha value.
-      table[(j * kNumRows + i) * kNumColumns + 3] = (j == 1) ? 256 * 64 - 1 : 0;
-    }
-    // And YUVA alpha is passed through as-is.
-    for (int k = 0; k < kNumTables; ++k)
-      table[((kNumTables - 1) * kNumRows + i) * kNumColumns + k] = i;
-  }
-
-  return table;
-}
-
-void InitializeCPUSpecificYUVConversions() {
-  CHECK(!g_filter_yuv_rows_proc_);
-  CHECK(!g_convert_yuv_to_rgb32_row_proc_);
-  CHECK(!g_scale_yuv_to_rgb32_row_proc_);
-  CHECK(!g_linear_scale_yuv_to_rgb32_row_proc_);
-  CHECK(!g_convert_rgb32_to_yuv_proc_);
-  CHECK(!g_convert_rgb24_to_yuv_proc_);
-  CHECK(!g_convert_yuv_to_rgb32_proc_);
-  CHECK(!g_convert_yuva_to_argb_proc_);
-  CHECK(!g_empty_register_state_proc_);
-
-  g_filter_yuv_rows_proc_ = FilterYUVRows_C;
-  g_convert_yuv_to_rgb32_row_proc_ = ConvertYUVToRGB32Row_C;
-  g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_C;
-  g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_C;
-  g_convert_rgb32_to_yuv_proc_ = ConvertRGB32ToYUV_C;
-  g_convert_rgb24_to_yuv_proc_ = ConvertRGB24ToYUV_C;
-  g_convert_yuv_to_rgb32_proc_ = ConvertYUVToRGB32_C;
-  g_convert_yuva_to_argb_proc_ = ConvertYUVAToARGB_C;
-  g_empty_register_state_proc_ = EmptyRegisterStateStub;
-
-  // Assembly code confuses MemorySanitizer. Also not available in iOS builds.
-#if defined(ARCH_CPU_X86_FAMILY) && !defined(MEMORY_SANITIZER) && \
-    !defined(OS_IOS)
-  g_convert_yuva_to_argb_proc_ = ConvertYUVAToARGB_MMX;
-
-#if defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
-  g_empty_register_state_proc_ = EmptyRegisterStateIntrinsic;
-#else
-  g_empty_register_state_proc_ = EmptyRegisterState_MMX;
-#endif
-
-  g_convert_yuv_to_rgb32_row_proc_ = ConvertYUVToRGB32Row_SSE;
-  g_convert_yuv_to_rgb32_proc_ = ConvertYUVToRGB32_SSE;
-
-  g_filter_yuv_rows_proc_ = FilterYUVRows_SSE2;
-  g_convert_rgb32_to_yuv_proc_ = ConvertRGB32ToYUV_SSE2;
-
-#if defined(ARCH_CPU_X86_64)
-  g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_SSE2_X64;
-
-  // Technically this should be in the MMX section, but MSVC will optimize out
-  // the export of LinearScaleYUVToRGB32Row_MMX, which is required by the unit
-  // tests, if that decision can be made at compile time.  Since all X64 CPUs
-  // have SSE2, we can hack around this by making the selection here.
-  g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_MMX_X64;
-#else
-  g_scale_yuv_to_rgb32_row_proc_ = ScaleYUVToRGB32Row_SSE;
-  g_linear_scale_yuv_to_rgb32_row_proc_ = LinearScaleYUVToRGB32Row_SSE;
-#endif
-
-  base::CPU cpu;
-  if (cpu.has_ssse3()) {
-    g_convert_rgb24_to_yuv_proc_ = &ConvertRGB24ToYUV_SSSE3;
-
-    // TODO(hclam): Add ConvertRGB32ToYUV_SSSE3 when the cyan problem is solved.
-    // See: crbug.com/100462
-  }
-#endif
-
-  // Initialize YUV conversion lookup tables.
-
-  // SD Rec601 YUV->RGB matrix, see http://www.fourcc.org/fccyvrgb.php
-  const double kRec601ConvertMatrix[3][3] = {
-      {1.164, 1.164, 1.164}, {0.0, -0.391, 2.018}, {1.596, -0.813, 0.0},
-  };
-
-  // JPEG table, values from above link.
-  const double kJPEGConvertMatrix[3][3] = {
-      {1.0, 1.0, 1.0}, {0.0, -0.34414, 1.772}, {1.402, -0.71414, 0.0},
-  };
-
-  // Rec709 "HD" color space, values from:
-  // http://www.equasys.de/colorconversion.html
-  const double kRec709ConvertMatrix[3][3] = {
-      {1.164, 1.164, 1.164}, {0.0, -0.213, 2.112}, {1.793, -0.533, 0.0},
-  };
-
-  g_table_rec601 =
-      static_cast<int16_t*>(base::AlignedAlloc(kYUVToRGBTableSize, 16));
-  PopulateYUVToRGBTable(kRec601ConvertMatrix, false, g_table_rec601);
-
-  g_table_rec709 =
-      static_cast<int16_t*>(base::AlignedAlloc(kYUVToRGBTableSize, 16));
-  PopulateYUVToRGBTable(kRec709ConvertMatrix, false, g_table_rec709);
-
-  g_table_jpeg =
-      static_cast<int16_t*>(base::AlignedAlloc(kYUVToRGBTableSize, 16));
-  PopulateYUVToRGBTable(kJPEGConvertMatrix, true, g_table_jpeg);
-}
-
-// Empty SIMD registers state after using them.
-void EmptyRegisterState() { g_empty_register_state_proc_(); }
-
-// 16.16 fixed point arithmetic
-const int kFractionBits = 16;
-const int kFractionMax = 1 << kFractionBits;
-const int kFractionMask = ((1 << kFractionBits) - 1);
-
-// Scale a frame of YUV to 32 bit ARGB.
-void ScaleYUVToRGB32(const uint8_t* y_buf,
-                     const uint8_t* u_buf,
-                     const uint8_t* v_buf,
-                     uint8_t* rgb_buf,
-                     int source_width,
-                     int source_height,
-                     int width,
-                     int height,
-                     int y_pitch,
-                     int uv_pitch,
-                     int rgb_pitch,
-                     YUVType yuv_type,
-                     Rotate view_rotate,
-                     ScaleFilter filter) {
-  // Handle zero sized sources and destinations.
-  if ((yuv_type == YV12 && (source_width < 2 || source_height < 2)) ||
-      (yuv_type == YV16 && (source_width < 2 || source_height < 1)) ||
-      width == 0 || height == 0)
-    return;
-
-  const int16_t* lookup_table = GetLookupTable(yuv_type);
-
-  // 4096 allows 3 buffers to fit in 12k.
-  // Helps performance on CPU with 16K L1 cache.
-  // Large enough for 3830x2160 and 30" displays which are 2560x1600.
-  const int kFilterBufferSize = 4096;
-  // Disable filtering if the screen is too big (to avoid buffer overflows).
-  // This should never happen to regular users: they don't have monitors
-  // wider than 4096 pixels.
-  // TODO(fbarchard): Allow rotated videos to filter.
-  if (source_width > kFilterBufferSize || view_rotate)
-    filter = FILTER_NONE;
-
-  unsigned int y_shift = GetVerticalShift(yuv_type);
-  // Diagram showing origin and direction of source sampling.
-  // ->0   4<-
-  // 7       3
-  //
-  // 6       5
-  // ->1   2<-
-  // Rotations that start at right side of image.
-  if ((view_rotate == ROTATE_180) || (view_rotate == ROTATE_270) ||
-      (view_rotate == MIRROR_ROTATE_0) || (view_rotate == MIRROR_ROTATE_90)) {
-    y_buf += source_width - 1;
-    u_buf += source_width / 2 - 1;
-    v_buf += source_width / 2 - 1;
-    source_width = -source_width;
-  }
-  // Rotations that start at bottom of image.
-  if ((view_rotate == ROTATE_90) || (view_rotate == ROTATE_180) ||
-      (view_rotate == MIRROR_ROTATE_90) || (view_rotate == MIRROR_ROTATE_180)) {
-    y_buf += (source_height - 1) * y_pitch;
-    u_buf += ((source_height >> y_shift) - 1) * uv_pitch;
-    v_buf += ((source_height >> y_shift) - 1) * uv_pitch;
-    source_height = -source_height;
-  }
-
-  int source_dx = source_width * kFractionMax / width;
-
-  if ((view_rotate == ROTATE_90) || (view_rotate == ROTATE_270)) {
-    int tmp = height;
-    height = width;
-    width = tmp;
-    tmp = source_height;
-    source_height = source_width;
-    source_width = tmp;
-    int source_dy = source_height * kFractionMax / height;
-    source_dx = ((source_dy >> kFractionBits) * y_pitch) << kFractionBits;
-    if (view_rotate == ROTATE_90) {
-      y_pitch = -1;
-      uv_pitch = -1;
-      source_height = -source_height;
-    } else {
-      y_pitch = 1;
-      uv_pitch = 1;
-    }
-  }
-
-  // Need padding because FilterRows() will write 1 to 16 extra pixels
-  // after the end for SSE2 version.
-  uint8_t yuvbuf[16 + kFilterBufferSize * 3 + 16];
-  uint8_t* ybuf = reinterpret_cast<uint8_t*>(
-      reinterpret_cast<uintptr_t>(yuvbuf + 15) & ~15);
-  uint8_t* ubuf = ybuf + kFilterBufferSize;
-  uint8_t* vbuf = ubuf + kFilterBufferSize;
-
-  // TODO(fbarchard): Fixed point math is off by 1 on negatives.
-
-  // We take a y-coordinate in [0,1] space in the source image space, and
-  // transform to a y-coordinate in [0,1] space in the destination image space.
-  // Note that the coordinate endpoints lie on pixel boundaries, not on pixel
-  // centers: e.g. a two-pixel-high image will have pixel centers at 0.25 and
-  // 0.75.  The formula is as follows (in fixed-point arithmetic):
-  //   y_dst = dst_height * ((y_src + 0.5) / src_height)
-  //   dst_pixel = clamp([0, dst_height - 1], floor(y_dst - 0.5))
-  // Implement this here as an accumulator + delta, to avoid expensive math
-  // in the loop.
-  int source_y_subpixel_accum =
-      ((kFractionMax / 2) * source_height) / height - (kFractionMax / 2);
-  int source_y_subpixel_delta = ((1 << kFractionBits) * source_height) / height;
-
-  // TODO(fbarchard): Split this into separate function for better efficiency.
-  for (int y = 0; y < height; ++y) {
-    uint8_t* dest_pixel = rgb_buf + y * rgb_pitch;
-    int source_y_subpixel = source_y_subpixel_accum;
-    source_y_subpixel_accum += source_y_subpixel_delta;
-    if (source_y_subpixel < 0)
-      source_y_subpixel = 0;
-    else if (source_y_subpixel > ((source_height - 1) << kFractionBits))
-      source_y_subpixel = (source_height - 1) << kFractionBits;
-
-    const uint8_t* y_ptr = NULL;
-    const uint8_t* u_ptr = NULL;
-    const uint8_t* v_ptr = NULL;
-    // Apply vertical filtering if necessary.
-    // TODO(fbarchard): Remove memcpy when not necessary.
-    if (filter & media::FILTER_BILINEAR_V) {
-      int source_y = source_y_subpixel >> kFractionBits;
-      y_ptr = y_buf + source_y * y_pitch;
-      u_ptr = u_buf + (source_y >> y_shift) * uv_pitch;
-      v_ptr = v_buf + (source_y >> y_shift) * uv_pitch;
-
-      // Vertical scaler uses 16.8 fixed point.
-      uint8_t source_y_fraction = (source_y_subpixel & kFractionMask) >> 8;
-      if (source_y_fraction != 0) {
-        g_filter_yuv_rows_proc_(
-            ybuf, y_ptr, y_ptr + y_pitch, source_width, source_y_fraction);
-      } else {
-        memcpy(ybuf, y_ptr, source_width);
-      }
-      y_ptr = ybuf;
-      ybuf[source_width] = ybuf[source_width - 1];
-
-      int uv_source_width = (source_width + 1) / 2;
-      uint8_t source_uv_fraction;
-
-      // For formats with half-height UV planes, each even-numbered pixel row
-      // should not interpolate, since the next row to interpolate from should
-      // be a duplicate of the current row.
-      if (y_shift && (source_y & 0x1) == 0)
-        source_uv_fraction = 0;
-      else
-        source_uv_fraction = source_y_fraction;
-
-      if (source_uv_fraction != 0) {
-        g_filter_yuv_rows_proc_(
-            ubuf, u_ptr, u_ptr + uv_pitch, uv_source_width, source_uv_fraction);
-        g_filter_yuv_rows_proc_(
-            vbuf, v_ptr, v_ptr + uv_pitch, uv_source_width, source_uv_fraction);
-      } else {
-        memcpy(ubuf, u_ptr, uv_source_width);
-        memcpy(vbuf, v_ptr, uv_source_width);
-      }
-      u_ptr = ubuf;
-      v_ptr = vbuf;
-      ubuf[uv_source_width] = ubuf[uv_source_width - 1];
-      vbuf[uv_source_width] = vbuf[uv_source_width - 1];
-    } else {
-      // Offset by 1/2 pixel for center sampling.
-      int source_y = (source_y_subpixel + (kFractionMax / 2)) >> kFractionBits;
-      y_ptr = y_buf + source_y * y_pitch;
-      u_ptr = u_buf + (source_y >> y_shift) * uv_pitch;
-      v_ptr = v_buf + (source_y >> y_shift) * uv_pitch;
-    }
-    if (source_dx == kFractionMax) {  // Not scaled
-      g_convert_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel, width,
-                                       lookup_table);
-    } else {
-      if (filter & FILTER_BILINEAR_H) {
-        g_linear_scale_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel,
-                                              width, source_dx,
-                                              lookup_table);
-      } else {
-        g_scale_yuv_to_rgb32_row_proc_(y_ptr, u_ptr, v_ptr, dest_pixel, width,
-                                       source_dx, lookup_table);
-      }
-    }
-  }
-
-  g_empty_register_state_proc_();
-}
-
-// Scale a frame of YV12 to 32 bit ARGB for a specific rectangle.
-void ScaleYUVToRGB32WithRect(const uint8_t* y_buf,
-                             const uint8_t* u_buf,
-                             const uint8_t* v_buf,
-                             uint8_t* rgb_buf,
-                             int source_width,
-                             int source_height,
-                             int dest_width,
-                             int dest_height,
-                             int dest_rect_left,
-                             int dest_rect_top,
-                             int dest_rect_right,
-                             int dest_rect_bottom,
-                             int y_pitch,
-                             int uv_pitch,
-                             int rgb_pitch) {
-  // This routine doesn't currently support up-scaling.
-  CHECK_LE(dest_width, source_width);
-  CHECK_LE(dest_height, source_height);
-
-  // Sanity-check the destination rectangle.
-  DCHECK(dest_rect_left >= 0 && dest_rect_right <= dest_width);
-  DCHECK(dest_rect_top >= 0 && dest_rect_bottom <= dest_height);
-  DCHECK(dest_rect_right > dest_rect_left);
-  DCHECK(dest_rect_bottom > dest_rect_top);
-
-  const int16_t* lookup_table = GetLookupTable(YV12);
-
-  // Fixed-point value of vertical and horizontal scale down factor.
-  // Values are in the format 16.16.
-  int y_step = kFractionMax * source_height / dest_height;
-  int x_step = kFractionMax * source_width / dest_width;
-
-  // Determine the coordinates of the rectangle in 16.16 coords.
-  // NB: Our origin is the *center* of the top/left pixel, NOT its top/left.
-  // If we're down-scaling by more than a factor of two, we start with a 50%
-  // fraction to avoid degenerating to point-sampling - we should really just
-  // fix the fraction at 50% for all pixels in that case.
-  int source_left = dest_rect_left * x_step;
-  int source_right = (dest_rect_right - 1) * x_step;
-  if (x_step < kFractionMax * 2) {
-    source_left += ((x_step - kFractionMax) / 2);
-    source_right += ((x_step - kFractionMax) / 2);
-  } else {
-    source_left += kFractionMax / 2;
-    source_right += kFractionMax / 2;
-  }
-  int source_top = dest_rect_top * y_step;
-  if (y_step < kFractionMax * 2) {
-    source_top += ((y_step - kFractionMax) / 2);
-  } else {
-    source_top += kFractionMax / 2;
-  }
-
-  // Determine the parts of the Y, U and V buffers to interpolate.
-  int source_y_left = source_left >> kFractionBits;
-  int source_y_right =
-      std::min((source_right >> kFractionBits) + 2, source_width + 1);
-
-  int source_uv_left = source_y_left / 2;
-  int source_uv_right = std::min((source_right >> (kFractionBits + 1)) + 2,
-                                 (source_width + 1) / 2);
-
-  int source_y_width = source_y_right - source_y_left;
-  int source_uv_width = source_uv_right - source_uv_left;
-
-  // Determine number of pixels in each output row.
-  int dest_rect_width = dest_rect_right - dest_rect_left;
-
-  // Intermediate buffer for vertical interpolation.
-  // 4096 bytes allows 3 buffers to fit in 12k, which fits in a 16K L1 cache,
-  // and is bigger than most users will generally need.
-  // The buffer is 16-byte aligned and padded with 16 extra bytes; some of the
-  // FilterYUVRowsProcs have alignment requirements, and the SSE version can
-  // write up to 16 bytes past the end of the buffer.
-  const int kFilterBufferSize = 4096;
-  const bool kAvoidUsingOptimizedFilter = source_width > kFilterBufferSize;
-  uint8_t yuv_temp[16 + kFilterBufferSize * 3 + 16];
-  // memset() yuv_temp to 0 to avoid bogus warnings when running on Valgrind.
-  if (RunningOnValgrind())
-    memset(yuv_temp, 0, sizeof(yuv_temp));
-  uint8_t* y_temp = reinterpret_cast<uint8_t*>(
-      reinterpret_cast<uintptr_t>(yuv_temp + 15) & ~15);
-  uint8_t* u_temp = y_temp + kFilterBufferSize;
-  uint8_t* v_temp = u_temp + kFilterBufferSize;
-
-  // Move to the top-left pixel of output.
-  rgb_buf += dest_rect_top * rgb_pitch;
-  rgb_buf += dest_rect_left * 4;
-
-  // For each destination row perform interpolation and color space
-  // conversion to produce the output.
-  for (int row = dest_rect_top; row < dest_rect_bottom; ++row) {
-    // Round the fixed-point y position to get the current row.
-    int source_row = source_top >> kFractionBits;
-    int source_uv_row = source_row / 2;
-    DCHECK(source_row < source_height);
-
-    // Locate the first row for each plane for interpolation.
-    const uint8_t* y0_ptr = y_buf + y_pitch * source_row + source_y_left;
-    const uint8_t* u0_ptr = u_buf + uv_pitch * source_uv_row + source_uv_left;
-    const uint8_t* v0_ptr = v_buf + uv_pitch * source_uv_row + source_uv_left;
-    const uint8_t* y1_ptr = NULL;
-    const uint8_t* u1_ptr = NULL;
-    const uint8_t* v1_ptr = NULL;
-
-    // Locate the second row for interpolation, being careful not to overrun.
-    if (source_row + 1 >= source_height) {
-      y1_ptr = y0_ptr;
-    } else {
-      y1_ptr = y0_ptr + y_pitch;
-    }
-    if (source_uv_row + 1 >= (source_height + 1) / 2) {
-      u1_ptr = u0_ptr;
-      v1_ptr = v0_ptr;
-    } else {
-      u1_ptr = u0_ptr + uv_pitch;
-      v1_ptr = v0_ptr + uv_pitch;
-    }
-
-    if (!kAvoidUsingOptimizedFilter) {
-      // Vertical scaler uses 16.8 fixed point.
-      uint8_t fraction = (source_top & kFractionMask) >> 8;
-      g_filter_yuv_rows_proc_(
-          y_temp + source_y_left, y0_ptr, y1_ptr, source_y_width, fraction);
-      g_filter_yuv_rows_proc_(
-          u_temp + source_uv_left, u0_ptr, u1_ptr, source_uv_width, fraction);
-      g_filter_yuv_rows_proc_(
-          v_temp + source_uv_left, v0_ptr, v1_ptr, source_uv_width, fraction);
-
-      // Perform horizontal interpolation and color space conversion.
-      // TODO(hclam): Use the MMX version after more testing.
-      LinearScaleYUVToRGB32RowWithRange_C(y_temp, u_temp, v_temp, rgb_buf,
-                                          dest_rect_width, source_left, x_step,
-                                          lookup_table);
-    } else {
-      // If the frame is too large then we linear scale a single row.
-      LinearScaleYUVToRGB32RowWithRange_C(y0_ptr, u0_ptr, v0_ptr, rgb_buf,
-                                          dest_rect_width, source_left, x_step,
-                                          lookup_table);
-    }
-
-    // Advance vertically in the source and destination image.
-    source_top += y_step;
-    rgb_buf += rgb_pitch;
-  }
-
-  g_empty_register_state_proc_();
-}
-
-void ConvertRGB32ToYUV(const uint8_t* rgbframe,
-                       uint8_t* yplane,
-                       uint8_t* uplane,
-                       uint8_t* vplane,
-                       int width,
-                       int height,
-                       int rgbstride,
-                       int ystride,
-                       int uvstride) {
-  g_convert_rgb32_to_yuv_proc_(rgbframe,
-                               yplane,
-                               uplane,
-                               vplane,
-                               width,
-                               height,
-                               rgbstride,
-                               ystride,
-                               uvstride);
-}
-
-void ConvertRGB24ToYUV(const uint8_t* rgbframe,
-                       uint8_t* yplane,
-                       uint8_t* uplane,
-                       uint8_t* vplane,
-                       int width,
-                       int height,
-                       int rgbstride,
-                       int ystride,
-                       int uvstride) {
-  g_convert_rgb24_to_yuv_proc_(rgbframe,
-                               yplane,
-                               uplane,
-                               vplane,
-                               width,
-                               height,
-                               rgbstride,
-                               ystride,
-                               uvstride);
-}
-
-void ConvertYUVToRGB32(const uint8_t* yplane,
-                       const uint8_t* uplane,
-                       const uint8_t* vplane,
-                       uint8_t* rgbframe,
-                       int width,
-                       int height,
-                       int ystride,
-                       int uvstride,
-                       int rgbstride,
-                       YUVType yuv_type) {
-  g_convert_yuv_to_rgb32_proc_(yplane,
-                               uplane,
-                               vplane,
-                               rgbframe,
-                               width,
-                               height,
-                               ystride,
-                               uvstride,
-                               rgbstride,
-                               yuv_type);
-}
-
-void ConvertYUVAToARGB(const uint8_t* yplane,
-                       const uint8_t* uplane,
-                       const uint8_t* vplane,
-                       const uint8_t* aplane,
-                       uint8_t* rgbframe,
-                       int width,
-                       int height,
-                       int ystride,
-                       int uvstride,
-                       int astride,
-                       int rgbstride,
-                       YUVType yuv_type) {
-  g_convert_yuva_to_argb_proc_(yplane,
-                               uplane,
-                               vplane,
-                               aplane,
-                               rgbframe,
-                               width,
-                               height,
-                               ystride,
-                               uvstride,
-                               astride,
-                               rgbstride,
-                               yuv_type);
-}
-
-}  // namespace media
diff --git a/media/base/yuv_convert.h b/media/base/yuv_convert.h
deleted file mode 100644
index e10ca7d7..0000000
--- a/media/base/yuv_convert.h
+++ /dev/null
@@ -1,152 +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 MEDIA_BASE_YUV_CONVERT_H_
-#define MEDIA_BASE_YUV_CONVERT_H_
-
-#include <stdint.h>
-
-#include "build/build_config.h"
-#include "media/base/media_export.h"
-
-// Visual Studio 2010 does not support MMX intrinsics on x64.
-// Some win64 yuv_convert code paths use SSE+MMX yasm, so without rewriting
-// them, we use yasm EmptyRegisterState_MMX in place of _mm_empty() or
-// hide the versions implemented with heavy use of MMX intrinsics.
-// TODO(wolenetz): Use MMX intrinsics when compiling win64 with Visual
-// Studio 2012? http://crbug.com/173450
-#if defined(ARCH_CPU_X86_FAMILY) && \
-    !(defined(ARCH_CPU_X86_64) && defined(COMPILER_MSVC))
-#define MEDIA_MMX_INTRINSICS_AVAILABLE
-#endif
-
-namespace media {
-
-// Type of YUV surface.
-enum YUVType {
-  YV16 = 0,    // YV16 is half width and full height chroma channels.
-  YV12 = 1,    // YV12 is half width and half height chroma channels.
-  YV12J = 2,   // YV12J is the same as YV12, but in JPEG color range.
-  YV12HD = 3,  // YV12HD is the same as YV12, but in 'HD' Rec709 color space.
-};
-
-// Get the appropriate value to bitshift by for vertical indices.
-MEDIA_EXPORT int GetVerticalShift(YUVType type);
-
-// Get the appropriate lookup table for a given YUV format.
-MEDIA_EXPORT const int16_t* GetLookupTable(YUVType type);
-
-// Mirror means flip the image horizontally, as in looking in a mirror.
-// Rotate happens after mirroring.
-enum Rotate {
-  ROTATE_0,           // Rotation off.
-  ROTATE_90,          // Rotate clockwise.
-  ROTATE_180,         // Rotate upside down.
-  ROTATE_270,         // Rotate counter clockwise.
-  MIRROR_ROTATE_0,    // Mirror horizontally.
-  MIRROR_ROTATE_90,   // Mirror then Rotate clockwise.
-  MIRROR_ROTATE_180,  // Mirror vertically.
-  MIRROR_ROTATE_270,  // Transpose.
-};
-
-// Filter affects how scaling looks.
-enum ScaleFilter {
-  FILTER_NONE = 0,        // No filter (point sampled).
-  FILTER_BILINEAR_H = 1,  // Bilinear horizontal filter.
-  FILTER_BILINEAR_V = 2,  // Bilinear vertical filter.
-  FILTER_BILINEAR = 3,    // Bilinear filter.
-};
-
-MEDIA_EXPORT void InitializeCPUSpecificYUVConversions();
-
-// Convert a frame of YUV to 32 bit ARGB.
-// Pass in YV16/YV12 depending on source format
-MEDIA_EXPORT void ConvertYUVToRGB32(const uint8_t* yplane,
-                                    const uint8_t* uplane,
-                                    const uint8_t* vplane,
-                                    uint8_t* rgbframe,
-                                    int width,
-                                    int height,
-                                    int ystride,
-                                    int uvstride,
-                                    int rgbstride,
-                                    YUVType yuv_type);
-
-// Convert a frame of YUVA to 32 bit ARGB.
-// Pass in YV12A
-MEDIA_EXPORT void ConvertYUVAToARGB(const uint8_t* yplane,
-                                    const uint8_t* uplane,
-                                    const uint8_t* vplane,
-                                    const uint8_t* aplane,
-                                    uint8_t* rgbframe,
-                                    int width,
-                                    int height,
-                                    int ystride,
-                                    int uvstride,
-                                    int astride,
-                                    int rgbstride,
-                                    YUVType yuv_type);
-
-// Scale a frame of YUV to 32 bit ARGB.
-// Supports rotation and mirroring.
-MEDIA_EXPORT void ScaleYUVToRGB32(const uint8_t* yplane,
-                                  const uint8_t* uplane,
-                                  const uint8_t* vplane,
-                                  uint8_t* rgbframe,
-                                  int source_width,
-                                  int source_height,
-                                  int width,
-                                  int height,
-                                  int ystride,
-                                  int uvstride,
-                                  int rgbstride,
-                                  YUVType yuv_type,
-                                  Rotate view_rotate,
-                                  ScaleFilter filter);
-
-// Biliner Scale a frame of YV12 to 32 bits ARGB on a specified rectangle.
-// |yplane|, etc and |rgbframe| should point to the top-left pixels of the
-// source and destination buffers.
-MEDIA_EXPORT void ScaleYUVToRGB32WithRect(const uint8_t* yplane,
-                                          const uint8_t* uplane,
-                                          const uint8_t* vplane,
-                                          uint8_t* rgbframe,
-                                          int source_width,
-                                          int source_height,
-                                          int dest_width,
-                                          int dest_height,
-                                          int dest_rect_left,
-                                          int dest_rect_top,
-                                          int dest_rect_right,
-                                          int dest_rect_bottom,
-                                          int ystride,
-                                          int uvstride,
-                                          int rgbstride);
-
-MEDIA_EXPORT void ConvertRGB32ToYUV(const uint8_t* rgbframe,
-                                    uint8_t* yplane,
-                                    uint8_t* uplane,
-                                    uint8_t* vplane,
-                                    int width,
-                                    int height,
-                                    int rgbstride,
-                                    int ystride,
-                                    int uvstride);
-
-MEDIA_EXPORT void ConvertRGB24ToYUV(const uint8_t* rgbframe,
-                                    uint8_t* yplane,
-                                    uint8_t* uplane,
-                                    uint8_t* vplane,
-                                    int width,
-                                    int height,
-                                    int rgbstride,
-                                    int ystride,
-                                    int uvstride);
-
-// Empty SIMD register state after calling optimized scaler functions.
-MEDIA_EXPORT void EmptyRegisterState();
-
-}  // namespace media
-
-#endif  // MEDIA_BASE_YUV_CONVERT_H_
diff --git a/media/base/yuv_convert_perftest.cc b/media/base/yuv_convert_perftest.cc
deleted file mode 100644
index ddf777cf..0000000
--- a/media/base/yuv_convert_perftest.cc
+++ /dev/null
@@ -1,222 +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 <stdint.h>
-
-#include <memory>
-
-#include "base/base_paths.h"
-#include "base/cpu.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/path_service.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
-#include "media/base/simd/convert_yuv_to_rgb.h"
-#include "media/base/yuv_convert.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
-#include "third_party/libyuv/include/libyuv/row.h"
-
-namespace media {
-#if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY)
-// Size of raw image.
-static const int kSourceWidth = 640;
-static const int kSourceHeight = 360;
-static const int kSourceYSize = kSourceWidth * kSourceHeight;
-static const int kSourceUOffset = kSourceYSize;
-static const int kSourceVOffset = kSourceYSize * 5 / 4;
-static const int kBpp = 4;
-
-// Width of the row to convert. Odd so that we exercise the ending
-// one-pixel-leftover case.
-static const int kWidth = 639;
-
-// Surface sizes for various test files.
-static const int kYUV12Size = kSourceYSize * 12 / 8;
-static const int kRGBSize = kSourceYSize * kBpp;
-
-static const int kPerfTestIterations = 2000;
-
-class YUVConvertPerfTest : public testing::Test {
- public:
-  YUVConvertPerfTest()
-      : yuv_bytes_(new uint8_t[kYUV12Size]),
-        rgb_bytes_converted_(new uint8_t[kRGBSize]) {
-    base::FilePath path;
-    CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &path));
-    path = path.Append(FILE_PATH_LITERAL("media"))
-               .Append(FILE_PATH_LITERAL("test"))
-               .Append(FILE_PATH_LITERAL("data"))
-               .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv"));
-
-    // Verify file size is correct.
-    int64_t actual_size = 0;
-    base::GetFileSize(path, &actual_size);
-    CHECK_EQ(actual_size, kYUV12Size);
-
-    // Verify bytes read are correct.
-    int bytes_read = base::ReadFile(
-        path, reinterpret_cast<char*>(yuv_bytes_.get()), kYUV12Size);
-
-    CHECK_EQ(bytes_read, kYUV12Size);
-  }
-
-  std::unique_ptr<uint8_t[]> yuv_bytes_;
-  std::unique_ptr<uint8_t[]> rgb_bytes_converted_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(YUVConvertPerfTest);
-};
-
-TEST_F(YUVConvertPerfTest, ConvertYUVToRGB32Row_SSE) {
-  ASSERT_TRUE(base::CPU().has_sse());
-
-  base::TimeTicks start = base::TimeTicks::Now();
-  for (int i = 0; i < kPerfTestIterations; ++i) {
-    for (int row = 0; row < kSourceHeight; ++row) {
-      int chroma_row = row / 2;
-      ConvertYUVToRGB32Row_SSE(
-          yuv_bytes_.get() + row * kSourceWidth,
-          yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2),
-          yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2),
-          rgb_bytes_converted_.get(),
-          kWidth,
-          GetLookupTable(YV12));
-    }
-  }
-  media::EmptyRegisterState();
-  double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF();
-  perf_test::PrintResult(
-      "yuv_convert_perftest", "", "ConvertYUVToRGB32Row_SSE",
-      kPerfTestIterations / total_time_seconds, "runs/s", true);
-}
-
-#ifdef HAS_I422TOARGBROW_SSSE3
-TEST_F(YUVConvertPerfTest, I422ToARGBRow_SSSE3) {
-  ASSERT_TRUE(base::CPU().has_ssse3());
-
-  base::TimeTicks start = base::TimeTicks::Now();
-  for (int i = 0; i < kPerfTestIterations; ++i) {
-    for (int row = 0; row < kSourceHeight; ++row) {
-      int chroma_row = row / 2;
-      libyuv::I422ToARGBRow_SSSE3(
-          yuv_bytes_.get() + row * kSourceWidth,
-          yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2),
-          yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2),
-          rgb_bytes_converted_.get(), &libyuv::kYuvI601Constants, kWidth);
-    }
-  }
-  double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF();
-  perf_test::PrintResult("yuv_convert_perftest", "", "I422ToARGBRow_SSSE3",
-                         kPerfTestIterations / total_time_seconds, "runs/s",
-                         true);
-}
-#endif
-
-TEST_F(YUVConvertPerfTest, ConvertYUVAToARGBRow_MMX) {
-  ASSERT_TRUE(base::CPU().has_sse());
-
-  base::TimeTicks start = base::TimeTicks::Now();
-  for (int i = 0; i < kPerfTestIterations; ++i) {
-    for (int row = 0; row < kSourceHeight; ++row) {
-      int chroma_row = row / 2;
-      ConvertYUVAToARGBRow_MMX(
-          yuv_bytes_.get() + row * kSourceWidth,
-          yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2),
-          yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2),
-          yuv_bytes_.get() + row * kSourceWidth,  // hack: use luma for alpha
-          rgb_bytes_converted_.get(), kWidth, GetLookupTable(YV12));
-    }
-  }
-  media::EmptyRegisterState();
-  double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF();
-  perf_test::PrintResult("yuv_convert_perftest", "", "ConvertYUVAToARGBRow_MMX",
-                         kPerfTestIterations / total_time_seconds, "runs/s",
-                         true);
-}
-
-#ifdef HAS_I422ALPHATOARGBROW_SSSE3
-TEST_F(YUVConvertPerfTest, I422AlphaToARGBRow_SSSE3) {
-  ASSERT_TRUE(base::CPU().has_ssse3());
-
-  base::TimeTicks start = base::TimeTicks::Now();
-  for (int i = 0; i < kPerfTestIterations; ++i) {
-    for (int row = 0; row < kSourceHeight; ++row) {
-      int chroma_row = row / 2;
-      libyuv::I422AlphaToARGBRow_SSSE3(
-          yuv_bytes_.get() + row * kSourceWidth,
-          yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2),
-          yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2),
-          yuv_bytes_.get() + row * kSourceWidth,  // hack: use luma for alpha
-          rgb_bytes_converted_.get(), &libyuv::kYuvI601Constants, kWidth);
-    }
-  }
-  double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF();
-  perf_test::PrintResult("yuv_convert_perftest", "", "I422AlphaToARGBRow_SSSE3",
-                         kPerfTestIterations / total_time_seconds, "runs/s",
-                         true);
-}
-#endif
-
-// 64-bit release + component builds on Windows are too smart and optimizes
-// away the function being tested.
-#if defined(OS_WIN) && (defined(ARCH_CPU_X86) || !defined(COMPONENT_BUILD))
-TEST_F(YUVConvertPerfTest, ScaleYUVToRGB32Row_SSE) {
-  ASSERT_TRUE(base::CPU().has_sse());
-
-  const int kSourceDx = 80000;  // This value means a scale down.
-
-  base::TimeTicks start = base::TimeTicks::Now();
-  for (int i = 0; i < kPerfTestIterations; ++i) {
-    for (int row = 0; row < kSourceHeight; ++row) {
-      int chroma_row = row / 2;
-      ScaleYUVToRGB32Row_SSE(
-          yuv_bytes_.get() + row * kSourceWidth,
-          yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2),
-          yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2),
-          rgb_bytes_converted_.get(),
-          kWidth,
-          kSourceDx,
-          GetLookupTable(YV12));
-    }
-  }
-  media::EmptyRegisterState();
-  double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF();
-  perf_test::PrintResult(
-      "yuv_convert_perftest", "", "ScaleYUVToRGB32Row_SSE",
-      kPerfTestIterations / total_time_seconds, "runs/s", true);
-}
-
-TEST_F(YUVConvertPerfTest, LinearScaleYUVToRGB32Row_SSE) {
-  ASSERT_TRUE(base::CPU().has_sse());
-
-  const int kSourceDx = 80000;  // This value means a scale down.
-
-  base::TimeTicks start = base::TimeTicks::Now();
-  for (int i = 0; i < kPerfTestIterations; ++i) {
-    for (int row = 0; row < kSourceHeight; ++row) {
-      int chroma_row = row / 2;
-      LinearScaleYUVToRGB32Row_SSE(
-          yuv_bytes_.get() + row * kSourceWidth,
-          yuv_bytes_.get() + kSourceUOffset + (chroma_row * kSourceWidth / 2),
-          yuv_bytes_.get() + kSourceVOffset + (chroma_row * kSourceWidth / 2),
-          rgb_bytes_converted_.get(),
-          kWidth,
-          kSourceDx,
-          GetLookupTable(YV12));
-    }
-  }
-  media::EmptyRegisterState();
-  double total_time_seconds = (base::TimeTicks::Now() - start).InSecondsF();
-  perf_test::PrintResult(
-      "yuv_convert_perftest", "", "LinearScaleYUVToRGB32Row_SSE",
-      kPerfTestIterations / total_time_seconds, "runs/s", true);
-}
-#endif  // defined(OS_WIN) && (ARCH_CPU_X86 || COMPONENT_BUILD)
-
-#endif  // !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY)
-
-}  // namespace media
diff --git a/media/base/yuv_convert_unittest.cc b/media/base/yuv_convert_unittest.cc
deleted file mode 100644
index ec872c89..0000000
--- a/media/base/yuv_convert_unittest.cc
+++ /dev/null
@@ -1,876 +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 "media/base/yuv_convert.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/base_paths.h"
-#include "base/cpu.h"
-#include "base/files/file_util.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "build/build_config.h"
-#include "media/base/djb2.h"
-#include "media/base/simd/convert_rgb_to_yuv.h"
-#include "media/base/simd/convert_yuv_to_rgb.h"
-#include "media/base/simd/filter_yuv.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/rect.h"
-
-// Size of raw image.
-static const int kSourceWidth = 640;
-static const int kSourceHeight = 360;
-static const int kSourceYSize = kSourceWidth * kSourceHeight;
-static const int kSourceUOffset = kSourceYSize;
-static const int kSourceVOffset = kSourceYSize * 5 / 4;
-static const int kScaledWidth = 1024;
-static const int kScaledHeight = 768;
-static const int kDownScaledWidth = 512;
-static const int kDownScaledHeight = 320;
-static const int kBpp = 4;
-
-// Surface sizes for various test files.
-static const int kYUV12Size = kSourceYSize * 12 / 8;
-static const int kYUV16Size = kSourceYSize * 16 / 8;
-static const int kRGBSize = kSourceYSize * kBpp;
-static const int kRGBSizeScaled = kScaledWidth * kScaledHeight * kBpp;
-static const int kRGB24Size = kSourceYSize * 3;
-static const int kRGBSizeConverted = kSourceYSize * kBpp;
-
-#if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) && \
-    !defined(OS_ANDROID)
-static const int kSourceAOffset = kSourceYSize * 12 / 8;
-static const int kYUVA12Size = kSourceYSize * 20 / 8;
-#endif
-
-// Helper for reading test data into a std::unique_ptr<uint8_t[]>.
-static void ReadData(const base::FilePath::CharType* filename,
-                     int expected_size,
-                     std::unique_ptr<uint8_t[]>* data) {
-  data->reset(new uint8_t[expected_size]);
-
-  base::FilePath path;
-  CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &path));
-  path = path.Append(FILE_PATH_LITERAL("media"))
-             .Append(FILE_PATH_LITERAL("test"))
-             .Append(FILE_PATH_LITERAL("data"))
-             .Append(filename);
-
-  // Verify file size is correct.
-  int64_t actual_size = 0;
-  base::GetFileSize(path, &actual_size);
-  CHECK_EQ(actual_size, expected_size);
-
-  // Verify bytes read are correct.
-  int bytes_read = base::ReadFile(
-      path, reinterpret_cast<char*>(data->get()), expected_size);
-  CHECK_EQ(bytes_read, expected_size);
-}
-
-static void ReadYV12Data(std::unique_ptr<uint8_t[]>* data) {
-  ReadData(FILE_PATH_LITERAL("bali_640x360_P420.yuv"), kYUV12Size, data);
-}
-
-static void ReadYV16Data(std::unique_ptr<uint8_t[]>* data) {
-  ReadData(FILE_PATH_LITERAL("bali_640x360_P422.yuv"), kYUV16Size, data);
-}
-
-#if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) && \
-    !defined(OS_ANDROID)
-static void ReadYV12AData(std::unique_ptr<uint8_t[]>* data) {
-  ReadData(FILE_PATH_LITERAL("bali_640x360_P420_alpha.yuv"), kYUVA12Size, data);
-}
-#endif
-
-static void ReadRGB24Data(std::unique_ptr<uint8_t[]>* data) {
-  ReadData(FILE_PATH_LITERAL("bali_640x360_RGB24.rgb"), kRGB24Size, data);
-}
-
-#if defined(OS_ANDROID)
-// Helper for swapping red and blue channels of RGBA or BGRA.
-static void SwapRedAndBlueChannels(unsigned char* pixels, size_t buffer_size) {
-  for (size_t i = 0; i < buffer_size; i += 4) {
-    std::swap(pixels[i], pixels[i + 2]);
-  }
-}
-#endif
-
-namespace media {
-
-TEST(YUVConvertTest, YV12) {
-  // Allocate all surfaces.
-  std::unique_ptr<uint8_t[]> yuv_bytes;
-  std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> rgb_converted_bytes(
-      new uint8_t[kRGBSizeConverted]);
-
-  // Read YUV reference data from file.
-  ReadYV12Data(&yuv_bytes);
-
-  // Convert a frame of YUV to 32 bit ARGB.
-  media::ConvertYUVToRGB32(yuv_bytes.get(),
-                           yuv_bytes.get() + kSourceUOffset,
-                           yuv_bytes.get() + kSourceVOffset,
-                           rgb_converted_bytes.get(),            // RGB output
-                           kSourceWidth, kSourceHeight,          // Dimensions
-                           kSourceWidth,                         // YStride
-                           kSourceWidth / 2,                     // UVStride
-                           kSourceWidth * kBpp,                  // RGBStride
-                           media::YV12);
-
-#if defined(OS_ANDROID)
-  SwapRedAndBlueChannels(rgb_converted_bytes.get(), kRGBSizeConverted);
-#endif
-
-  uint32_t rgb_hash =
-      DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted, kDJB2HashSeed);
-  EXPECT_EQ(2413171226u, rgb_hash);
-}
-
-TEST(YUVConvertTest, YV16) {
-  // Allocate all surfaces.
-  std::unique_ptr<uint8_t[]> yuv_bytes;
-  std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> rgb_converted_bytes(
-      new uint8_t[kRGBSizeConverted]);
-
-  // Read YUV reference data from file.
-  ReadYV16Data(&yuv_bytes);
-
-  // Convert a frame of YUV to 32 bit ARGB.
-  media::ConvertYUVToRGB32(yuv_bytes.get(),                        // Y
-                           yuv_bytes.get() + kSourceUOffset,       // U
-                           yuv_bytes.get() + kSourceYSize * 3 / 2, // V
-                           rgb_converted_bytes.get(),              // RGB output
-                           kSourceWidth, kSourceHeight,            // Dimensions
-                           kSourceWidth,                           // YStride
-                           kSourceWidth / 2,                       // UVStride
-                           kSourceWidth * kBpp,                    // RGBStride
-                           media::YV16);
-
-#if defined(OS_ANDROID)
-  SwapRedAndBlueChannels(rgb_converted_bytes.get(), kRGBSizeConverted);
-#endif
-
-  uint32_t rgb_hash =
-      DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted, kDJB2HashSeed);
-  EXPECT_EQ(4222342047u, rgb_hash);
-}
-
-struct YUVScaleTestData {
-  YUVScaleTestData(media::YUVType y, media::ScaleFilter s, uint32_t r)
-      : yuv_type(y), scale_filter(s), rgb_hash(r) {}
-
-  media::YUVType yuv_type;
-  media::ScaleFilter scale_filter;
-  uint32_t rgb_hash;
-};
-
-class YUVScaleTest : public ::testing::TestWithParam<YUVScaleTestData> {
- public:
-  YUVScaleTest() {
-    switch (GetParam().yuv_type) {
-      case media::YV12:
-      case media::YV12J:
-      case media::YV12HD:
-        ReadYV12Data(&yuv_bytes_);
-        break;
-      case media::YV16:
-        ReadYV16Data(&yuv_bytes_);
-        break;
-    }
-
-    rgb_bytes_.reset(new uint8_t[kRGBSizeScaled]);
-  }
-
-  // Helpers for getting the proper Y, U and V plane offsets.
-  uint8_t* y_plane() { return yuv_bytes_.get(); }
-  uint8_t* u_plane() { return yuv_bytes_.get() + kSourceYSize; }
-  uint8_t* v_plane() {
-    switch (GetParam().yuv_type) {
-      case media::YV12:
-      case media::YV12J:
-      case media::YV12HD:
-        return yuv_bytes_.get() + kSourceVOffset;
-      case media::YV16:
-        return yuv_bytes_.get() + kSourceYSize * 3 / 2;
-    }
-    return NULL;
-  }
-
-  std::unique_ptr<uint8_t[]> yuv_bytes_;
-  std::unique_ptr<uint8_t[]> rgb_bytes_;
-};
-
-TEST_P(YUVScaleTest, NoScale) {
-  media::ScaleYUVToRGB32(y_plane(),                    // Y
-                         u_plane(),                    // U
-                         v_plane(),                    // V
-                         rgb_bytes_.get(),             // RGB output
-                         kSourceWidth, kSourceHeight,  // Dimensions
-                         kSourceWidth, kSourceHeight,  // Dimensions
-                         kSourceWidth,                 // YStride
-                         kSourceWidth / 2,             // UvStride
-                         kSourceWidth * kBpp,          // RgbStride
-                         GetParam().yuv_type,
-                         media::ROTATE_0,
-                         GetParam().scale_filter);
-
-  uint32_t yuv_hash = DJB2Hash(rgb_bytes_.get(), kRGBSize, kDJB2HashSeed);
-
-  media::ConvertYUVToRGB32(y_plane(),                    // Y
-                           u_plane(),                    // U
-                           v_plane(),                    // V
-                           rgb_bytes_.get(),             // RGB output
-                           kSourceWidth, kSourceHeight,  // Dimensions
-                           kSourceWidth,                 // YStride
-                           kSourceWidth / 2,             // UVStride
-                           kSourceWidth * kBpp,          // RGBStride
-                           GetParam().yuv_type);
-
-  uint32_t rgb_hash = DJB2Hash(rgb_bytes_.get(), kRGBSize, kDJB2HashSeed);
-
-  EXPECT_EQ(yuv_hash, rgb_hash);
-}
-
-TEST_P(YUVScaleTest, Normal) {
-  media::ScaleYUVToRGB32(y_plane(),                    // Y
-                         u_plane(),                    // U
-                         v_plane(),                    // V
-                         rgb_bytes_.get(),             // RGB output
-                         kSourceWidth, kSourceHeight,  // Dimensions
-                         kScaledWidth, kScaledHeight,  // Dimensions
-                         kSourceWidth,                 // YStride
-                         kSourceWidth / 2,             // UvStride
-                         kScaledWidth * kBpp,          // RgbStride
-                         GetParam().yuv_type,
-                         media::ROTATE_0,
-                         GetParam().scale_filter);
-
-#if defined(OS_ANDROID)
-  SwapRedAndBlueChannels(rgb_bytes_.get(), kRGBSizeScaled);
-#endif
-
-  uint32_t rgb_hash = DJB2Hash(rgb_bytes_.get(), kRGBSizeScaled, kDJB2HashSeed);
-  EXPECT_EQ(GetParam().rgb_hash, rgb_hash);
-}
-
-TEST_P(YUVScaleTest, ZeroSourceSize) {
-  media::ScaleYUVToRGB32(y_plane(),                    // Y
-                         u_plane(),                    // U
-                         v_plane(),                    // V
-                         rgb_bytes_.get(),             // RGB output
-                         0, 0,                         // Dimensions
-                         kScaledWidth, kScaledHeight,  // Dimensions
-                         kSourceWidth,                 // YStride
-                         kSourceWidth / 2,             // UvStride
-                         kScaledWidth * kBpp,          // RgbStride
-                         GetParam().yuv_type,
-                         media::ROTATE_0,
-                         GetParam().scale_filter);
-
-  // Testing for out-of-bound read/writes with AddressSanitizer.
-}
-
-TEST_P(YUVScaleTest, ZeroDestinationSize) {
-  media::ScaleYUVToRGB32(y_plane(),                    // Y
-                         u_plane(),                    // U
-                         v_plane(),                    // V
-                         rgb_bytes_.get(),             // RGB output
-                         kSourceWidth, kSourceHeight,  // Dimensions
-                         0, 0,                         // Dimensions
-                         kSourceWidth,                 // YStride
-                         kSourceWidth / 2,             // UvStride
-                         kScaledWidth * kBpp,          // RgbStride
-                         GetParam().yuv_type,
-                         media::ROTATE_0,
-                         GetParam().scale_filter);
-
-  // Testing for out-of-bound read/writes with AddressSanitizer.
-}
-
-TEST_P(YUVScaleTest, OddWidthAndHeightNotCrash) {
-  media::ScaleYUVToRGB32(y_plane(),                    // Y
-                         u_plane(),                    // U
-                         v_plane(),                    // V
-                         rgb_bytes_.get(),             // RGB output
-                         kSourceWidth, kSourceHeight,  // Dimensions
-                         3, 3,                         // Dimensions
-                         kSourceWidth,                 // YStride
-                         kSourceWidth / 2,             // UvStride
-                         kScaledWidth * kBpp,          // RgbStride
-                         GetParam().yuv_type,
-                         media::ROTATE_0,
-                         GetParam().scale_filter);
-}
-
-INSTANTIATE_TEST_CASE_P(
-    YUVScaleFormats, YUVScaleTest,
-    ::testing::Values(
-        YUVScaleTestData(media::YV12, media::FILTER_NONE, 4136904952u),
-        YUVScaleTestData(media::YV16, media::FILTER_NONE, 1501777547u),
-        YUVScaleTestData(media::YV12, media::FILTER_BILINEAR, 3164274689u),
-        YUVScaleTestData(media::YV16, media::FILTER_BILINEAR, 3095878046u)));
-
-// This tests a known worst case YUV value, and for overflow.
-TEST(YUVConvertTest, Clamp) {
-  // Allocate all surfaces.
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[1]);
-  std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[1]);
-  std::unique_ptr<uint8_t[]> rgb_converted_bytes(new uint8_t[1]);
-
-  // Values that failed previously in bug report.
-  unsigned char y = 255u;
-  unsigned char u = 255u;
-  unsigned char v = 19u;
-
-  // Prefill extra large destination buffer to test for overflow.
-  unsigned char rgb[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
-  unsigned char expected[8] = { 255, 255, 104, 255, 4, 5, 6, 7 };
-  // Convert a frame of YUV to 32 bit ARGB.
-  media::ConvertYUVToRGB32(&y,       // Y
-                           &u,       // U
-                           &v,       // V
-                           &rgb[0],  // RGB output
-                           1, 1,     // Dimensions
-                           0,        // YStride
-                           0,        // UVStride
-                           0,        // RGBStride
-                           media::YV12);
-
-#if defined(OS_ANDROID)
-  SwapRedAndBlueChannels(rgb, kBpp);
-#endif
-
-  int expected_test = memcmp(rgb, expected, sizeof(expected));
-  EXPECT_EQ(0, expected_test);
-}
-
-TEST(YUVConvertTest, RGB24ToYUV) {
-  // Allocate all surfaces.
-  std::unique_ptr<uint8_t[]> rgb_bytes;
-  std::unique_ptr<uint8_t[]> yuv_converted_bytes(new uint8_t[kYUV12Size]);
-
-  // Read RGB24 reference data from file.
-  ReadRGB24Data(&rgb_bytes);
-
-  // Convert to I420.
-  media::ConvertRGB24ToYUV(rgb_bytes.get(),
-                           yuv_converted_bytes.get(),
-                           yuv_converted_bytes.get() + kSourceUOffset,
-                           yuv_converted_bytes.get() + kSourceVOffset,
-                           kSourceWidth, kSourceHeight,        // Dimensions
-                           kSourceWidth * 3,                   // RGBStride
-                           kSourceWidth,                       // YStride
-                           kSourceWidth / 2);                  // UVStride
-
-  uint32_t rgb_hash =
-      DJB2Hash(yuv_converted_bytes.get(), kYUV12Size, kDJB2HashSeed);
-  EXPECT_EQ(320824432u, rgb_hash);
-}
-
-TEST(YUVConvertTest, RGB32ToYUV) {
-  // Allocate all surfaces.
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> yuv_converted_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> rgb_converted_bytes(new uint8_t[kRGBSize]);
-
-  // Read YUV reference data from file.
-  base::FilePath yuv_url;
-  EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url));
-  yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media"))
-                   .Append(FILE_PATH_LITERAL("test"))
-                   .Append(FILE_PATH_LITERAL("data"))
-                   .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv"));
-  EXPECT_EQ(static_cast<int>(kYUV12Size),
-            base::ReadFile(yuv_url,
-                           reinterpret_cast<char*>(yuv_bytes.get()),
-                           static_cast<int>(kYUV12Size)));
-
-  // Convert a frame of YUV to 32 bit ARGB.
-  media::ConvertYUVToRGB32(yuv_bytes.get(),
-                           yuv_bytes.get() + kSourceUOffset,
-                           yuv_bytes.get() + kSourceVOffset,
-                           rgb_bytes.get(),            // RGB output
-                           kSourceWidth, kSourceHeight,          // Dimensions
-                           kSourceWidth,                         // YStride
-                           kSourceWidth / 2,                     // UVStride
-                           kSourceWidth * kBpp,                  // RGBStride
-                           media::YV12);
-
-  // Convert RGB32 to YV12.
-  media::ConvertRGB32ToYUV(rgb_bytes.get(),
-                           yuv_converted_bytes.get(),
-                           yuv_converted_bytes.get() + kSourceUOffset,
-                           yuv_converted_bytes.get() + kSourceVOffset,
-                           kSourceWidth, kSourceHeight,        // Dimensions
-                           kSourceWidth * 4,                   // RGBStride
-                           kSourceWidth,                       // YStride
-                           kSourceWidth / 2);                  // UVStride
-
-  // Convert YV12 back to RGB32.
-  media::ConvertYUVToRGB32(yuv_converted_bytes.get(),
-                           yuv_converted_bytes.get() + kSourceUOffset,
-                           yuv_converted_bytes.get() + kSourceVOffset,
-                           rgb_converted_bytes.get(),            // RGB output
-                           kSourceWidth, kSourceHeight,          // Dimensions
-                           kSourceWidth,                         // YStride
-                           kSourceWidth / 2,                     // UVStride
-                           kSourceWidth * kBpp,                  // RGBStride
-                           media::YV12);
-
-  int error = 0;
-  for (int i = 0; i < kRGBSize; ++i) {
-    int diff = rgb_converted_bytes[i] - rgb_bytes[i];
-    if (diff < 0)
-      diff = -diff;
-    error += diff;
-  }
-
-  // Make sure error is within bound.
-  DVLOG(1) << "Average error per channel: " << error / kRGBSize;
-  EXPECT_GT(5, error / kRGBSize);
-}
-
-TEST(YUVConvertTest, DownScaleYUVToRGB32WithRect) {
-  // Read YUV reference data from file.
-  base::FilePath yuv_url;
-  EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url));
-  yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media"))
-                   .Append(FILE_PATH_LITERAL("test"))
-                   .Append(FILE_PATH_LITERAL("data"))
-                   .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv"));
-  const size_t size_of_yuv = kSourceYSize * 12 / 8;  // 12 bpp.
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[size_of_yuv]);
-  EXPECT_EQ(static_cast<int>(size_of_yuv),
-            base::ReadFile(yuv_url,
-                           reinterpret_cast<char*>(yuv_bytes.get()),
-                           static_cast<int>(size_of_yuv)));
-
-  // Scale the full frame of YUV to 32 bit ARGB.
-  // The API currently only supports down-scaling, so we don't test up-scaling.
-  const size_t size_of_rgb_scaled = kDownScaledWidth * kDownScaledHeight * kBpp;
-  std::unique_ptr<uint8_t[]> rgb_scaled_bytes(new uint8_t[size_of_rgb_scaled]);
-  gfx::Rect sub_rect(0, 0, kDownScaledWidth, kDownScaledHeight);
-
-  // We can't compare with the full-frame scaler because it uses slightly
-  // different sampling coordinates.
-  media::ScaleYUVToRGB32WithRect(
-      yuv_bytes.get(),                          // Y
-      yuv_bytes.get() + kSourceUOffset,         // U
-      yuv_bytes.get() + kSourceVOffset,         // V
-      rgb_scaled_bytes.get(),                   // Rgb output
-      kSourceWidth, kSourceHeight,              // Dimensions
-      kDownScaledWidth, kDownScaledHeight,      // Dimensions
-      sub_rect.x(), sub_rect.y(),               // Dest rect
-      sub_rect.right(), sub_rect.bottom(),      // Dest rect
-      kSourceWidth,                             // YStride
-      kSourceWidth / 2,                         // UvStride
-      kDownScaledWidth * kBpp);                 // RgbStride
-
-  uint32_t rgb_hash_full_rect =
-      DJB2Hash(rgb_scaled_bytes.get(), size_of_rgb_scaled, kDJB2HashSeed);
-
-  // Re-scale sub-rectangles and verify the results are the same.
-  int next_sub_rect = 0;
-  while (!sub_rect.IsEmpty()) {
-    // Scale a partial rectangle.
-    media::ScaleYUVToRGB32WithRect(
-        yuv_bytes.get(),                          // Y
-        yuv_bytes.get() + kSourceUOffset,         // U
-        yuv_bytes.get() + kSourceVOffset,         // V
-        rgb_scaled_bytes.get(),                   // Rgb output
-        kSourceWidth, kSourceHeight,              // Dimensions
-        kDownScaledWidth, kDownScaledHeight,      // Dimensions
-        sub_rect.x(), sub_rect.y(),               // Dest rect
-        sub_rect.right(), sub_rect.bottom(),      // Dest rect
-        kSourceWidth,                             // YStride
-        kSourceWidth / 2,                         // UvStride
-        kDownScaledWidth * kBpp);                 // RgbStride
-    uint32_t rgb_hash_sub_rect =
-        DJB2Hash(rgb_scaled_bytes.get(), size_of_rgb_scaled, kDJB2HashSeed);
-
-    EXPECT_EQ(rgb_hash_full_rect, rgb_hash_sub_rect);
-
-    // Now pick choose a quarter rect of this sub-rect.
-    if (next_sub_rect & 1)
-      sub_rect.set_x(sub_rect.x() + sub_rect.width() / 2);
-    if (next_sub_rect & 2)
-      sub_rect.set_y(sub_rect.y() + sub_rect.height() / 2);
-    sub_rect.set_width(sub_rect.width() / 2);
-    sub_rect.set_height(sub_rect.height() / 2);
-    next_sub_rect++;
-  }
-}
-
-#if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY)
-#if !defined(OS_ANDROID)
-TEST(YUVConvertTest, YUVAtoARGB_MMX_MatchReference) {
-  // Allocate all surfaces.
-  std::unique_ptr<uint8_t[]> yuv_bytes;
-  std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> rgb_converted_bytes(
-      new uint8_t[kRGBSizeConverted]);
-  std::unique_ptr<uint8_t[]> rgb_converted_bytes_ref(
-      new uint8_t[kRGBSizeConverted]);
-
-  // Read YUV reference data from file.
-  ReadYV12AData(&yuv_bytes);
-
-  // Convert a frame of YUV to 32 bit ARGB using both C and MMX versions.
-  media::ConvertYUVAToARGB_C(yuv_bytes.get(),
-                             yuv_bytes.get() + kSourceUOffset,
-                             yuv_bytes.get() + kSourceVOffset,
-                             yuv_bytes.get() + kSourceAOffset,
-                             rgb_converted_bytes_ref.get(),
-                             kSourceWidth,
-                             kSourceHeight,
-                             kSourceWidth,
-                             kSourceWidth / 2,
-                             kSourceWidth,
-                             kSourceWidth * kBpp,
-                             media::YV12);
-  media::ConvertYUVAToARGB_MMX(yuv_bytes.get(),
-                               yuv_bytes.get() + kSourceUOffset,
-                               yuv_bytes.get() + kSourceVOffset,
-                               yuv_bytes.get() + kSourceAOffset,
-                               rgb_converted_bytes.get(),
-                               kSourceWidth,
-                               kSourceHeight,
-                               kSourceWidth,
-                               kSourceWidth / 2,
-                               kSourceWidth,
-                               kSourceWidth * kBpp,
-                               media::YV12);
-
-  EXPECT_EQ(0,
-            memcmp(rgb_converted_bytes.get(),
-                   rgb_converted_bytes_ref.get(),
-                   kRGBSizeConverted));
-}
-#endif  // !defined(OS_ANDROID)
-
-TEST(YUVConvertTest, RGB32ToYUV_SSE2_MatchReference) {
-  base::CPU cpu;
-  if (!cpu.has_sse2()) {
-    LOG(WARNING) << "System doesn't support SSE2, test not executed.";
-    return;
-  }
-
-  // Allocate all surfaces.
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> yuv_converted_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> yuv_reference_bytes(new uint8_t[kYUV12Size]);
-
-  ReadYV12Data(&yuv_bytes);
-
-  // Convert a frame of YUV to 32 bit ARGB.
-  media::ConvertYUVToRGB32(
-      yuv_bytes.get(),
-      yuv_bytes.get() + kSourceUOffset,
-      yuv_bytes.get() + kSourceVOffset,
-      rgb_bytes.get(),            // RGB output
-      kSourceWidth, kSourceHeight,          // Dimensions
-      kSourceWidth,                         // YStride
-      kSourceWidth / 2,                     // UVStride
-      kSourceWidth * kBpp,                  // RGBStride
-      media::YV12);
-
-  // Convert RGB32 to YV12 with SSE2 version.
-  media::ConvertRGB32ToYUV_SSE2(
-      rgb_bytes.get(),
-      yuv_converted_bytes.get(),
-      yuv_converted_bytes.get() + kSourceUOffset,
-      yuv_converted_bytes.get() + kSourceVOffset,
-      kSourceWidth, kSourceHeight,        // Dimensions
-      kSourceWidth * 4,                   // RGBStride
-      kSourceWidth,                       // YStride
-      kSourceWidth / 2);                  // UVStride
-
-  // Convert RGB32 to YV12 with reference version.
-  media::ConvertRGB32ToYUV_SSE2_Reference(
-      rgb_bytes.get(),
-      yuv_reference_bytes.get(),
-      yuv_reference_bytes.get() + kSourceUOffset,
-      yuv_reference_bytes.get() + kSourceVOffset,
-      kSourceWidth, kSourceHeight,        // Dimensions
-      kSourceWidth * 4,                   // RGBStride
-      kSourceWidth,                       // YStride
-      kSourceWidth / 2);                  // UVStride
-
-  // Now convert a odd width and height, this overrides part of the buffer
-  // generated above but that is fine because the point of this test is to
-  // match the result with the reference code.
-
-  // Convert RGB32 to YV12 with SSE2 version.
-  media::ConvertRGB32ToYUV_SSE2(
-      rgb_bytes.get(),
-      yuv_converted_bytes.get(),
-      yuv_converted_bytes.get() + kSourceUOffset,
-      yuv_converted_bytes.get() + kSourceVOffset,
-      7, 7,                               // Dimensions
-      kSourceWidth * 4,                   // RGBStride
-      kSourceWidth,                       // YStride
-      kSourceWidth / 2);                  // UVStride
-
-  // Convert RGB32 to YV12 with reference version.
-  media::ConvertRGB32ToYUV_SSE2_Reference(
-      rgb_bytes.get(),
-      yuv_reference_bytes.get(),
-      yuv_reference_bytes.get() + kSourceUOffset,
-      yuv_reference_bytes.get() + kSourceVOffset,
-      7, 7,                               // Dimensions
-      kSourceWidth * 4,                   // RGBStride
-      kSourceWidth,                       // YStride
-      kSourceWidth / 2);                  // UVStride
-
-  int error = 0;
-  for (int i = 0; i < kYUV12Size; ++i) {
-    int diff = yuv_reference_bytes[i] - yuv_converted_bytes[i];
-    if (diff < 0)
-      diff = -diff;
-    error += diff;
-  }
-
-  // Make sure there's no difference from the reference.
-  EXPECT_EQ(0, error);
-}
-
-TEST(YUVConvertTest, ConvertYUVToRGB32Row_SSE) {
-  base::CPU cpu;
-  if (!cpu.has_sse()) {
-    LOG(WARNING) << "System not supported. Test skipped.";
-    return;
-  }
-
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
-  ReadYV12Data(&yuv_bytes);
-
-  const int kWidth = 167;
-  ConvertYUVToRGB32Row_C(yuv_bytes.get(),
-                         yuv_bytes.get() + kSourceUOffset,
-                         yuv_bytes.get() + kSourceVOffset,
-                         rgb_bytes_reference.get(),
-                         kWidth,
-                         GetLookupTable(YV12));
-  ConvertYUVToRGB32Row_SSE(yuv_bytes.get(),
-                           yuv_bytes.get() + kSourceUOffset,
-                           yuv_bytes.get() + kSourceVOffset,
-                           rgb_bytes_converted.get(),
-                           kWidth,
-                           GetLookupTable(YV12));
-  media::EmptyRegisterState();
-  EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
-                      rgb_bytes_converted.get(),
-                      kWidth * kBpp));
-}
-
-// 64-bit release + component builds on Windows are too smart and optimizes
-// away the function being tested.
-#if defined(OS_WIN) && (defined(ARCH_CPU_X86) || !defined(COMPONENT_BUILD))
-TEST(YUVConvertTest, ScaleYUVToRGB32Row_SSE) {
-  base::CPU cpu;
-  if (!cpu.has_sse()) {
-    LOG(WARNING) << "System not supported. Test skipped.";
-    return;
-  }
-
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
-  ReadYV12Data(&yuv_bytes);
-
-  const int kWidth = 167;
-  const int kSourceDx = 80000;  // This value means a scale down.
-  ScaleYUVToRGB32Row_C(yuv_bytes.get(),
-                       yuv_bytes.get() + kSourceUOffset,
-                       yuv_bytes.get() + kSourceVOffset,
-                       rgb_bytes_reference.get(),
-                       kWidth,
-                       kSourceDx,
-                       GetLookupTable(YV12));
-  ScaleYUVToRGB32Row_SSE(yuv_bytes.get(),
-                         yuv_bytes.get() + kSourceUOffset,
-                         yuv_bytes.get() + kSourceVOffset,
-                         rgb_bytes_converted.get(),
-                         kWidth,
-                         kSourceDx,
-                         GetLookupTable(YV12));
-  media::EmptyRegisterState();
-  EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
-                      rgb_bytes_converted.get(),
-                      kWidth * kBpp));
-}
-
-TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_SSE) {
-  base::CPU cpu;
-  if (!cpu.has_sse()) {
-    LOG(WARNING) << "System not supported. Test skipped.";
-    return;
-  }
-
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
-  ReadYV12Data(&yuv_bytes);
-
-  const int kWidth = 167;
-  const int kSourceDx = 80000;  // This value means a scale down.
-  LinearScaleYUVToRGB32Row_C(yuv_bytes.get(),
-                             yuv_bytes.get() + kSourceUOffset,
-                             yuv_bytes.get() + kSourceVOffset,
-                             rgb_bytes_reference.get(),
-                             kWidth,
-                             kSourceDx,
-                             GetLookupTable(YV12));
-  LinearScaleYUVToRGB32Row_SSE(yuv_bytes.get(),
-                               yuv_bytes.get() + kSourceUOffset,
-                               yuv_bytes.get() + kSourceVOffset,
-                               rgb_bytes_converted.get(),
-                               kWidth,
-                               kSourceDx,
-                               GetLookupTable(YV12));
-  media::EmptyRegisterState();
-  EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
-                      rgb_bytes_converted.get(),
-                      kWidth * kBpp));
-}
-#endif  // defined(OS_WIN) && (ARCH_CPU_X86 || COMPONENT_BUILD)
-
-TEST(YUVConvertTest, FilterYUVRows_C_OutOfBounds) {
-  std::unique_ptr<uint8_t[]> src(new uint8_t[16]);
-  std::unique_ptr<uint8_t[]> dst(new uint8_t[16]);
-
-  memset(src.get(), 0xff, 16);
-  memset(dst.get(), 0, 16);
-
-  media::FilterYUVRows_C(dst.get(), src.get(), src.get(), 1, 255);
-
-  EXPECT_EQ(255u, dst[0]);
-  for (int i = 1; i < 16; ++i) {
-    EXPECT_EQ(0u, dst[i]) << " not equal at " << i;
-  }
-}
-
-TEST(YUVConvertTest, FilterYUVRows_SSE2_OutOfBounds) {
-  base::CPU cpu;
-  if (!cpu.has_sse2()) {
-    LOG(WARNING) << "System not supported. Test skipped.";
-    return;
-  }
-
-  std::unique_ptr<uint8_t[]> src(new uint8_t[16]);
-  std::unique_ptr<uint8_t[]> dst(new uint8_t[16]);
-
-  memset(src.get(), 0xff, 16);
-  memset(dst.get(), 0, 16);
-
-  media::FilterYUVRows_SSE2(dst.get(), src.get(), src.get(), 1, 255);
-
-  EXPECT_EQ(255u, dst[0]);
-  for (int i = 1; i < 16; ++i) {
-    EXPECT_EQ(0u, dst[i]);
-  }
-}
-
-TEST(YUVConvertTest, FilterYUVRows_SSE2_UnalignedDestination) {
-  base::CPU cpu;
-  if (!cpu.has_sse2()) {
-    LOG(WARNING) << "System not supported. Test skipped.";
-    return;
-  }
-
-  const int kSize = 64;
-  std::unique_ptr<uint8_t[]> src(new uint8_t[kSize]);
-  std::unique_ptr<uint8_t[]> dst_sample(new uint8_t[kSize]);
-  std::unique_ptr<uint8_t[]> dst(new uint8_t[kSize]);
-
-  memset(dst_sample.get(), 0, kSize);
-  memset(dst.get(), 0, kSize);
-  for (int i = 0; i < kSize; ++i)
-    src[i] = 100 + i;
-
-  media::FilterYUVRows_C(dst_sample.get(),
-                         src.get(), src.get(), 37, 128);
-
-  // Generate an unaligned output address.
-  uint8_t* dst_ptr = reinterpret_cast<uint8_t*>(
-      (reinterpret_cast<uintptr_t>(dst.get() + 16) & ~15) + 1);
-  media::FilterYUVRows_SSE2(dst_ptr, src.get(), src.get(), 37, 128);
-  media::EmptyRegisterState();
-
-  EXPECT_EQ(0, memcmp(dst_sample.get(), dst_ptr, 37));
-}
-
-#if defined(ARCH_CPU_X86_64)
-
-TEST(YUVConvertTest, ScaleYUVToRGB32Row_SSE2_X64) {
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
-  ReadYV12Data(&yuv_bytes);
-
-  const int kWidth = 167;
-  const int kSourceDx = 80000;  // This value means a scale down.
-  ScaleYUVToRGB32Row_C(yuv_bytes.get(),
-                       yuv_bytes.get() + kSourceUOffset,
-                       yuv_bytes.get() + kSourceVOffset,
-                       rgb_bytes_reference.get(),
-                       kWidth,
-                       kSourceDx,
-                       GetLookupTable(YV12));
-  ScaleYUVToRGB32Row_SSE2_X64(yuv_bytes.get(),
-                              yuv_bytes.get() + kSourceUOffset,
-                              yuv_bytes.get() + kSourceVOffset,
-                              rgb_bytes_converted.get(),
-                              kWidth,
-                              kSourceDx,
-                              GetLookupTable(YV12));
-  media::EmptyRegisterState();
-  EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
-                      rgb_bytes_converted.get(),
-                      kWidth * kBpp));
-}
-
-TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_MMX_X64) {
-  std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
-  std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
-  ReadYV12Data(&yuv_bytes);
-
-  const int kWidth = 167;
-  const int kSourceDx = 80000;  // This value means a scale down.
-  LinearScaleYUVToRGB32Row_C(yuv_bytes.get(),
-                             yuv_bytes.get() + kSourceUOffset,
-                             yuv_bytes.get() + kSourceVOffset,
-                             rgb_bytes_reference.get(),
-                             kWidth,
-                             kSourceDx,
-                             GetLookupTable(YV12));
-  LinearScaleYUVToRGB32Row_MMX_X64(yuv_bytes.get(),
-                                   yuv_bytes.get() + kSourceUOffset,
-                                   yuv_bytes.get() + kSourceVOffset,
-                                   rgb_bytes_converted.get(),
-                                   kWidth,
-                                   kSourceDx,
-                                   GetLookupTable(YV12));
-  media::EmptyRegisterState();
-  EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
-                      rgb_bytes_converted.get(),
-                      kWidth * kBpp));
-}
-
-#endif  // defined(ARCH_CPU_X86_64)
-
-#endif  // defined(ARCH_CPU_X86_FAMILY)
-
-}  // namespace media
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index a195bbff..0fa7375 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -1424,6 +1424,10 @@
     video_weblayer_->layer()->SetContentsOpaque(opaque_);
 }
 
+void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
+  UpdateBackgroundVideoOptimizationState();
+}
+
 void WebMediaPlayerImpl::OnFrameHidden() {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index 1b184a8..5f4d579 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -265,6 +265,7 @@
   void OnWaitingForDecryptionKey() override;
   void OnVideoNaturalSizeChange(const gfx::Size& size) override;
   void OnVideoOpacityChange(bool opaque) override;
+  void OnVideoAverageKeyframeDistanceUpdate() override;
 
   // Actually seek. Avoids causing |should_notify_time_changed_| to be set when
   // |time_updated| is false.
diff --git a/media/filters/pipeline_controller_unittest.cc b/media/filters/pipeline_controller_unittest.cc
index fe2f158..228014d 100644
--- a/media/filters/pipeline_controller_unittest.cc
+++ b/media/filters/pipeline_controller_unittest.cc
@@ -136,6 +136,7 @@
   void OnWaitingForDecryptionKey() override {}
   void OnVideoNaturalSizeChange(const gfx::Size& size) override {}
   void OnVideoOpacityChange(bool opaque) override {}
+  void OnVideoAverageKeyframeDistanceUpdate() override {}
 
   base::MessageLoop message_loop_;
 
diff --git a/media/gpu/media_foundation_video_encode_accelerator_win.cc b/media/gpu/media_foundation_video_encode_accelerator_win.cc
index 2de7b01..050dfb7 100644
--- a/media/gpu/media_foundation_video_encode_accelerator_win.cc
+++ b/media/gpu/media_foundation_video_encode_accelerator_win.cc
@@ -200,20 +200,20 @@
   HRESULT hr =
       encoder_->GetInputStreamInfo(input_stream_id_, &input_stream_info);
   RETURN_ON_HR_FAILURE(hr, "Couldn't get input stream info", false);
-  input_sample_.Attach(mf::CreateEmptySampleWithBuffer(
+  input_sample_ = mf::CreateEmptySampleWithBuffer(
       input_stream_info.cbSize
           ? input_stream_info.cbSize
           : VideoFrame::AllocationSize(PIXEL_FORMAT_I420, input_visible_size_),
-      input_stream_info.cbAlignment));
+      input_stream_info.cbAlignment);
 
   MFT_OUTPUT_STREAM_INFO output_stream_info;
   hr = encoder_->GetOutputStreamInfo(output_stream_id_, &output_stream_info);
   RETURN_ON_HR_FAILURE(hr, "Couldn't get output stream info", false);
-  output_sample_.Attach(mf::CreateEmptySampleWithBuffer(
+  output_sample_ = mf::CreateEmptySampleWithBuffer(
       output_stream_info.cbSize
           ? output_stream_info.cbSize
           : bitstream_buffer_size_ * kOutputSampleBufferSizeRatio,
-      output_stream_info.cbAlignment));
+      output_stream_info.cbAlignment);
 
   hr = encoder_->ProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, NULL);
   RETURN_ON_HR_FAILURE(hr, "Couldn't set ProcessMessage", false);
diff --git a/media/gpu/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi_video_decode_accelerator.cc
index 07107f6..9c6897f 100644
--- a/media/gpu/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi_video_decode_accelerator.cc
@@ -951,8 +951,8 @@
 
   base::AutoLock auto_lock(lock_);
   if (state_ != kDecoding) {
-    DCHECK_EQ(state_, kDestroying);
-    return;  // We could've gotten destroyed already.
+    DCHECK(state_ == kDestroying || state_ == kResetting) << state_;
+    return;
   }
 
   // Still waiting for textures from client to finish outputting all pending
diff --git a/media/remoting/courier_renderer.cc b/media/remoting/courier_renderer.cc
index 4722f4b..27f2c32 100644
--- a/media/remoting/courier_renderer.cc
+++ b/media/remoting/courier_renderer.cc
@@ -102,6 +102,14 @@
   main_task_runner_->PostTask(
       FROM_HERE, base::Bind(&RpcBroker::UnregisterMessageReceiverCallback,
                             rpc_broker_, rpc_handle_));
+
+  // If the "between sessions" interstitial is not the one currently showing,
+  // paint a blank black frame to clear remoting messaging.
+  if (interstitial_type_ != InterstitialType::BETWEEN_SESSIONS) {
+    scoped_refptr<VideoFrame> frame =
+        VideoFrame::CreateBlackFrame(gfx::Size(1280, 720));
+    PaintInterstitial(frame, InterstitialType::BETWEEN_SESSIONS);
+  }
 }
 
 void CourierRenderer::Initialize(MediaResource* media_resource,
@@ -699,12 +707,14 @@
     return;
   }
   media_task_runner->PostTask(
-      FROM_HERE,
-      base::Bind(&CourierRenderer::PaintInterstitial, self, std::move(frame)));
+      FROM_HERE, base::Bind(&CourierRenderer::PaintInterstitial, self,
+                            std::move(frame), type));
 }
 
-void CourierRenderer::PaintInterstitial(scoped_refptr<VideoFrame> frame) {
+void CourierRenderer::PaintInterstitial(scoped_refptr<VideoFrame> frame,
+                                        InterstitialType type) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
+  interstitial_type_ = type;
   if (!video_renderer_sink_)
     return;
   video_renderer_sink_->PaintSingleFrame(frame);
diff --git a/media/remoting/courier_renderer.h b/media/remoting/courier_renderer.h
index 22643ec..969c1f33 100644
--- a/media/remoting/courier_renderer.h
+++ b/media/remoting/courier_renderer.h
@@ -136,7 +136,8 @@
 
   // Called to pass the newly-rendered interstitial VideoFrame to the
   // VideoRendererSink.
-  void PaintInterstitial(scoped_refptr<VideoFrame> frame);
+  void PaintInterstitial(scoped_refptr<VideoFrame> frame,
+                         InterstitialType type);
 
   // Called when |current_media_time_| is updated.
   void OnMediaTimeUpdated();
@@ -225,6 +226,9 @@
   // the data flow rates for metrics.
   base::RepeatingTimer data_flow_poll_timer_;
 
+  // Current type of the interstitial frame.
+  InterstitialType interstitial_type_ = InterstitialType::BETWEEN_SESSIONS;
+
   base::WeakPtrFactory<CourierRenderer> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CourierRenderer);
diff --git a/media/renderers/skcanvas_video_renderer.cc b/media/renderers/skcanvas_video_renderer.cc
index 5f76455..8a8fa7b 100644
--- a/media/renderers/skcanvas_video_renderer.cc
+++ b/media/renderers/skcanvas_video_renderer.cc
@@ -15,7 +15,6 @@
 #include "gpu/command_buffer/common/mailbox_holder.h"
 #include "media/base/data_buffer.h"
 #include "media/base/video_frame.h"
-#include "media/base/yuv_convert.h"
 #include "skia/ext/texture_handle.h"
 #include "third_party/libyuv/include/libyuv.h"
 #include "third_party/skia/include/core/SkImage.h"
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h
index 064fd17f..192d6f8 100644
--- a/media/test/pipeline_integration_test_base.h
+++ b/media/test/pipeline_integration_test_base.h
@@ -206,6 +206,7 @@
   MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
   MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
   MOCK_METHOD1(OnVideoOpacityChange, void(bool));
+  MOCK_METHOD0(OnVideoAverageKeyframeDistanceUpdate, void());
 };
 
 }  // namespace media
diff --git a/mojo/OWNERS b/mojo/OWNERS
index b03794cd..f233345 100644
--- a/mojo/OWNERS
+++ b/mojo/OWNERS
@@ -3,3 +3,5 @@
 rockot@chromium.org
 sky@chromium.org
 yzshen@chromium.org
+
+# COMPONENT: Internals>Mojo
diff --git a/net/BUILD.gn b/net/BUILD.gn
index a6c239c..a5b3c20d 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1342,6 +1342,8 @@
       "quic/platform/api/quic_stack_trace.h",
       "quic/platform/api/quic_str_cat.h",
       "quic/platform/api/quic_text_utils.h",
+      "quic/platform/api/quic_url.cc",
+      "quic/platform/api/quic_url.h",
       "quic/platform/api/quic_url_utils.cc",
       "quic/platform/api/quic_url_utils.h",
       "quic/platform/impl/quic_aligned_impl.h",
@@ -1364,6 +1366,8 @@
       "quic/platform/impl/quic_stack_trace_impl.h",
       "quic/platform/impl/quic_str_cat_impl.h",
       "quic/platform/impl/quic_text_utils_impl.h",
+      "quic/platform/impl/quic_url_impl.cc",
+      "quic/platform/impl/quic_url_impl.h",
       "quic/platform/impl/quic_url_utils_impl.cc",
       "quic/platform/impl/quic_url_utils_impl.h",
       "quic/quartc/quartc_alarm_factory.cc",
@@ -1542,6 +1546,7 @@
       "spdy/spdy_write_queue.cc",
       "spdy/spdy_write_queue.h",
       "spdy/write_scheduler.h",
+      "spdy/zero_copy_output_buffer.h",
       "ssl/client_cert_store.h",
       "ssl/client_cert_store_mac.cc",
       "ssl/client_cert_store_mac.h",
@@ -4502,6 +4507,7 @@
     "quic/platform/api/quic_reference_counted_test.cc",
     "quic/platform/api/quic_str_cat_test.cc",
     "quic/platform/api/quic_text_utils_test.cc",
+    "quic/platform/api/quic_url_test.cc",
     "quic/platform/api/quic_url_utils_test.cc",
     "quic/platform/impl/quic_chromium_clock_test.cc",
     "quic/platform/impl/quic_estimate_memory_usage_impl.h",
@@ -4624,6 +4630,8 @@
     "socket/unix_domain_server_socket_posix_unittest.cc",
     "socket/websocket_endpoint_lock_manager_unittest.cc",
     "socket/websocket_transport_client_socket_pool_unittest.cc",
+    "spdy/array_output_buffer.cc",
+    "spdy/array_output_buffer.h",
     "spdy/bidirectional_stream_spdy_impl_unittest.cc",
     "spdy/buffered_spdy_framer_unittest.cc",
     "spdy/fuzzing/hpack_fuzz_util_test.cc",
diff --git a/net/base/registry_controlled_domains/OWNERS b/net/base/registry_controlled_domains/OWNERS
index 2ba05a6..10be63d 100644
--- a/net/base/registry_controlled_domains/OWNERS
+++ b/net/base/registry_controlled_domains/OWNERS
@@ -1,3 +1,5 @@
 pam@chromium.org
 pkasting@chromium.org
 rsleevi@chromium.org
+
+# COMPONENT: Internals>Network
diff --git a/net/data/quic_http_response_cache_data/www.example.com/index.html b/net/data/quic_http_response_cache_data/test.example.com/index.html
similarity index 100%
rename from net/data/quic_http_response_cache_data/www.example.com/index.html
rename to net/data/quic_http_response_cache_data/test.example.com/index.html
diff --git a/net/data/quic_http_response_cache_data/www.example.com/map.html b/net/data/quic_http_response_cache_data/test.example.com/map.html
similarity index 96%
rename from net/data/quic_http_response_cache_data/www.example.com/map.html
rename to net/data/quic_http_response_cache_data/test.example.com/map.html
index 470faa1..b34c3b0 100644
--- a/net/data/quic_http_response_cache_data/www.example.com/map.html
+++ b/net/data/quic_http_response_cache_data/test.example.com/map.html
@@ -10,7 +10,7 @@
 X-UA-Compatible: IE=7
 Connection: close
 Content-Type: text/html; charset=ISO-8859-1
-X-Original-Url: http://www.example.com/site_map.html
+X-Original-Url: http://test.example.com/site_map.html
 
 
 <!doctype html>
diff --git a/net/data/quic_http_response_cache_data_with_push/www.example.com/favicon.ico b/net/data/quic_http_response_cache_data_with_push/test.example.com/favicon.ico
similarity index 94%
rename from net/data/quic_http_response_cache_data_with_push/www.example.com/favicon.ico
rename to net/data/quic_http_response_cache_data_with_push/test.example.com/favicon.ico
index b7b01b5..4cf168a 100644
--- a/net/data/quic_http_response_cache_data_with_push/www.example.com/favicon.ico
+++ b/net/data/quic_http_response_cache_data_with_push/test.example.com/favicon.ico
Binary files differ
diff --git a/net/data/quic_http_response_cache_data_with_push/www.example.com/index.html b/net/data/quic_http_response_cache_data_with_push/test.example.com/index.html
similarity index 77%
rename from net/data/quic_http_response_cache_data_with_push/www.example.com/index.html
rename to net/data/quic_http_response_cache_data_with_push/test.example.com/index.html
index bfcb614..d5349489 100644
--- a/net/data/quic_http_response_cache_data_with_push/www.example.com/index.html
+++ b/net/data/quic_http_response_cache_data_with_push/test.example.com/index.html
@@ -9,7 +9,7 @@
 Keep-Alive: timeout=5, max=100
 Connection: close
 Content-Type: text/html
-X-Original-Url: https://www.example.com/
-X-Push-Url: https://www.example.com/kitten-1.jpg
+X-Original-Url: https://test.example.com/
+X-Push-Url: https://test.example.com/kitten-1.jpg
 
 This is a test page.
diff --git a/net/data/quic_http_response_cache_data_with_push/www.example.com/index2.html b/net/data/quic_http_response_cache_data_with_push/test.example.com/index2.html
similarity index 67%
rename from net/data/quic_http_response_cache_data_with_push/www.example.com/index2.html
rename to net/data/quic_http_response_cache_data_with_push/test.example.com/index2.html
index 58c5db9..4b9b5e44 100644
--- a/net/data/quic_http_response_cache_data_with_push/www.example.com/index2.html
+++ b/net/data/quic_http_response_cache_data_with_push/test.example.com/index2.html
@@ -9,8 +9,8 @@
 Keep-Alive: timeout=5, max=100
 Connection: close
 Content-Type: text/html
-X-Original-Url: https://www.example.com/index2.html
-X-Push-Url: https://www.example.com/kitten-1.jpg
-X-Push-Url: https://www.example.com/favicon.ico
+X-Original-Url: https://test.example.com/index2.html
+X-Push-Url: https://test.example.com/kitten-1.jpg
+X-Push-Url: https://test.example.com/favicon.ico
 
 This is a test page.
diff --git a/net/data/quic_http_response_cache_data_with_push/www.example.com/kitten-1.jpg b/net/data/quic_http_response_cache_data_with_push/test.example.com/kitten-1.jpg
similarity index 99%
rename from net/data/quic_http_response_cache_data_with_push/www.example.com/kitten-1.jpg
rename to net/data/quic_http_response_cache_data_with_push/test.example.com/kitten-1.jpg
index 25d543b8..27c553b 100644
--- a/net/data/quic_http_response_cache_data_with_push/www.example.com/kitten-1.jpg
+++ b/net/data/quic_http_response_cache_data_with_push/test.example.com/kitten-1.jpg
Binary files differ
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index c078986f..dfd4752 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -2452,7 +2452,7 @@
   // Abandon all ProbeJobs.
   probe_weak_ptr_factory_.InvalidateWeakPtrs();
   if (cache_.get()) {
-    cache_->clear();
+    cache_->OnNetworkChange();
     cache_hit_callbacks_.clear();
   }
 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index 3edee0f7..0c960af 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "net/http/http_byte_range.h"
+#include "net/http/http_util.h"
 #include "net/log/net_log_capture_mode.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -94,6 +95,40 @@
       public ::testing::WithParamInterface<TestData> {
 };
 
+// Returns a simple text serialization of the given
+// |HttpResponseHeaders|. This is used by tests to verify that an
+// |HttpResponseHeaders| matches an expectation string.
+//
+//  * One line per header, written as:
+//        HEADER_NAME: HEADER_VALUE\n
+//  * The original case of header names is preserved.
+//  * Whitespace around head names/values is stripped.
+//  * Repeated headers are not aggregated.
+//  * Headers are listed in their original order.
+std::string ToSimpleString(const scoped_refptr<HttpResponseHeaders>& parsed) {
+  std::string result = parsed->GetStatusLine() + "\n";
+
+  size_t iter = 0;
+  std::string name;
+  std::string value;
+  while (parsed->EnumerateHeaderLines(&iter, &name, &value)) {
+    std::string new_line = name + ": " + value + "\n";
+
+    // Verify that |name| and |value| do not contain ':' or '\n' (if they did
+    // it would make this serialized format ambiguous).
+    if (std::count(new_line.begin(), new_line.end(), '\n') != 1 ||
+        std::count(new_line.begin(), new_line.end(), ':') != 1) {
+      ADD_FAILURE() << "Unexpected characters in the header name or value: "
+                    << new_line;
+      return result;
+    }
+
+    result += new_line;
+  }
+
+  return result;
+}
+
 TEST_P(CommonHttpResponseHeadersTest, TestCommon) {
   const TestData test = GetParam();
 
@@ -101,10 +136,9 @@
   HeadersToRaw(&raw_headers);
   std::string expected_headers(test.expected_headers);
 
-  std::string headers;
   scoped_refptr<HttpResponseHeaders> parsed(
       new HttpResponseHeaders(raw_headers));
-  parsed->GetNormalizedHeaders(&headers);
+  std::string headers = ToSimpleString(parsed);
 
   // Transform to readable output format (so it's easier to see diffs).
   std::replace(headers.begin(), headers.end(), ' ', '_');
@@ -128,7 +162,8 @@
 
      "HTTP/1.1 202 Accepted\n"
      "Content-TYPE: text/html; charset=utf-8\n"
-     "Set-Cookie: a, b\n",
+     "Set-Cookie: a\n"
+     "Set-Cookie: b\n",
 
      HttpVersion(1, 1), 202, "Accepted"},
     {// Normalize leading whitespace.
@@ -139,7 +174,8 @@
      "Set-Cookie:   b \n",
 
      "HTTP/1.1 202 Accepted\n"
-     "Set-Cookie: a, b\n",
+     "Set-Cookie: a\n"
+     "Set-Cookie: b\n",
 
      HttpVersion(1, 1), 202, "Accepted"},
     {// Keep whitespace within status text.
@@ -245,22 +281,24 @@
      "HTTP/1.0 200 OK\n",
 
      HttpVersion(1, 0), 200, "OK"},
-    {// Consolidate Set-Cookie headers.
+    {// Has multiple Set-Cookie headers.
      "HTTP/1.1 200 OK\n"
      "Set-Cookie: x=1\n"
      "Set-Cookie: y=2\n",
 
      "HTTP/1.1 200 OK\n"
-     "Set-Cookie: x=1, y=2\n",
+     "Set-Cookie: x=1\n"
+     "Set-Cookie: y=2\n",
 
      HttpVersion(1, 1), 200, "OK"},
-    {// Consolidate cache-control headers.
+    {// Has multiple cache-control headers.
      "HTTP/1.1 200 OK\n"
      "Cache-control: private\n"
      "cache-Control: no-store\n",
 
      "HTTP/1.1 200 OK\n"
-     "Cache-control: private, no-store\n",
+     "Cache-control: private\n"
+     "cache-Control: no-store\n",
 
      HttpVersion(1, 1), 200, "OK"},
 };
@@ -293,9 +331,7 @@
   base::PickleIterator iter(pickle);
   scoped_refptr<HttpResponseHeaders> parsed2(new HttpResponseHeaders(&iter));
 
-  std::string h2;
-  parsed2->GetNormalizedHeaders(&h2);
-  EXPECT_EQ(std::string(test.expected_headers), h2);
+  EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed2));
 }
 
 const struct PersistData persistence_tests[] = {
@@ -305,7 +341,8 @@
      "cache-Control:no-store\n",
 
      "HTTP/1.1 200 OK\n"
-     "Cache-control: private, no-store\n"},
+     "Cache-control: private\n"
+     "cache-Control: no-store\n"},
     {HttpResponseHeaders::PERSIST_SANS_HOP_BY_HOP,
      "HTTP/1.1 200 OK\n"
      "connection: keep-alive\n"
@@ -393,8 +430,9 @@
      "Foo: 3\n",
 
      "HTTP/1.1 200 OK\n"
-     "Foo: 1, 3\n"
-     "Bar: 2\n"},
+     "Foo: 1\n"
+     "Bar: 2\n"
+     "Foo: 3\n"},
     // Header name appears twice, separated by another header (type 2).
     {HttpResponseHeaders::PERSIST_ALL,
      "HTTP/1.1 200 OK\n"
@@ -403,8 +441,9 @@
      "Foo: 4\n",
 
      "HTTP/1.1 200 OK\n"
-     "Foo: 1, 3, 4\n"
-     "Bar: 2\n"},
+     "Foo: 1, 3\n"
+     "Bar: 2\n"
+     "Foo: 4\n"},
     // Test filtering of cookie headers.
     {HttpResponseHeaders::PERSIST_SANS_COOKIES,
      "HTTP/1.1 200 OK\n"
@@ -1017,9 +1056,7 @@
 
   parsed->Update(*new_parsed.get());
 
-  std::string resulting_headers;
-  parsed->GetNormalizedHeaders(&resulting_headers);
-  EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
+  EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
 }
 
 const UpdateTestData update_tests[] = {
@@ -1677,9 +1714,7 @@
   std::string new_header(test.new_header);
   parsed->AddHeader(new_header);
 
-  std::string resulting_headers;
-  parsed->GetNormalizedHeaders(&resulting_headers);
-  EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
+  EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
 }
 
 const AddHeaderTestData add_header_tests[] = {
@@ -1733,9 +1768,7 @@
   std::string name(test.to_remove);
   parsed->RemoveHeader(name);
 
-  std::string resulting_headers;
-  parsed->GetNormalizedHeaders(&resulting_headers);
-  EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
+  EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
 }
 
 const RemoveHeaderTestData remove_header_tests[] = {
@@ -1792,9 +1825,7 @@
   }
   parsed->RemoveHeaders(to_remove);
 
-  std::string resulting_headers;
-  parsed->GetNormalizedHeaders(&resulting_headers);
-  EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
+  EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
 }
 
 const RemoveHeadersTestData remove_headers_tests[] = {
@@ -1855,9 +1886,7 @@
   std::string value(test.to_remove_value);
   parsed->RemoveHeaderLine(name, value);
 
-  std::string resulting_headers;
-  parsed->GetNormalizedHeaders(&resulting_headers);
-  EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
+  EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
 }
 
 const RemoveIndividualHeaderTestData remove_individual_header_tests[] = {
@@ -1958,9 +1987,7 @@
   std::string name(test.new_status);
   parsed->ReplaceStatusLine(name);
 
-  std::string resulting_headers;
-  parsed->GetNormalizedHeaders(&resulting_headers);
-  EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
+  EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
 }
 
 const ReplaceStatusTestData replace_status_tests[] = {
@@ -2023,18 +2050,15 @@
   scoped_refptr<HttpResponseHeaders> parsed(
       new HttpResponseHeaders(orig_headers + '\0'));
   int64_t content_size = parsed->GetContentLength();
-  std::string resulting_headers;
 
   // Update headers without replacing status line.
   parsed->UpdateWithNewRange(range, content_size, false);
-  parsed->GetNormalizedHeaders(&resulting_headers);
-  EXPECT_EQ(std::string(test.expected_headers), resulting_headers);
+  EXPECT_EQ(std::string(test.expected_headers), ToSimpleString(parsed));
 
   // Replace status line too.
   parsed->UpdateWithNewRange(range, content_size, true);
-  parsed->GetNormalizedHeaders(&resulting_headers);
   EXPECT_EQ(std::string(test.expected_headers_with_replaced_status),
-            resulting_headers);
+            ToSimpleString(parsed));
 }
 
 const UpdateWithNewRangeTestData update_range_tests[] = {
@@ -2085,11 +2109,7 @@
   EXPECT_EQ(parsed->GetContentLength(), recreated->GetContentLength());
   EXPECT_EQ(parsed->IsKeepAlive(), recreated->IsKeepAlive());
 
-  std::string normalized_parsed;
-  parsed->GetNormalizedHeaders(&normalized_parsed);
-  std::string normalized_recreated;
-  parsed->GetNormalizedHeaders(&normalized_recreated);
-  EXPECT_EQ(normalized_parsed, normalized_recreated);
+  EXPECT_EQ(ToSimpleString(parsed), ToSimpleString(parsed));
 }
 
 TEST_F(HttpResponseHeadersCacheControlTest, AbsentMaxAgeReturnsFalse) {
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 2aa4d31..3aa590ec 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -55,7 +55,6 @@
 #include "net/spdy/spdy_session_pool.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/ssl_cert_request_info.h"
-#include "net/ssl/ssl_connection_status_flags.h"
 #include "url/url_constants.h"
 
 namespace net {
@@ -1259,19 +1258,11 @@
     return ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY;
   }
 
-  SSLInfo ssl_info;
-  if (spdy_session->GetSSLInfo(&ssl_info)) {
-    UMA_HISTOGRAM_SPARSE_SLOWLY(
-        "Net.Http2SSLCipherSuite",
-        SSLConnectionStatusToCipherSuite(ssl_info.connection_status));
-  }
-
   new_spdy_session_ = spdy_session;
   spdy_session_direct_ = direct;
   const HostPortPair host_port_pair = spdy_session_key.host_port_pair();
-  bool is_https = ssl_info.is_valid();
   url::SchemeHostPort scheme_host_port(
-      is_https ? url::kHttpsScheme : url::kHttpScheme, host_port_pair.host(),
+      using_ssl_ ? url::kHttpsScheme : url::kHttpScheme, host_port_pair.host(),
       host_port_pair.port());
 
   HttpServerProperties* http_server_properties =
diff --git a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
index afcee7f9..8c6b800 100644
--- a/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/chromium/bidirectional_stream_quic_impl_unittest.cc
@@ -435,7 +435,7 @@
         base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
         QuicServerId(kDefaultServerHostName, kDefaultServerPort,
                      PRIVACY_MODE_DISABLED),
-        kQuicYieldAfterPacketsRead,
+        /*require_confirmation=*/false, kQuicYieldAfterPacketsRead,
         QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
         /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
         "CONNECTION_UNKNOWN", dns_start, dns_end, &push_promise_index_, nullptr,
@@ -443,8 +443,7 @@
         /*socket_performance_watcher=*/nullptr, net_log().bound().net_log()));
     session_->Initialize();
     TestCompletionCallback callback;
-    session_->CryptoConnect(/*require_confirmation=*/false,
-                            callback.callback());
+    session_->CryptoConnect(callback.callback());
     EXPECT_TRUE(session_->IsEncryptionEstablished());
   }
 
diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc
index e3f4cfe6..9d586835 100644
--- a/net/quic/chromium/quic_chromium_client_session.cc
+++ b/net/quic/chromium/quic_chromium_client_session.cc
@@ -235,6 +235,7 @@
     TransportSecurityState* transport_security_state,
     std::unique_ptr<QuicServerInfo> server_info,
     const QuicServerId& server_id,
+    bool require_confirmation,
     int yield_after_packets,
     QuicTime::Delta yield_after_duration,
     int cert_verify_flags,
@@ -250,7 +251,7 @@
     NetLog* net_log)
     : QuicClientSessionBase(connection, push_promise_index, config),
       server_id_(server_id),
-      require_confirmation_(false),
+      require_confirmation_(require_confirmation),
       stream_factory_(stream_factory),
       transport_security_state_(transport_security_state),
       server_info_(std::move(server_info)),
@@ -663,9 +664,7 @@
 }
 
 int QuicChromiumClientSession::CryptoConnect(
-    bool require_confirmation,
     const CompletionCallback& callback) {
-  require_confirmation_ = require_confirmation;
   connect_timing_.connect_start = base::TimeTicks::Now();
   RecordHandshakeState(STATE_STARTED);
   DCHECK(flow_controller());
diff --git a/net/quic/chromium/quic_chromium_client_session.h b/net/quic/chromium/quic_chromium_client_session.h
index 12b007aa..7d9a87b 100644
--- a/net/quic/chromium/quic_chromium_client_session.h
+++ b/net/quic/chromium/quic_chromium_client_session.h
@@ -126,6 +126,7 @@
       TransportSecurityState* transport_security_state,
       std::unique_ptr<QuicServerInfo> server_info,
       const QuicServerId& server_id,
+      bool require_confirmation,
       int yield_after_packets,
       QuicTime::Delta yield_after_duration,
       int cert_verify_flags,
@@ -213,8 +214,7 @@
                                  std::vector<uint8_t>* out) override;
 
   // Performs a crypto handshake with the server.
-  int CryptoConnect(bool require_confirmation,
-                    const CompletionCallback& callback);
+  int CryptoConnect(const CompletionCallback& callback);
 
   // Resumes a crypto handshake with the server after a timeout.
   int ResumeCryptoConnect(const CompletionCallback& callback);
diff --git a/net/quic/chromium/quic_chromium_client_session_test.cc b/net/quic/chromium/quic_chromium_client_session_test.cc
index e8772e5..8d75a51 100644
--- a/net/quic/chromium/quic_chromium_client_session_test.cc
+++ b/net/quic/chromium/quic_chromium_client_session_test.cc
@@ -121,7 +121,7 @@
         &transport_security_state_,
         base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
         QuicServerId(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED),
-        kQuicYieldAfterPacketsRead,
+        /*require_confirmation=*/false, kQuicYieldAfterPacketsRead,
         QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
         /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
         "CONNECTION_UNKNOWN", base::TimeTicks::Now(), base::TimeTicks::Now(),
@@ -143,7 +143,7 @@
   }
 
   void CompleteCryptoHandshake() {
-    ASSERT_THAT(session_->CryptoConnect(false, callback_.callback()), IsOk());
+    ASSERT_THAT(session_->CryptoConnect(callback_.callback()), IsOk());
   }
 
   QuicChromiumPacketWriter* CreateQuicChromiumPacketWriter(
diff --git a/net/quic/chromium/quic_http_stream_test.cc b/net/quic/chromium/quic_http_stream_test.cc
index d57d2db..ee84931 100644
--- a/net/quic/chromium/quic_http_stream_test.cc
+++ b/net/quic/chromium/quic_http_stream_test.cc
@@ -317,7 +317,7 @@
         base::WrapUnique(static_cast<QuicServerInfo*>(nullptr)),
         QuicServerId(kDefaultServerHostName, kDefaultServerPort,
                      PRIVACY_MODE_DISABLED),
-        kQuicYieldAfterPacketsRead,
+        /*require_confirmation=*/false, kQuicYieldAfterPacketsRead,
         QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds),
         /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_,
         "CONNECTION_UNKNOWN", dns_start, dns_end, &push_promise_index_, nullptr,
@@ -325,8 +325,7 @@
         /*socket_performance_watcher=*/nullptr, net_log_.bound().net_log()));
     session_->Initialize();
     TestCompletionCallback callback;
-    session_->CryptoConnect(/*require_confirmation=*/false,
-                            callback.callback());
+    session_->CryptoConnect(callback.callback());
     EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
     stream_.reset(use_closing_stream_
                       ? new AutoClosingStream(session_->GetWeakPtr())
diff --git a/net/quic/chromium/quic_stream_factory.cc b/net/quic/chromium/quic_stream_factory.cc
index 60a70d08..6e63b9be0 100644
--- a/net/quic/chromium/quic_stream_factory.cc
+++ b/net/quic/chromium/quic_stream_factory.cc
@@ -588,10 +588,13 @@
 int QuicStreamFactory::Job::DoConnect() {
   io_state_ = STATE_CONNECT_COMPLETE;
 
-  int rv =
-      factory_->CreateSession(key_, cert_verify_flags_, std::move(server_info_),
-                              address_list_, dns_resolution_start_time_,
-                              dns_resolution_end_time_, net_log_, &session_);
+  bool require_confirmation = factory_->require_confirmation() ||
+                              was_alternative_service_recently_broken_;
+
+  int rv = factory_->CreateSession(
+      key_, cert_verify_flags_, std::move(server_info_), require_confirmation,
+      address_list_, dns_resolution_start_time_, dns_resolution_end_time_,
+      net_log_, &session_);
   if (rv != OK) {
     DCHECK(rv != ERR_IO_PENDING);
     DCHECK(!session_);
@@ -604,11 +607,8 @@
   session_->StartReading();
   if (!session_->connection()->connected())
     return ERR_QUIC_PROTOCOL_ERROR;
-  bool require_confirmation = factory_->require_confirmation() ||
-                              was_alternative_service_recently_broken_;
 
   rv = session_->CryptoConnect(
-      require_confirmation,
       base::Bind(&QuicStreamFactory::Job::OnIOComplete, GetWeakPtr()));
 
   if (!session_->connection()->connected() &&
@@ -1650,6 +1650,7 @@
     const QuicSessionKey& key,
     int cert_verify_flags,
     std::unique_ptr<QuicServerInfo> server_info,
+    bool require_confirmation,
     const AddressList& address_list,
     base::TimeTicks dns_resolution_start_time,
     base::TimeTicks dns_resolution_end_time,
@@ -1730,11 +1731,11 @@
   *session = new QuicChromiumClientSession(
       connection, std::move(socket), this, quic_crypto_client_stream_factory_,
       clock_.get(), transport_security_state_, std::move(server_info),
-      server_id, yield_after_packets_, yield_after_duration_, cert_verify_flags,
-      config, &crypto_config_, network_connection_.connection_description(),
-      dns_resolution_start_time, dns_resolution_end_time, &push_promise_index_,
-      push_delegate_, task_runner_, std::move(socket_performance_watcher),
-      net_log.net_log());
+      server_id, require_confirmation, yield_after_packets_,
+      yield_after_duration_, cert_verify_flags, config, &crypto_config_,
+      network_connection_.connection_description(), dns_resolution_start_time,
+      dns_resolution_end_time, &push_promise_index_, push_delegate_,
+      task_runner_, std::move(socket_performance_watcher), net_log.net_log());
 
   all_sessions_[*session] = key;  // owning pointer
   writer->set_delegate(*session);
diff --git a/net/quic/chromium/quic_stream_factory.h b/net/quic/chromium/quic_stream_factory.h
index 047623a1..2d01e34 100644
--- a/net/quic/chromium/quic_stream_factory.h
+++ b/net/quic/chromium/quic_stream_factory.h
@@ -453,6 +453,7 @@
   int CreateSession(const QuicSessionKey& key,
                     int cert_verify_flags,
                     std::unique_ptr<QuicServerInfo> quic_server_info,
+                    bool require_confirmation,
                     const AddressList& address_list,
                     base::TimeTicks dns_resolution_start_time,
                     base::TimeTicks dns_resolution_end_time,
diff --git a/net/quic/platform/api/quic_url.cc b/net/quic/platform/api/quic_url.cc
new file mode 100644
index 0000000..950f9dd
--- /dev/null
+++ b/net/quic/platform/api/quic_url.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 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 "net/quic/platform/api/quic_url.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+QuicUrl::QuicUrl(StringPiece url) : impl_(url) {}
+
+QuicUrl::QuicUrl(StringPiece url, StringPiece default_scheme)
+    : impl_(url, default_scheme) {}
+
+QuicUrl::QuicUrl(const QuicUrl& url) : impl_(url.impl()) {}
+
+bool QuicUrl::IsValid() const {
+  return impl_.IsValid();
+}
+
+string QuicUrl::ToString() const {
+  return impl_.ToStringIfValid();
+}
+
+string QuicUrl::HostPort() const {
+  return impl_.HostPort();
+}
+
+string QuicUrl::PathParamsQuery() const {
+  return impl_.PathParamsQuery();
+}
+
+string QuicUrl::host() const {
+  return impl_.host();
+}
+
+string QuicUrl::path() const {
+  return impl_.path();
+}
+
+string QuicUrl::scheme() const {
+  return impl_.scheme();
+}
+
+uint16_t QuicUrl::port() const {
+  return impl_.port();
+}
+
+}  // namespace net
diff --git a/net/quic/platform/api/quic_url.h b/net/quic/platform/api/quic_url.h
new file mode 100644
index 0000000..931fcbd
--- /dev/null
+++ b/net/quic/platform/api/quic_url.h
@@ -0,0 +1,68 @@
+// Copyright (c) 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 NET_QUIC_PLATFORM_API_QUIC_URL_H_
+#define NET_QUIC_PLATFORM_API_QUIC_URL_H_
+
+#include "net/quic/platform/api/quic_export.h"
+#include "net/quic/platform/impl/quic_url_impl.h"
+
+namespace net {
+
+// QuicUrl stores a representation of a URL.
+class QUIC_EXPORT_PRIVATE QuicUrl {
+ public:
+  // Constructs an empty QuicUrl.
+  QuicUrl() = default;
+
+  // Constructs a QuicUrl from the url string |url|.
+  // NOTE: If |url| doesn't have a scheme, it will have an empty scheme
+  // field. If that's not what you want, use the QuicUrlImpl(url,
+  // default_scheme) form below.
+  explicit QuicUrl(base::StringPiece url);
+
+  // Constructs a QuicUrl from |url|, assuming that the scheme for the QuicUrl
+  // is |default_scheme| if there is no scheme specified in |url|.
+  QuicUrl(base::StringPiece url, base::StringPiece default_scheme);
+
+  QuicUrl(const QuicUrl& url);
+
+  // Returns false if any of these conditions occur:
+  // No scheme specified
+  // Host name too long (the maximum hostname length is platform-dependent)
+  // Invalid characters in host name, path or params
+  // Invalid port number (e.g. greater than 65535)
+  bool IsValid() const;
+
+  // PLEASE NOTE: ToString(), HostPort(), PathParamsQuery(), scheme(), host(),
+  // path() and port() functions should be only called on a valid QuicUrl.
+  // Return values are platform-dependent if called on a invalid QuicUrl.
+
+  // Returns full text of the QuicUrl.
+  std::string ToString() const;
+
+  // Returns host:port.
+  // If the host is empty, it will return an empty string.
+  // If the host is an IPv6 address, it will be bracketed.
+  // If port is not present or is equal to default_port of scheme (e.g., port
+  // 80 for HTTP), it won't be returned.
+  std::string HostPort() const;
+
+  // Returns a string assembles path, parameters and query.
+  std::string PathParamsQuery() const;
+
+  std::string scheme() const;
+  std::string host() const;
+  std::string path() const;
+  uint16_t port() const;
+
+  const QuicUrlImpl& impl() const { return impl_; }
+
+ private:
+  QuicUrlImpl impl_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_PLATFORM_API_QUIC_URL_H_
diff --git a/net/quic/platform/api/quic_url_test.cc b/net/quic/platform/api/quic_url_test.cc
new file mode 100644
index 0000000..8f575c5
--- /dev/null
+++ b/net/quic/platform/api/quic_url_test.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 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 "net/quic/platform/api/quic_url.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace net {
+namespace test {
+namespace {
+
+TEST(QuicUrlTest, Basic) {
+  // No scheme specified.
+  string url_str = "www.example.com";
+  QuicUrl url(url_str);
+  EXPECT_FALSE(url.IsValid());
+
+  // scheme is HTTP.
+  url_str = "http://www.example.com";
+  url = QuicUrl(url_str);
+  EXPECT_TRUE(url.IsValid());
+  EXPECT_EQ("http://www.example.com/", url.ToString());
+  EXPECT_EQ("http", url.scheme());
+  EXPECT_EQ("www.example.com", url.HostPort());
+  EXPECT_EQ("/", url.PathParamsQuery());
+  EXPECT_EQ(80u, url.port());
+
+  // scheme is HTTPS.
+  url_str = "https://www.example.com:12345/path/to/resource?a=1&campaign=2";
+  url = QuicUrl(url_str);
+  EXPECT_TRUE(url.IsValid());
+  EXPECT_EQ("https://www.example.com:12345/path/to/resource?a=1&campaign=2",
+            url.ToString());
+  EXPECT_EQ("https", url.scheme());
+  EXPECT_EQ("www.example.com:12345", url.HostPort());
+  EXPECT_EQ("/path/to/resource?a=1&campaign=2", url.PathParamsQuery());
+  EXPECT_EQ(12345u, url.port());
+
+  // scheme is FTP.
+  url_str = "ftp://www.example.com";
+  url = QuicUrl(url_str);
+  EXPECT_TRUE(url.IsValid());
+  EXPECT_EQ("ftp://www.example.com/", url.ToString());
+  EXPECT_EQ("ftp", url.scheme());
+  EXPECT_EQ("www.example.com", url.HostPort());
+  EXPECT_EQ("/", url.PathParamsQuery());
+  EXPECT_EQ(21u, url.port());
+}
+
+TEST(QuicUrlTest, DefaultScheme) {
+  // Default scheme to HTTP.
+  string url_str = "www.example.com";
+  QuicUrl url(url_str, "http");
+  EXPECT_EQ("http://www.example.com/", url.ToString());
+  EXPECT_EQ("http", url.scheme());
+
+  // URL already has a scheme specified.
+  url_str = "http://www.example.com";
+  url = QuicUrl(url_str, "https");
+  EXPECT_EQ("http://www.example.com/", url.ToString());
+  EXPECT_EQ("http", url.scheme());
+
+  // Default scheme to FTP.
+  url_str = "www.example.com";
+  url = QuicUrl(url_str, "ftp");
+  EXPECT_EQ("ftp://www.example.com/", url.ToString());
+  EXPECT_EQ("ftp", url.scheme());
+}
+
+TEST(QuicUrlTest, IsValid) {
+  string url_str =
+      "ftp://www.example.com:12345/path/to/resource?a=1&campaign=2";
+  EXPECT_TRUE(QuicUrl(url_str).IsValid());
+
+  // Invalid characters in host name.
+  url_str = "https://www%.example.com:12345/path/to/resource?a=1&campaign=2";
+  EXPECT_FALSE(QuicUrl(url_str).IsValid());
+
+  // Invalid characters in scheme.
+  url_str = "%http://www.example.com:12345/path/to/resource?a=1&campaign=2";
+  EXPECT_FALSE(QuicUrl(url_str).IsValid());
+
+  // Host name too long.
+  string host(1024, 'a');
+  url_str = "https://" + host;
+  EXPECT_FALSE(QuicUrl(url_str).IsValid());
+
+  // Invalid port number.
+  url_str = "https://www..example.com:123456/path/to/resource?a=1&campaign=2";
+  EXPECT_FALSE(QuicUrl(url_str).IsValid());
+}
+
+TEST(QuicUrlTest, HostPort) {
+  string url_str = "http://www.example.com/";
+  QuicUrl url(url_str);
+  EXPECT_EQ("www.example.com", url.HostPort());
+  EXPECT_EQ("www.example.com", url.host());
+  EXPECT_EQ(80u, url.port());
+
+  url_str = "http://www.example.com:80/";
+  url = QuicUrl(url_str);
+  EXPECT_EQ("www.example.com", url.HostPort());
+  EXPECT_EQ("www.example.com", url.host());
+  EXPECT_EQ(80u, url.port());
+
+  url_str = "http://www.example.com:81/";
+  url = QuicUrl(url_str);
+  EXPECT_EQ("www.example.com:81", url.HostPort());
+  EXPECT_EQ("www.example.com", url.host());
+  EXPECT_EQ(81u, url.port());
+
+  url_str = "https://192.168.1.1:443/";
+  url = QuicUrl(url_str);
+  EXPECT_EQ("192.168.1.1", url.HostPort());
+  EXPECT_EQ("192.168.1.1", url.host());
+  EXPECT_EQ(443u, url.port());
+
+  url_str = "http://[2001::1]:80/";
+  url = QuicUrl(url_str);
+  EXPECT_EQ("[2001::1]", url.HostPort());
+  EXPECT_EQ("2001::1", url.host());
+  EXPECT_EQ(80u, url.port());
+
+  url_str = "http://[2001::1]:81/";
+  url = QuicUrl(url_str);
+  EXPECT_EQ("[2001::1]:81", url.HostPort());
+  EXPECT_EQ("2001::1", url.host());
+  EXPECT_EQ(81u, url.port());
+}
+
+TEST(QuicUrlTest, PathParamsQuery) {
+  string url_str =
+      "https://www.example.com:12345/path/to/resource?a=1&campaign=2";
+  QuicUrl url(url_str);
+  EXPECT_EQ("/path/to/resource?a=1&campaign=2", url.PathParamsQuery());
+  EXPECT_EQ("/path/to/resource", url.path());
+
+  url_str = "https://www.example.com/?";
+  url = QuicUrl(url_str);
+  EXPECT_EQ("/?", url.PathParamsQuery());
+  EXPECT_EQ("/", url.path());
+
+  url_str = "https://www.example.com/";
+  url = QuicUrl(url_str);
+  EXPECT_EQ("/", url.PathParamsQuery());
+  EXPECT_EQ("/", url.path());
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace net
diff --git a/net/quic/platform/impl/quic_url_impl.cc b/net/quic/platform/impl/quic_url_impl.cc
new file mode 100644
index 0000000..76f5a540c
--- /dev/null
+++ b/net/quic/platform/impl/quic_url_impl.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 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 "net/quic/platform/impl/quic_url_impl.h"
+
+#include "net/quic/platform/api/quic_text_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+QuicUrlImpl::QuicUrlImpl(StringPiece url) : url_(url) {}
+
+QuicUrlImpl::QuicUrlImpl(StringPiece url, StringPiece default_scheme)
+    : url_(url) {
+  if (url_.has_scheme()) {
+    return;
+  }
+  string buffer = default_scheme.as_string() + "://" + url.as_string();
+  url_ = GURL(buffer);
+}
+
+QuicUrlImpl::QuicUrlImpl(const QuicUrlImpl& url) : url_(url.url()) {}
+
+string QuicUrlImpl::ToStringIfValid() const {
+  if (IsValid()) {
+    return url_.spec();
+  }
+  return "";
+}
+
+bool QuicUrlImpl::IsValid() const {
+  if (!url_.is_valid() || !url_.has_scheme()) {
+    return false;
+  }
+
+  if (url_.has_host() && url_.host().length() > kMaxHostNameLength) {
+    return false;
+  }
+
+  return true;
+}
+
+string QuicUrlImpl::HostPort() const {
+  if (!IsValid() || !url_.has_host()) {
+    return "";
+  }
+
+  string buffer = url_.host();
+  int port = url_.IntPort();
+  string scheme = url_.scheme();
+  if (port == url::PORT_UNSPECIFIED ||
+      (url_.IsStandard() &&
+       port == url::DefaultPortForScheme(scheme.c_str(), scheme.length()))) {
+    return buffer;
+  }
+  buffer = buffer + ":" + std::to_string(port);
+  return buffer;
+}
+
+string QuicUrlImpl::PathParamsQuery() const {
+  if (!IsValid() || !url_.has_path()) {
+    return "/";
+  }
+
+  return url_.PathForRequest();
+}
+
+string QuicUrlImpl::scheme() const {
+  if (!IsValid()) {
+    return "";
+  }
+
+  return url_.scheme();
+}
+
+string QuicUrlImpl::host() const {
+  if (!IsValid()) {
+    return "";
+  }
+
+  return url_.HostNoBrackets();
+}
+
+string QuicUrlImpl::path() const {
+  if (!IsValid()) {
+    return "";
+  }
+
+  return url_.path();
+}
+
+uint16_t QuicUrlImpl::port() const {
+  if (!IsValid()) {
+    return 0;
+  }
+
+  int port = url_.EffectiveIntPort();
+  if (port == url::PORT_UNSPECIFIED) {
+    return 0;
+  }
+  return port;
+}
+
+}  // namespace net
diff --git a/net/quic/platform/impl/quic_url_impl.h b/net/quic/platform/impl/quic_url_impl.h
new file mode 100644
index 0000000..bb688a9c
--- /dev/null
+++ b/net/quic/platform/impl/quic_url_impl.h
@@ -0,0 +1,66 @@
+// Copyright (c) 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 NET_QUIC_PLATFORM_IMPL_QUIC_URL_IMPL_H_
+#define NET_QUIC_PLATFORM_IMPL_QUIC_URL_IMPL_H_
+
+#include "net/quic/platform/api/quic_export.h"
+#include "url/gurl.h"
+
+namespace net {
+
+class QUIC_EXPORT_PRIVATE QuicUrlImpl {
+ public:
+  static const size_t kMaxHostNameLength = 256;
+
+  // Constructs an empty QuicUrl.
+  QuicUrlImpl() = default;
+
+  // Constructs a QuicUrlImpl from the url string |url|.
+  // NOTE: If |url| doesn't have a scheme, it will have an empty scheme
+  // field. If that's not what you want, use the QuicUrlImpl(url,
+  // default_scheme) form below.
+  explicit QuicUrlImpl(base::StringPiece url);
+
+  // Constructs a QuicUrlImpl from |url|, assuming that the scheme for the URL
+  // is |default_scheme| if there is no scheme specified in |url|.
+  QuicUrlImpl(base::StringPiece url, base::StringPiece default_scheme);
+
+  QuicUrlImpl(const QuicUrlImpl& url);
+
+  // Returns false if any of these conditions occur:
+  // No scheme specified
+  // Host name too long (> 256 bytes)
+  // Invalid characters in host name, path or params
+  // Invalid port number (e.g. greater than 65535)
+  bool IsValid() const;
+
+  // Returns full text of the QuicUrlImpl if it is valid. Return empty string
+  // otherwise.
+  std::string ToStringIfValid() const;
+
+  // Returns host:port.
+  // If the host is empty, it will return an empty std::string.
+  // If the host is an IPv6 address, it will be bracketed.
+  // If port is not present or is equal to default_port of scheme (e.g., port
+  // 80 for HTTP), it won't be returned.
+  std::string HostPort() const;
+
+  // Returns a string assembles path, parameters and query.
+  std::string PathParamsQuery() const;
+
+  std::string scheme() const;
+  std::string host() const;
+  std::string path() const;
+  uint16_t port() const;
+
+  const GURL& url() const { return url_; }
+
+ private:
+  GURL url_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_PLATFORM_IMPL_QUIC_URL_IMPL_H_
diff --git a/net/spdy/array_output_buffer.cc b/net/spdy/array_output_buffer.cc
new file mode 100644
index 0000000..2ce82fc
--- /dev/null
+++ b/net/spdy/array_output_buffer.cc
@@ -0,0 +1,23 @@
+// 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 "net/spdy/array_output_buffer.h"
+
+namespace net {
+
+void ArrayOutputBuffer::Next(char** data, int* size) {
+  *data = current_;
+  *size = capacity_ > 0 ? capacity_ : 0;
+}
+
+void ArrayOutputBuffer::AdvanceWritePtr(int64_t count) {
+  current_ += count;
+  capacity_ -= count;
+}
+
+uint64_t ArrayOutputBuffer::BytesFree() const {
+  return capacity_;
+}
+
+}  // namespace net
diff --git a/net/spdy/array_output_buffer.h b/net/spdy/array_output_buffer.h
new file mode 100644
index 0000000..a363e56d
--- /dev/null
+++ b/net/spdy/array_output_buffer.h
@@ -0,0 +1,40 @@
+// 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 NET_SPDY_ARRAY_OUTPUT_BUFFER_H_
+#define NET_SPDY_ARRAY_OUTPUT_BUFFER_H_
+
+#include <string.h>
+#include "net/spdy/zero_copy_output_buffer.h"
+
+namespace net {
+
+class ArrayOutputBuffer : public ZeroCopyOutputBuffer {
+ public:
+  // |buffer| is pointed to the output to write to, and |size| is the capacity
+  // of the output.
+  ArrayOutputBuffer(char* buffer, int64_t size)
+      : current_(buffer), begin_(buffer), capacity_(size) {}
+  ~ArrayOutputBuffer() override{};
+
+  void Next(char** data, int* size) override;
+  void AdvanceWritePtr(int64_t count) override;
+  uint64_t BytesFree() const override;
+
+  size_t Size() const { return current_ - begin_; }
+  char* Begin() const { return begin_; }
+  void Reset() { begin_ = current_; }
+
+  ArrayOutputBuffer(const ArrayOutputBuffer&) = delete;
+  ArrayOutputBuffer& operator=(const ArrayOutputBuffer&) = delete;
+
+ private:
+  char* current_ = nullptr;
+  char* begin_ = nullptr;
+  int64_t capacity_ = 0;
+};
+
+}  // namespace net
+
+#endif  // NET_SPDY_ARRAY_OUTPUT_BUFFER_H_
diff --git a/net/spdy/spdy_frame_builder.cc b/net/spdy/spdy_frame_builder.cc
index a92aaecb..cb31ee2 100644
--- a/net/spdy/spdy_frame_builder.cc
+++ b/net/spdy/spdy_frame_builder.cc
@@ -4,34 +4,61 @@
 
 #include "net/spdy/spdy_frame_builder.h"
 
+#include <algorithm>
+#include <cstdint>
 #include <limits>
 
 #include "base/logging.h"
 #include "net/spdy/spdy_bug_tracker.h"
 #include "net/spdy/spdy_framer.h"
 #include "net/spdy/spdy_protocol.h"
+#include "net/spdy/zero_copy_output_buffer.h"
 
 namespace net {
 
 SpdyFrameBuilder::SpdyFrameBuilder(size_t size)
     : buffer_(new char[size]), capacity_(size), length_(0), offset_(0) {}
 
+SpdyFrameBuilder::SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output)
+    : buffer_(output == nullptr ? new char[size] : nullptr),
+      output_(output),
+      capacity_(size),
+      length_(0),
+      offset_(0) {}
+
 SpdyFrameBuilder::~SpdyFrameBuilder() {
 }
 
 char* SpdyFrameBuilder::GetWritableBuffer(size_t length) {
   if (!CanWrite(length)) {
-    return NULL;
+    return nullptr;
   }
   return buffer_.get() + offset_ + length_;
 }
 
+char* SpdyFrameBuilder::GetWritableOutput(size_t length,
+                                          size_t* actual_length) {
+  char* dest = nullptr;
+  int size = 0;
+
+  if (!CanWrite(length)) {
+    return nullptr;
+  }
+  output_->Next(&dest, &size);
+  *actual_length = std::min(length, (size_t)size);
+  return dest;
+}
+
 bool SpdyFrameBuilder::Seek(size_t length) {
   if (!CanWrite(length)) {
     return false;
   }
-
-  length_ += length;
+  if (output_ == nullptr) {
+    length_ += length;
+  } else {
+    output_->AdvanceWritePtr(length);
+    length_ += length;
+  }
   return true;
 }
 
@@ -114,9 +141,29 @@
     return false;
   }
 
-  char* dest = GetWritableBuffer(data_len);
-  memcpy(dest, data, data_len);
-  Seek(data_len);
+  if (output_ == nullptr) {
+    char* dest = GetWritableBuffer(data_len);
+    memcpy(dest, data, data_len);
+    Seek(data_len);
+  } else {
+    char* dest = nullptr;
+    size_t size = 0;
+    size_t total_written = 0;
+    const char* data_ptr = reinterpret_cast<const char*>(data);
+    while (data_len > 0) {
+      dest = GetWritableOutput(data_len, &size);
+      if (dest == nullptr || size == 0) {
+        // Unable to make progress.
+        return false;
+      }
+      uint32_t to_copy = std::min((size_t)data_len, size);
+      const char* src = data_ptr + total_written;
+      memcpy(dest, src, to_copy);
+      Seek(to_copy);
+      data_len -= to_copy;
+      total_written += to_copy;
+    }
+  }
   return true;
 }
 
@@ -139,9 +186,16 @@
     return false;
   }
 
-  if (offset_ + length_ + length > capacity_) {
-    DCHECK(false);
-    return false;
+  if (output_ == nullptr) {
+    if (offset_ + length_ + length > capacity_) {
+      DLOG(FATAL) << "Requested: " << length << " capacity: " << capacity_
+                  << " used: " << offset_ + length_;
+      return false;
+    }
+  } else {
+    if (length > output_->BytesFree()) {
+      return false;
+    }
   }
 
   return true;
diff --git a/net/spdy/spdy_frame_builder.h b/net/spdy/spdy_frame_builder.h
index 2432c19d..c5973ca 100644
--- a/net/spdy/spdy_frame_builder.h
+++ b/net/spdy/spdy_frame_builder.h
@@ -17,6 +17,7 @@
 #include "net/base/net_export.h"
 #include "net/spdy/spdy_bug_tracker.h"
 #include "net/spdy/spdy_protocol.h"
+#include "net/spdy/zero_copy_output_buffer.h"
 
 namespace net {
 
@@ -33,6 +34,8 @@
  public:
   // Initializes a SpdyFrameBuilder with a buffer of given size
   explicit SpdyFrameBuilder(size_t size);
+  // Doesn't take ownership of output.
+  SpdyFrameBuilder(size_t size, ZeroCopyOutputBuffer* output);
 
   ~SpdyFrameBuilder();
 
@@ -61,6 +64,8 @@
 
   // Takes the buffer from the SpdyFrameBuilder.
   SpdySerializedFrame take() {
+    SPDY_BUG_IF(output_ != nullptr) << "ZeroCopyOutputBuffer is used to build "
+                                    << "frames. take() shouldn't be called";
     SPDY_BUG_IF(kMaxFrameSizeLimit < length_)
         << "Frame length " << length_
         << " is longer than the maximum possible allowed length.";
@@ -107,6 +112,8 @@
 
  private:
   FRIEND_TEST_ALL_PREFIXES(SpdyFrameBuilderTest, GetWritableBuffer);
+  FRIEND_TEST_ALL_PREFIXES(SpdyFrameBuilderTest, GetWritableOutput);
+  FRIEND_TEST_ALL_PREFIXES(SpdyFrameBuilderTest, GetWritableOutputNegative);
 
   // Returns a writeable buffer of given size in bytes, to be appended to the
   // currently written frame. Does bounds checking on length but does not
@@ -115,12 +122,19 @@
   // In general, consumers should use Write*() calls instead of this.
   // Returns NULL on failure.
   char* GetWritableBuffer(size_t length);
+  char* GetWritableOutput(size_t desired_length, size_t* actual_length);
 
   // Checks to make sure that there is an appropriate amount of space for a
   // write of given size, in bytes.
   bool CanWrite(size_t length) const;
 
+  // A buffer to be created whenever a new frame needs to be written. Used only
+  // if |output_| is nullptr.
   std::unique_ptr<char[]> buffer_;
+  // A pre-allocated buffer. If not-null, serialized frame data is written to
+  // this buffer.
+  ZeroCopyOutputBuffer* output_ = nullptr;  // Does not own.
+
   size_t capacity_;  // Allocation size of payload, set by constructor.
   size_t length_;    // Length of the latest frame in the buffer.
   size_t offset_;    // Position at which the latest frame begins.
diff --git a/net/spdy/spdy_frame_builder_test.cc b/net/spdy/spdy_frame_builder_test.cc
index 34fcfd5..56016bc0 100644
--- a/net/spdy/spdy_frame_builder_test.cc
+++ b/net/spdy/spdy_frame_builder_test.cc
@@ -4,12 +4,22 @@
 
 #include "net/spdy/spdy_frame_builder.h"
 
+#include "net/spdy/array_output_buffer.h"
 #include "net/spdy/spdy_framer.h"
 #include "net/spdy/spdy_protocol.h"
 #include "testing/platform_test.h"
 
 namespace net {
 
+namespace {
+
+const int64_t kSize = 64 * 1024;
+char output_buffer[kSize] = "";
+
+}  // namespace
+
+// Verifies that SpdyFrameBuilder::GetWritableBuffer() can be used to build a
+// SpdySerializedFrame.
 TEST(SpdyFrameBuilderTest, GetWritableBuffer) {
   const size_t kBuilderSize = 10;
   SpdyFrameBuilder builder(kBuilderSize);
@@ -23,4 +33,34 @@
             base::StringPiece(frame.data(), kBuilderSize));
 }
 
+// Verifies that SpdyFrameBuilder::GetWritableBuffer() can be used to build a
+// SpdySerializedFrame to the output buffer.
+TEST(SpdyFrameBuilderTest, GetWritableOutput) {
+  ArrayOutputBuffer output(output_buffer, kSize);
+  const size_t kBuilderSize = 10;
+  SpdyFrameBuilder builder(kBuilderSize, &output);
+  size_t actual_size = 0;
+  char* writable_buffer = builder.GetWritableOutput(kBuilderSize, &actual_size);
+  memset(writable_buffer, ~1, kBuilderSize);
+  EXPECT_TRUE(builder.Seek(kBuilderSize));
+  SpdySerializedFrame frame(output.Begin(), kBuilderSize, false);
+  char expected[kBuilderSize];
+  memset(expected, ~1, kBuilderSize);
+  EXPECT_EQ(base::StringPiece(expected, kBuilderSize),
+            base::StringPiece(frame.data(), kBuilderSize));
+}
+
+// Verifies the case that the buffer's capacity is too small.
+TEST(SpdyFrameBuilderTest, GetWritableOutputNegative) {
+  size_t small_cap = 1;
+  ArrayOutputBuffer output(output_buffer, small_cap);
+  const size_t kBuilderSize = 10;
+  SpdyFrameBuilder builder(kBuilderSize, &output);
+  size_t actual_size = 0;
+  char* writable_buffer = builder.GetWritableOutput(kBuilderSize, &actual_size);
+  builder.GetWritableOutput(kBuilderSize, &actual_size);
+  EXPECT_EQ((uint64_t)0, actual_size);
+  EXPECT_EQ(nullptr, writable_buffer);
+}
+
 }  // namespace net
diff --git a/net/spdy/zero_copy_output_buffer.h b/net/spdy/zero_copy_output_buffer.h
new file mode 100644
index 0000000..2051962
--- /dev/null
+++ b/net/spdy/zero_copy_output_buffer.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_SPDY_ZERO_COPY_OUTPUT_BUFFER_H_
+#define NET_SPDY_ZERO_COPY_OUTPUT_BUFFER_H_
+
+#include <cstdint>
+
+namespace net {
+
+class ZeroCopyOutputBuffer {
+ public:
+  virtual ~ZeroCopyOutputBuffer() {}
+
+  // Returns the next available segment of memory to write. Will always return
+  // the same segment until AdvanceWritePtr is called.
+  virtual void Next(char** data, int* size) = 0;
+
+  // After writing to a buffer returned from Next(), the caller should call
+  // this method to indicate how many bytes were written.
+  virtual void AdvanceWritePtr(int64_t count) = 0;
+
+  // Returns the available capacity of the buffer.
+  virtual uint64_t BytesFree() const = 0;
+};
+
+}  // namespace net
+
+#endif  // NET_SPDY_ZERO_COPY_OUTPUT_BUFFER_H_
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 31cf5f0..4995021c 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -2638,7 +2638,7 @@
     std::list<QuicHttpResponseCache::ServerPushInfo> push_resources;
     for (size_t i = 0; i < num_resources; ++i) {
       string url = push_urls[i];
-      GURL resource_url(url);
+      QuicUrl resource_url(url);
       string body =
           use_large_response
               ? large_resource
diff --git a/net/tools/quic/quic_client_bin.cc b/net/tools/quic/quic_client_bin.cc
index 45ed463d..7b899af 100644
--- a/net/tools/quic/quic_client_bin.cc
+++ b/net/tools/quic/quic_client_bin.cc
@@ -57,11 +57,11 @@
 #include "net/quic/platform/api/quic_socket_address.h"
 #include "net/quic/platform/api/quic_str_cat.h"
 #include "net/quic/platform/api/quic_text_utils.h"
+#include "net/quic/platform/api/quic_url.h"
 #include "net/spdy/spdy_header_block.h"
 #include "net/tools/epoll_server/epoll_server.h"
 #include "net/tools/quic/quic_client.h"
 #include "net/tools/quic/synchronous_host_resolver.h"
-#include "url/gurl.h"
 
 using base::StringPiece;
 using net::CertVerifier;
@@ -71,6 +71,7 @@
 using net::ProofVerifier;
 using net::ProofVerifierChromium;
 using net::QuicTextUtils;
+using net::QuicUrl;
 using net::SpdyHeaderBlock;
 using net::TransportSecurityState;
 using std::cout;
@@ -223,14 +224,14 @@
   // Determine IP address to connect to from supplied hostname.
   net::QuicIpAddress ip_addr;
 
-  GURL url(urls[0]);
+  QuicUrl url(urls[0], "https");
   string host = FLAGS_host;
   if (host.empty()) {
     host = url.host();
   }
   int port = FLAGS_port;
   if (port == 0) {
-    port = url.EffectiveIntPort();
+    port = url.port();
   }
   if (!ip_addr.FromString(host)) {
     net::AddressList addresses;
@@ -249,7 +250,7 @@
 
   // Build the client, and try to connect.
   net::EpollServer epoll_server;
-  net::QuicServerId server_id(url.host(), url.EffectiveIntPort(),
+  net::QuicServerId server_id(url.host(), url.port(),
                               net::PRIVACY_MODE_DISABLED);
   net::QuicVersionVector versions = net::AllSupportedVersions();
   if (FLAGS_quic_version != -1) {
@@ -304,8 +305,8 @@
   SpdyHeaderBlock header_block;
   header_block[":method"] = body.empty() ? "GET" : "POST";
   header_block[":scheme"] = url.scheme();
-  header_block[":authority"] = url.host();
-  header_block[":path"] = url.path();
+  header_block[":authority"] = url.HostPort();
+  header_block[":path"] = url.PathParamsQuery();
 
   // Append any additional headers supplied on the command line.
   for (StringPiece sp : QuicTextUtils::Split(FLAGS_headers, ';')) {
diff --git a/net/tools/quic/quic_http_response_cache.cc b/net/tools/quic/quic_http_response_cache.cc
index c079081d..b65c8e5 100644
--- a/net/tools/quic/quic_http_response_cache.cc
+++ b/net/tools/quic/quic_http_response_cache.cc
@@ -24,7 +24,7 @@
 namespace net {
 
 QuicHttpResponseCache::ServerPushInfo::ServerPushInfo(
-    GURL request_url,
+    QuicUrl request_url,
     SpdyHeaderBlock headers,
     net::SpdyPriority priority,
     string body)
@@ -270,7 +270,7 @@
   for (const auto& resource_file : resource_files) {
     std::list<ServerPushInfo> push_resources;
     for (const auto& push_url : resource_file->push_urls()) {
-      GURL url(push_url);
+      QuicUrl url(push_url);
       const Response* response = GetResponse(url.host(), url.path());
       if (!response) {
         QUIC_BUG << "Push URL '" << push_url << "' not found.";
@@ -345,7 +345,8 @@
     }
 
     QUIC_DVLOG(1) << "Add request-resource association: request url "
-                  << request_url << " push url " << push_resource.request_url
+                  << request_url << " push url "
+                  << push_resource.request_url.ToString()
                   << " response headers "
                   << push_resource.headers.DebugString();
     {
@@ -380,7 +381,8 @@
       server_push_resources_.equal_range(original_request_url);
   for (auto it = resource_range.first; it != resource_range.second; ++it) {
     ServerPushInfo push_resource = it->second;
-    if (push_resource.request_url.spec() == resource.request_url.spec()) {
+    if (push_resource.request_url.ToString() ==
+        resource.request_url.ToString()) {
       return true;
     }
   }
diff --git a/net/tools/quic/quic_http_response_cache.h b/net/tools/quic/quic_http_response_cache.h
index ad274bf..13efd31d 100644
--- a/net/tools/quic/quic_http_response_cache.h
+++ b/net/tools/quic/quic_http_response_cache.h
@@ -18,8 +18,8 @@
 #include "net/http/http_response_headers.h"
 #include "net/quic/core/spdy_utils.h"
 #include "net/quic/platform/api/quic_mutex.h"
+#include "net/quic/platform/api/quic_url.h"
 #include "net/spdy/spdy_framer.h"
-#include "url/gurl.h"
 
 namespace net {
 
@@ -31,12 +31,12 @@
   // A ServerPushInfo contains path of the push request and everything needed in
   // comprising a response for the push request.
   struct ServerPushInfo {
-    ServerPushInfo(GURL request_url,
+    ServerPushInfo(QuicUrl request_url,
                    SpdyHeaderBlock headers,
                    SpdyPriority priority,
                    std::string body);
     ServerPushInfo(const ServerPushInfo& other);
-    GURL request_url;
+    QuicUrl request_url;
     SpdyHeaderBlock headers;
     SpdyPriority priority;
     std::string body;
diff --git a/net/tools/quic/quic_http_response_cache_test.cc b/net/tools/quic/quic_http_response_cache_test.cc
index c0f5347..037c384 100644
--- a/net/tools/quic/quic_http_response_cache_test.cc
+++ b/net/tools/quic/quic_http_response_cache_test.cc
@@ -96,7 +96,7 @@
 TEST_F(QuicHttpResponseCacheTest, ReadsCacheDir) {
   cache_.InitializeFromDirectory(CacheDirectory());
   const QuicHttpResponseCache::Response* response =
-      cache_.GetResponse("www.example.com", "/index.html");
+      cache_.GetResponse("test.example.com", "/index.html");
   ASSERT_TRUE(response);
   ASSERT_TRUE(QuicContainsKey(response->headers(), ":status"));
   EXPECT_EQ("200", response->headers().find(":status")->second);
@@ -108,21 +108,21 @@
 TEST_F(QuicHttpResponseCacheTest, ReadsCacheDirWithServerPushResource) {
   cache_.InitializeFromDirectory(CacheDirectory() + "_with_push");
   std::list<ServerPushInfo> resources =
-      cache_.GetServerPushResources("www.example.com/");
+      cache_.GetServerPushResources("test.example.com/");
   ASSERT_EQ(1UL, resources.size());
 }
 
 TEST_F(QuicHttpResponseCacheTest, ReadsCacheDirWithServerPushResources) {
   cache_.InitializeFromDirectory(CacheDirectory() + "_with_push");
   std::list<ServerPushInfo> resources =
-      cache_.GetServerPushResources("www.example.com/index2.html");
+      cache_.GetServerPushResources("test.example.com/index2.html");
   ASSERT_EQ(2UL, resources.size());
 }
 
 TEST_F(QuicHttpResponseCacheTest, UsesOriginalUrl) {
   cache_.InitializeFromDirectory(CacheDirectory());
   const QuicHttpResponseCache::Response* response =
-      cache_.GetResponse("www.example.com", "/site_map.html");
+      cache_.GetResponse("test.example.com", "/site_map.html");
   ASSERT_TRUE(response);
   ASSERT_TRUE(QuicContainsKey(response->headers(), ":status"));
   EXPECT_EQ("200", response->headers().find(":status")->second);
@@ -177,7 +177,7 @@
   for (int i = 0; i < NumResources; ++i) {
     string path = "/server_push_src" + QuicTextUtils::Uint64ToString(i);
     string url = scheme + "://" + request_host + path;
-    GURL resource_url(url);
+    QuicUrl resource_url(url);
     string body = QuicStrCat("This is server push response body for ", path);
     SpdyHeaderBlock response_headers;
     response_headers[":version"] = "HTTP/1.1";
@@ -196,7 +196,8 @@
   ASSERT_EQ(kNumResources, resources.size());
   for (const auto& push_resource : push_resources) {
     ServerPushInfo resource = resources.front();
-    EXPECT_EQ(resource.request_url.spec(), push_resource.request_url.spec());
+    EXPECT_EQ(resource.request_url.ToString(),
+              push_resource.request_url.ToString());
     EXPECT_EQ(resource.priority, push_resource.priority);
     resources.pop_front();
   }
@@ -213,7 +214,7 @@
   for (int i = 0; i < NumResources; ++i) {
     string path = "/server_push_src" + QuicTextUtils::Uint64ToString(i);
     string url = scheme + "://" + request_host + path;
-    GURL resource_url(url);
+    QuicUrl resource_url(url);
     string body = "This is server push response body for " + path;
     SpdyHeaderBlock response_headers;
     response_headers[":version"] = "HTTP/1.1";
@@ -231,7 +232,7 @@
   ASSERT_EQ(kNumResources, resources.size());
   int i = 0;
   for (const auto& push_resource : push_resources) {
-    GURL url = resources.front().request_url;
+    QuicUrl url = resources.front().request_url;
     string host = url.host();
     string path = url.path();
     const QuicHttpResponseCache::Response* response =
diff --git a/net/tools/quic/quic_simple_server_session.cc b/net/tools/quic/quic_simple_server_session.cc
index 3e60f3a2..f138d93e 100644
--- a/net/tools/quic/quic_simple_server_session.cc
+++ b/net/tools/quic/quic_simple_server_session.cc
@@ -13,7 +13,6 @@
 #include "net/quic/platform/api/quic_logging.h"
 #include "net/quic/platform/api/quic_ptr_util.h"
 #include "net/tools/quic/quic_simple_server_stream.h"
-#include "url/gurl.h"
 
 using std::string;
 
@@ -154,7 +153,7 @@
     string request_url,
     QuicHttpResponseCache::ServerPushInfo resource,
     const SpdyHeaderBlock& original_request_headers) {
-  GURL push_request_url = resource.request_url;
+  QuicUrl push_request_url = resource.request_url;
   string path = push_request_url.path();
 
   SpdyHeaderBlock spdy_headers = original_request_headers.Clone();
diff --git a/net/tools/quic/quic_simple_server_session_test.cc b/net/tools/quic/quic_simple_server_session_test.cc
index 37317065..1af7ffe0 100644
--- a/net/tools/quic/quic_simple_server_session_test.cc
+++ b/net/tools/quic/quic_simple_server_session_test.cc
@@ -473,7 +473,7 @@
       string path =
           partial_push_resource_path + QuicTextUtils::Uint64ToString(i);
       string url = scheme + "://" + resource_host + path;
-      GURL resource_url = GURL(url);
+      QuicUrl resource_url = QuicUrl(url);
       string body(body_size, 'a');
       response_cache_.AddSimpleResponse(resource_host, path, 200, body);
       push_resources.push_back(QuicHttpResponseCache::ServerPushInfo(
diff --git a/net/tools/quic/quic_simple_server_stream_test.cc b/net/tools/quic/quic_simple_server_stream_test.cc
index 81ced2e..67a01790 100644
--- a/net/tools/quic/quic_simple_server_stream_test.cc
+++ b/net/tools/quic/quic_simple_server_stream_test.cc
@@ -26,7 +26,6 @@
 #include "net/tools/quic/quic_simple_server_session.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
 
 using base::StringPiece;
 using std::string;
@@ -433,9 +432,8 @@
   string host = "www.google.com";
   string request_path = "/foo";
   string body = "Yummm";
-  string url = host + "/bar";
   QuicHttpResponseCache::ServerPushInfo push_info(
-      GURL(url), SpdyHeaderBlock(), kDefaultPriority, "Push body");
+      QuicUrl(host, "/bar"), SpdyHeaderBlock(), kDefaultPriority, "Push body");
   std::list<QuicHttpResponseCache::ServerPushInfo> push_resources;
   push_resources.push_back(push_info);
   response_cache_.AddSimpleResponseWithServerPushResources(
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc
index 28fd7f9..56fe712 100644
--- a/net/tools/quic/test_tools/quic_test_client.cc
+++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -17,6 +17,7 @@
 #include "net/quic/platform/api/quic_ptr_util.h"
 #include "net/quic/platform/api/quic_stack_trace.h"
 #include "net/quic/platform/api/quic_text_utils.h"
+#include "net/quic/platform/api/quic_url.h"
 #include "net/quic/test_tools/crypto_test_utils.h"
 #include "net/quic/test_tools/quic_connection_peer.h"
 #include "net/quic/test_tools/quic_spdy_session_peer.h"
@@ -27,7 +28,6 @@
 #include "net/tools/quic/quic_spdy_client_stream.h"
 #include "net/tools/quic/test_tools/quic_client_peer.h"
 #include "third_party/boringssl/src/include/openssl/x509.h"
-#include "url/gurl.h"
 
 using base::StringPiece;
 using std::string;
@@ -353,10 +353,10 @@
 
   // If we're not connected, try to find an sni hostname.
   if (!connected()) {
-    GURL url(SpdyUtils::GetUrlFromHeaderBlock(headers));
+    QuicUrl url(SpdyUtils::GetUrlFromHeaderBlock(headers));
     if (override_sni_set_) {
-      client_->set_server_id(QuicServerId(override_sni_, url.EffectiveIntPort(),
-                                          PRIVACY_MODE_DISABLED));
+      client_->set_server_id(
+          QuicServerId(override_sni_, url.port(), PRIVACY_MODE_DISABLED));
     }
   }
 
diff --git a/ppapi/generators/OWNERS b/ppapi/generators/OWNERS
index b800ab2e..18a9061 100644
--- a/ppapi/generators/OWNERS
+++ b/ppapi/generators/OWNERS
@@ -4,3 +4,5 @@
 sehr@chromium.org
 sehr@google.com
 yzshen@chromium.org
+
+# COMPONENT: Internals>Plugins>Pepper
diff --git a/remoting/client/plugin/pepper_video_renderer_3d.cc b/remoting/client/plugin/pepper_video_renderer_3d.cc
index aff694a2..4cd976d 100644
--- a/remoting/client/plugin/pepper_video_renderer_3d.cc
+++ b/remoting/client/plugin/pepper_video_renderer_3d.cc
@@ -333,8 +333,14 @@
 }
 
 void PepperVideoRenderer3D::GetNextPicture() {
-  if (get_picture_pending_)
+  // Return early if |decoded_frames_| is empty or the decoder is already
+  // preparing a picture.  If we call GetPicture() before a new frame has been
+  // prepared (i.e. |decoded_frames_| is populated), the OnPictureReady callback
+  // could be called before OnDecodeDone() is called which will cause a crash.
+  // See crbug.com/689229 for more details.
+  if (get_picture_pending_ || decoded_frames_.empty()) {
     return;
+  }
 
   int32_t result =
       video_decoder_.GetPicture(callback_factory_.NewCallbackWithOutput(
diff --git a/remoting/webapp/crd/js/options_export.js b/remoting/webapp/crd/js/options_export.js
index dbd3a25..392b043e 100644
--- a/remoting/webapp/crd/js/options_export.js
+++ b/remoting/webapp/crd/js/options_export.js
@@ -20,11 +20,17 @@
 
 remoting.OptionsExporter.migrateSettings_ = function() {
   var result = new base.Deferred();
-  chrome.storage.local.get('remoting-host-options', function(options) {
+  chrome.storage.local.get(KEY_NAME, function(options) {
+    // If there are no host options stored, reformat the message response so
+    // that the sender doesn't interpret it as an error.
+    if (Object.keys(options).length == 0) {
+      options[KEY_NAME] = '{}';
+    }
     result.resolve(options);
   })
   return result.promise();
 };
 
+var KEY_NAME = 'remoting-host-options';
 
 }());
diff --git a/rlz/test/rlz_test_helpers.cc b/rlz/test/rlz_test_helpers.cc
index 4e870fd..2d4b6dd 100644
--- a/rlz/test/rlz_test_helpers.cc
+++ b/rlz/test/rlz_test_helpers.cc
@@ -115,8 +115,10 @@
                                        KEY_READ), &data);
   }
 
-  override_manager->OverrideRegistry(HKEY_LOCAL_MACHINE);
-  override_manager->OverrideRegistry(HKEY_CURRENT_USER);
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager->OverrideRegistry(HKEY_LOCAL_MACHINE));
+  ASSERT_NO_FATAL_FAILURE(
+      override_manager->OverrideRegistry(HKEY_CURRENT_USER));
 
   if (do_copy) {
     base::win::RegKey key(
@@ -131,7 +133,8 @@
 
 void RlzLibTestNoMachineStateHelper::SetUp() {
 #if defined(OS_WIN)
-  InitializeRegistryOverridesForTesting(&override_manager_);
+  ASSERT_NO_FATAL_FAILURE(
+      InitializeRegistryOverridesForTesting(&override_manager_));
 #elif defined(OS_MACOSX)
   base::mac::ScopedNSAutoreleasePool pool;
 #endif  // defined(OS_WIN)
diff --git a/services/BUILD.gn b/services/BUILD.gn
index 38f150c..e2d5332 100644
--- a/services/BUILD.gn
+++ b/services/BUILD.gn
@@ -18,6 +18,7 @@
     "//services/device:tests",
     "//services/image_decoder:tests",
     "//services/memory_instrumentation:tests",
+    "//services/shape_detection:tests",
   ]
 
   if (is_android) {
diff --git a/services/shape_detection/BUILD.gn b/services/shape_detection/BUILD.gn
index 2546fb7f..e4d401d 100644
--- a/services/shape_detection/BUILD.gn
+++ b/services/shape_detection/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//services/service_manager/public/cpp/service.gni")
 import("//services/service_manager/public/service_manifest.gni")
+import("//testing/test.gni")
 
 source_set("lib") {
   sources = [
@@ -48,3 +49,30 @@
   name = "shape_detection"
   source = "manifest.json"
 }
+
+source_set("tests") {
+  testonly = true
+  sources = []
+  if (is_mac) {
+    sources += [
+      "barcode_detection_impl_mac_unittest.mm",
+      "face_detection_impl_mac_unittest.mm",
+    ]
+
+    libs = [
+      "CoreFoundation.framework",
+      "CoreGraphics.framework",
+      "QuartzCore.framework",
+    ]
+
+    deps = [
+      ":lib",
+      "//base",
+      "//skia",
+      "//testing/gmock",
+      "//testing/gtest",
+      "//ui/gfx",
+      "//ui/gl",
+    ]
+  }
+}
diff --git a/services/shape_detection/DEPS b/services/shape_detection/DEPS
index 7db8eb2..a2872a2 100644
--- a/services/shape_detection/DEPS
+++ b/services/shape_detection/DEPS
@@ -1,3 +1,6 @@
 include_rules = [
   "+media/capture/video/scoped_result_callback.h",
+  "+third_party/skia/include",
+  "+ui/gfx/codec",
+  "+ui/gl/gl_switches.h"
 ]
diff --git a/services/shape_detection/PRESUBMIT.py b/services/shape_detection/PRESUBMIT.py
new file mode 100644
index 0000000..ad094f7
--- /dev/null
+++ b/services/shape_detection/PRESUBMIT.py
@@ -0,0 +1,36 @@
+# 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.
+
+"""Top-level presubmit script for shape_detection.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+import re
+
+def PostUploadHook(cl, change, output_api):
+  """git cl upload will call this hook after the issue is created/modified.
+
+  This hook adds extra try bots list to the CL description in order to run
+  the Mac GPU bots in addition to the usual CQ try bots.
+  """
+  rietveld_obj = cl.RpcServer()
+  issue = cl.issue
+  description = rietveld_obj.get_description(issue)
+  if re.search(r'^CQ_INCLUDE_TRYBOTS=.*', description, re.M | re.I):
+    return []
+
+  bots = [ 'master.tryserver.chromium.mac:mac_optional_gpu_tests_rel' ]
+
+  results = []
+  new_description = description
+  new_description += '\nCQ_INCLUDE_TRYBOTS=%s' % ';'.join(bots)
+  results.append(output_api.PresubmitNotifyResult(
+      'Automatically added optional Mac GPU tests to run on CQ.'))
+
+  if new_description != description:
+    rietveld_obj.update_description(issue, new_description)
+
+  return results
diff --git a/services/shape_detection/barcode_detection_impl_mac.mm b/services/shape_detection/barcode_detection_impl_mac.mm
index 0e873d7..ec0ac0b 100644
--- a/services/shape_detection/barcode_detection_impl_mac.mm
+++ b/services/shape_detection/barcode_detection_impl_mac.mm
@@ -42,10 +42,10 @@
 }
 
 BarcodeDetectionImplMac::BarcodeDetectionImplMac() {
-  NSDictionary* const opts = @{CIDetectorAccuracy : CIDetectorAccuracyHigh};
+  NSDictionary* const options = @{CIDetectorAccuracy : CIDetectorAccuracyHigh};
   detector_.reset([[CIDetector detectorOfType:CIDetectorTypeQRCode
                                       context:nil
-                                      options:opts] retain]);
+                                      options:options] retain]);
 }
 
 BarcodeDetectionImplMac::~BarcodeDetectionImplMac() {}
diff --git a/services/shape_detection/barcode_detection_impl_mac_unittest.mm b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
new file mode 100644
index 0000000..55c2cd27
--- /dev/null
+++ b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
@@ -0,0 +1,104 @@
+// 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 "services/shape_detection/barcode_detection_impl_mac.h"
+
+#include "base/command_line.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "base/run_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_switches.h"
+
+namespace shape_detection {
+
+ACTION_P(RunClosure, closure) {
+  closure.Run();
+}
+
+class BarcodeDetectionImplMacTest : public ::testing::Test {
+ public:
+  ~BarcodeDetectionImplMacTest() override = default;
+
+  void DetectCallback(std::vector<mojom::BarcodeDetectionResultPtr> results) {
+    Detection(results.size(), results.empty() ? "" : results[0]->raw_value);
+  }
+  MOCK_METHOD2(Detection, void(size_t, const std::string&));
+
+  BarcodeDetectionImplMac impl_;
+  const base::MessageLoop message_loop_;
+};
+
+TEST_F(BarcodeDetectionImplMacTest, CreateAndDestroy) {}
+
+// This test generates a single QR code and scans it back.
+TEST_F(BarcodeDetectionImplMacTest, ScanOneBarcode) {
+  // Barcode detection needs at least MAC OS X 10.10, and GPU infrastructure.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kUseGpuInTests) ||
+      !base::mac::IsAtLeastOS10_10()) {
+    return;
+  }
+
+  const std::string kInfoString = "https://www.chromium.org";
+  // Generate a QR code image as a CIImage by using |qr_code_generator|.
+  NSData* const qr_code_data =
+      [[NSString stringWithUTF8String:kInfoString.c_str()]
+          dataUsingEncoding:NSISOLatin1StringEncoding];
+  // TODO(mcasas): Consider using other generator types (e.g.
+  // CI{AztecCode,Code128Barcode,PDF417Barcode}Generator) when the minimal OS X
+  // is upgraded to 10.10+ (https://crbug.com/624049).
+  CIFilter* qr_code_generator =
+      [CIFilter filterWithName:@"CIQRCodeGenerator"];
+  [qr_code_generator setValue:qr_code_data forKey:@"inputMessage"];
+
+  // [CIImage outputImage] is available in macOS 10.10+.  Could be added to
+  // sdk_forward_declarations.h but seems hardly worth it.
+  EXPECT_TRUE([qr_code_generator respondsToSelector:@selector(outputImage)]);
+  CIImage* qr_code_image =
+      [qr_code_generator performSelector:@selector(outputImage)];
+
+  const gfx::Size size([qr_code_image extent].size.width,
+                       [qr_code_image extent].size.height);
+  const int num_bytes = size.GetArea() * 4 /* bytes per pixel */;
+
+  base::scoped_nsobject<CIContext> context([[CIContext alloc] init]);
+
+  base::ScopedCFTypeRef<CGImageRef> cg_image(
+      [context createCGImage:qr_code_image fromRect:[qr_code_image extent]]);
+  EXPECT_EQ(static_cast<size_t>(size.width()), CGImageGetWidth(cg_image));
+  EXPECT_EQ(static_cast<size_t>(size.height()), CGImageGetHeight(cg_image));
+
+  base::ScopedCFTypeRef<CFDataRef> raw_cg_image_data(
+      CGDataProviderCopyData(CGImageGetDataProvider(cg_image)));
+  EXPECT_TRUE(CFDataGetBytePtr(raw_cg_image_data));
+  EXPECT_EQ(num_bytes, CFDataGetLength(raw_cg_image_data));
+
+  // Generate a new ScopedSharedBufferHandle of the aproppriate size, map it and
+  // copy the generated qr code image pixels into it.
+  mojo::ScopedSharedBufferHandle handle =
+      mojo::SharedBufferHandle::Create(num_bytes);
+  ASSERT_TRUE(handle->is_valid());
+
+  mojo::ScopedSharedBufferMapping mapping = handle->Map(num_bytes);
+  ASSERT_TRUE(mapping);
+
+  memcpy(mapping.get(), CFDataGetBytePtr(raw_cg_image_data), num_bytes);
+
+  base::RunLoop run_loop;
+  base::Closure quit_closure = run_loop.QuitClosure();
+  // Send the image Detect() and expect the response in callback.
+  EXPECT_CALL(*this, Detection(1, kInfoString))
+      .WillOnce(RunClosure(quit_closure));
+  impl_.Detect(std::move(handle), size.width(), size.height(),
+               base::Bind(&BarcodeDetectionImplMacTest::DetectCallback,
+                          base::Unretained(this)));
+
+  run_loop.Run();
+}
+
+}  // shape_detection namespace
diff --git a/services/shape_detection/face_detection_impl_mac.mm b/services/shape_detection/face_detection_impl_mac.mm
index b8539f0..151e0a7c 100644
--- a/services/shape_detection/face_detection_impl_mac.mm
+++ b/services/shape_detection/face_detection_impl_mac.mm
@@ -4,8 +4,6 @@
 
 #include "services/shape_detection/face_detection_impl_mac.h"
 
-#import <QuartzCore/QuartzCore.h>
-
 #include "base/mac/scoped_cftyperef.h"
 #include "media/capture/video/scoped_result_callback.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -39,10 +37,12 @@
 
 FaceDetectionImplMac::FaceDetectionImplMac(
     shape_detection::mojom::FaceDetectorOptionsPtr options) {
-  NSDictionary* const opts = @{CIDetectorAccuracy : CIDetectorAccuracyHigh};
+  NSString* const accuracy =
+      options->fast_mode ? CIDetectorAccuracyHigh : CIDetectorAccuracyLow;
+  NSDictionary* const detector_options = @{CIDetectorAccuracy : accuracy};
   detector_.reset([[CIDetector detectorOfType:CIDetectorTypeFace
                                       context:nil
-                                      options:opts] retain]);
+                                      options:detector_options] retain]);
 }
 
 FaceDetectionImplMac::~FaceDetectionImplMac() {}
diff --git a/services/shape_detection/face_detection_impl_mac_unittest.mm b/services/shape_detection/face_detection_impl_mac_unittest.mm
new file mode 100644
index 0000000..e07f700f
--- /dev/null
+++ b/services/shape_detection/face_detection_impl_mac_unittest.mm
@@ -0,0 +1,103 @@
+// 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 "services/shape_detection/face_detection_impl_mac.h"
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/run_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/codec/jpeg_codec.h"
+#include "ui/gl/gl_switches.h"
+
+using ::testing::TestWithParam;
+using ::testing::ValuesIn;
+
+namespace shape_detection {
+
+namespace {
+
+ACTION_P(RunClosure, closure) {
+  closure.Run();
+}
+
+// Base64 encoding of the Mona Lisa Face thumbnail from:
+// https://commons.wikimedia.org/wiki/File:Mona_Lisa_face_800x800px.jpg
+const int kJpegImageWidth = 120;
+const int kJpegImageHeight = 120;
+const char kJpegImageInBase64[]="/9j/4AAQSkZJRgABAQEAZABkAAD//gBSRmlsZSBzb3VyY2U6IGh0dHA6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9GaWxlOk1vbmFfTGlzYV9mYWNlXzgwMHg4MDBweC5qcGf/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAB4AHgDAREAAhEBAxEB/8QAHAAAAgIDAQEAAAAAAAAAAAAABQYEBwEDCAIA/8QAOxAAAgECBQIEBAQFAwMFAAAAAQIDBBEABRIhMQZBEyJRYQcycYEUkaGxFUJiwfAjJOEWF9ElM1LC8f/EABoBAAIDAQEAAAAAAAAAAAAAAAIDAQQFAAb/xAAvEQACAgICAgAEBQQCAwAAAAAAAQIRAyESMQRBBRMiUTJhcaGxFCNSgZHwweHx/9oADAMBAAIRAxEAPwBqiIChT5t7gEYwX1ssJUbY0ErKBHpFu498Q3fRKTMmJVNm2POo9/tiG2kTFG+FfIAq9t2ta2BtvsKtkqKmDE2UgMDiUn2C3ugTnvVGRdPy6M2zKFJxv+HivLN6i6LuPvbDsalPaRPy29Cw/wAYOn1kPgUmYS3OxZUjJvwbFrgYfHx8hziqCVF8V+namVUnSvojzqlp9SkD3QkYGWKa62SsY5ZVmVDmlMKnLamCqgvu8bBgPYjkH64U3x/FpkcWF4yT8oG4337YBzdUgVHezEwN1N1BxzurslJGI1uSpJG3bvjlew2bYUN+fS+Cj12DJkqEWNgOeL4OM66AaNscXkb2vziVK47ZD0IkcG1r/X/PthVWFZLRNKqAAdiCT9cC19jk77MRpqILKNjfi/tbCpcug40SooAz6tNyfLsOPbBQhslsrH4n/ECXLa+Tp7IZvBrxaOprEXU0Fx8if1+/a/ri3i8e1zn1/P8A6Ba6oR8h6YqY8szKshpauaWdNCzBHkZifmYk778ffAZvIU5Qg3pMsQg4xbS2KmcZQKPUaqmqItVhqeEqL9rnGhjzc3SaZXyY63QGDvSuJaScofVfMp57YsOPLUkLUnHcQplXUFfQZrFV5bK2XZkll8SEWRx6MnBB9D+mEywppqW0N+by/U6Y+EvXdP1rlrJKkVNnVMAtVTLsrDgSJ30nj2O3pjLz4XhlXr0d+JWh6eJQCy2b6DEOKAT+55hQrYsNrW98TH2S2ToAATYG5GwI4wUqSYPZuSEBNXAIBO2E8eO0TZ8UZVtf5hvbE7RHYkQRG6kix7f2wuMnexjr0SvDZiqpf6dsH30D12bIKe77gna7W7bYHbbCtIFdf9R0/R3S9VmcrIJFHh06t/PKR5Rbk+v0GLMISk1CK2wE03begP8ACHommhy6LM8zjhqM0qf9eeoljEjhm3sL7D7b++KmXK8+Tin9K0l+hcUflwTrbLXFHCABftYdvtthbjRHNgjOsoiqKaaJ9TqykFWAKn88Vsip6HwlfZzV8R+kKeikeSjS128wCD+2NT4f57yfTP0I8jCltFWyJJEXul0vYkLce4JxtqSfRRoJ9K5/WdNdSUOb5a7iWmbUVPEkZI1o3qCt/wBMBmxLLjcP+P1IjOpWztvJa+lzTJ6PMqF9dJVxLLG47qwuPpbi2MqP0Opd9ByV9E2KNWF97AbNiWlu2crN8cIABIFxyL7YW2yTZGhlNr7eltscnZD0ZkpyI++1+cMcVVg3sUUWMxRtHpbVc3GKr4voYrM063k32YEi9t9zhiTXRDJVHAzSB3uoK2F/bEwm4u7OaT0UL8cs9TqHPsqyZEH+nWxaWvuus7KB6keYn6Dti5gySm5Zn0kyflrGlBdtl7dNWp6FFY2awU39RjFxx1aNHJ9g6pdWa5LX3J9MS27aE0uyHXiSRCFN9rG3OEThyGxaQi9UdOpXwyCW1muDb/PbC4J4ZckNdTVM5u63y5cpzeemilCQDzebuff9bY9R4eV5cak+zMzxUJUhVmbUNQt6W9bC++LpWaSOjvgT1JK/w+ho5mtHl9Y1OD6o1pB9hrP5Yy/Mhxm697Gp3Wy0aXNhNMsIYi29u1j2v37Yq7fZLetB01arE5DKVQaRY8m+/wDbHUxTnvQRplvbcaTuL+/GIXdMY2bwbxFd2wXNtUD07KMyvqid3WGnLvqszF0PIB8o/LfEairZNT9D109mYzSmMiRaJUkMbjmxIDCx+hwacpNEKadk3Nq38HlE8oGpvw7sthvcKdsLlG6TCUt0jkbrCsaXramzCGSNr10MmkfNrUqtxfsQBtjS8eP9hwf2f7jJ25KS+6Lv/wC6VBDlQq0lSipEm/DhqpZSddr2IRG08H5iDtxjGXi5XJQjt1fa6L7yQrkx1n6p0dKSZwIwAE4vca+BY973B++KXJyfFd9B/LS2xLTq7NKbIWzvOfHpaeRxGFWkknILfKCFsBe3rg/lKWR48cr/ADbpHcmo3JAOLrjqHPcwio8uyeaohcj/AHUaSJGBv5jrUabW4P64tT8XHjjynk39tX+wr5km6jErP4oUM8Od+JUfM/zC99/rjT+GZYvHSRV8lNSViSmmF2XUrM1wQefe2NTsp7uix/hJWFKDNaUMViM0E5AYgsNJUi/2GKHmR/C/ZPWi5MkzgykxMYlABszCxuP32xVUFsGWR+w1Lm0cNJHGAJRIw3U302bfbne2IpdsSOXT9UKqEsHLJqBH0HbFKVqSTLqaadByJ/D1FgbW2vhuO07BbXRydQZocvqqclJCW31XA3IsSe1zfbFiWHndC1krQfyLrl6TI5KKFNFTGDaULfU1yGJ/NQCe2AyYJJ/T0Hjkktk2l6tmoTmVI0zSrBEqwySG5RmZthc8AXIxPy3KCZy1Oijxoi67yiKUf7eHNI1Z73DDxRck+v8A4xou/wCnlXbi/wCBqf1x17OwP4TBW05RJqiJTJ4jBQu7X3O4Nj7jHmFBTjyTNNzcHRo6ioUk6ckprBYGlBFxfYf/AIMdwaWiLTeyblGXRnLYYWqaiOwsdDDf87jELFyVSOlNx/Caa5abKKdjCZGL3LNI5YnC5pQdRQULkrZyz8YcwNZ1G3hFrIeB2/y2PRfCYccNv2Z/lu5UhEcuXErWYHdibbE/2xq1ZRHz4VpNP1BVU1I0i+PRlyq2a5V1P/2/XFPyopQTfoJLk9Fy5TRVkMjvLTVMpA3ZrHew/I/bvijyW9kSg0uiWIK2PSYaGpYA7CwvxyT3xzURLvsaukq2opJSKiCWJGJtZCdz9sJlFdpjMc2tMbJMxQqbyMCb8jAPI1sclZyPmMBZ2ZZWGkeJqLaix4A+mNODr0IaNbMYiDDJIAbgMBbUpAO4F9r3/K+J2yaT7AGeVdTYtHIG1Pu3qTcbn7n8sWMUVQSb5C3mFayrGYXa8bhyrdiDdbHvxh0YJ6GznpUdk9I9QJmuUUciOC00aEXO1iAf748jNPHcH6dGy6nUgN8QOuafpqloqGty+tkr5m3iiFw68albhhxxv64b4+CedaaSX3ETlHG7e7GLpPMzU9OUlZVRS0krhv8AQlPnUajpv72thTSg2rug/wASTFzrTNZTCywgkr9sLjHnJX6Dk6WjmLrCoaozeWR7sdR2btvwceq8VVjSRlZvxAaWcNEpK2f+axPGLCEMNdLVMkWYRmJn8UkqpHuLf87emByxuLvoh7LbynM8wphrSSrjB8xW1lJ2/wA7YoNKnQDeg7H1DXooAmrFckWUbn9rdsQ8a9CqDtB1XUJvUzh1202sDv625tgJwXVEptK7CY6jlqoisTygggGy7geuFcFdkcm/pbOdpa7xpQzCXzeQG2s27WONCMKHHppnlHhqg1KbhhtfjkG37euJBe2Q81y92y8vM6HUy2AI8p3P9t//ADgoZVy0iYJ3QqThI4NBVZJmc3bkqB6fXFlNt2Ntca9l5fA7qWlzTp6PJ6ipNPmVIDGrgjV4d/Kwvza9vtjznxXBKGR5K+mX8ml4mVTgoe0WR1OlR4UUZrcwqHUXSdcvjk29yLAfljN0pW/5LXoh5DA1NMZszrKyrn07LKiokYHoFHJuNyTiZSjJrVV+oKX52LvXGcwDxI42BYgjbfe22H+Pi5y2LyTpUc/Z9KZcwZ2Yl2a/t7DHqMKSjSMvK9gyVlvZCRtp+vqcNQtumFMhDfjIWifS9wb3taxwvJJKLOirLlpljjdYiulnF/KfNuNhx9+cZnPTdC3HVBCSjUxqZFOlPMCU77knb2xHNN7YFM30ckEQIAXTfY6fMLd8Tr2CyfJnsUKlIULNfsPl55PpxiJQV2FG0ikqKoLlRpRlbSCjC4O/Fr8k+98aEo/caHaWYyOVMOXBRIWCSHYj6ffCZxXabIoL5hl0/wD05WySJQNEkQmURhiWCkG1jyQL++EJrmtjIqip8x8JpnnkRXZyQNPC27n12tjSiq0TrtkGOtlocziqsullp54SGjkDWa+3+Wwc4KUeM9pkW4SuLOi+kfjrlz9PxwZ0r0+ZIgWTSl0f+ofX0x5/P8Kywf8Aa3H+DRx+VCf4tMEZ/wDEuOoB/A6UjI80kjC/5emBx/DZ95Dp511ErvMuojVvppr1EzXJfgL32vzjSx+Lw70V5ZL62LVXSy+O5ZjIxNy9tgMXLVUV3FoinQiG+7WNiB++D7AJuWzGJ1K3BUcn7EYiULVExdOy6qLNoTl1LIWEr2XSVIsGNr77d7jb9cZrwtXE7l7DdVXxVETeV4ybKoQ727m3bfCfkxUrBcrVUQBXwq7GJZmXRqKActf0+ww2Ka0C4Jn1TnETVI0sCC1iBGPU/p+3ptjpJvs5QS9i1Q0IVUctAlmuPCjB/ckg4a5xYwPUpiiZ1srPqHnbw9TahyABzta+Ikv8URFm+oqA0Eo8VDGV0MqkEDm4P14++EO09DE12UbnlGtPn1VTh2aNJLIVTc+VSARtv5gMa2KVwUgX2BZUu6nURcXJY73w7sGSoO9ARUcnWuUQ5giyUk1QIXRvl84Ki/3IxW8vl8mTi6dB4GlkXItXqb4WU8JY0EcSWO5AuAMZGH4nKL4z2Wsnjp7RAynonTIgnjUpcCygj8v3wefzk1pnQxv2TOrOlBT5S/gRqiqoJ2tbfck+mEeN5vLJ9TGSxaKlqKfwigdGUgHy25B4xvRmn0UZRNog8GjSWQeQFjbttYYlTTlR0o0rLL6OzCiqMshK1FPSLpWO7garj5u3YnnFDKppvt//AEFRTHVYacgQ0udQSMynWGS4tzzqxUtydyQTiq0YfpseHLWawaYC6u3kPoCvub4OOWvpbI4ezbTdJxC0r1XhIx1aW8oUn1v/AJvivPzI39DsdHx5PtUVPoneOVpayRKlKZfCaJiCdyTvck2F/uMaXKnpavYiiMnW1Y9OwqxTtO6C0ynQoIuo1AA78/8AGHy8aL6YN0eM16rr5qeHxggpp0CzaYwLMrndTyLGx9MQvHjvfR1+hPramevr6iaSZpJJZS2vgsext9hixGKjFJE22fZbltZmtctLQwy1FQ+yJGNRv+1vfHTyQhHnkdImMJSfFLZevw3+EUcEyV2czh6lfkVR5EbtYnk+/tjB8n4m8v0YVS/cu4vGUPql2XFJl5MAWYaibD5f8tjIk0XEjNNkSIxa2jfa/wCWBa+xNkHPMnSajdbgEIwIbv6XHpgVqXJBJXo5zqsnEWdGjIWS8oVSG+XU9h9bb3HbHpoZ+WHn+RQljqVEHqOkENFDSqiMq1UxW3JF7H7XXj64d487lyv0hWRar8wJk0arVCJ2RUJJ1MdlbixPobYt5HcW0V0iysiyTMa6ro2pqOi0RvdHjk1K+2wIBJIxk5pwjabewoxd2hpHRvU1TmFFXVGZapoTdjqKge3Nj2H0AxXl5eOMWlHsOOCTY7ZjUTUmVwrLL+JrVGyKCdbD1P8ALz3OMzDH63JaTLkp8Y17KG6k8OOKopKGIvII1GuxBtxb2G55/vj0HjqTlym/ZTlVUhPqqA/wWREVS8Uha+m+w2IB/LjGgprmhDTI2awuuVUxmLqI49Kqex1E2PvucdGVzdE1SsG0ccktSqxX1Dvbgep/PBt0rOirejpj4C9IJQ5TLWTxXnqW1K9iCYx8ot6Hn7jHmfifkPNlUU9L+TVwY/lw/Nl009Ivg2CgWsRccHFSNpWiW7dGWijuBGLXbAPYa12bWj0wGx78WxMlUQU9i91AqpSzCUnwyp498VcjldD8Zz7EIaTOqd6dkll/EukjWuCQbkqSeNyfXtvj0D5TxvkvVlZ1FiP1DXvJmwicqRCWN/fUf73xqePjUcdr2UMsvqPa5LVVVG88dNK8RYBNKni3Jt62wXz4xbi2FxbV0Fum80qKevSnqZXpp1kChilib8bYR5GFSi5R2LafRfGW9RR1FHFBUxzyGMJTuIxpAfgAXtfb19748/ODT2WYz0e6l6GOnWVzXxr4nhp8urUb3BBa/wBzhP1ctfuE6rZVOe0aNCskauXSO7Kw0rIO2/pe36Y1sGRp02VpxdWKeeS02V5PGs0aLUMRaPuSMaGLnlyWnoBpRVsQayplq5DJMQVDHSnZfYY0IxSWhTdlp/B3pMZtRzVksPiXa2+1gP2A2NxvjH+JeY8clCJf8TEmuTOm+k8pGU5VBT69ciLubW1H1AxhOTcm37LcpWHwBYDa/e+Du9AL7mDGRp3IOq9sQ4vom/Z9UJqW1rEbHvgZHJ7EvrVo48qqBJJa6FTcHk9vU4RdzikWI9MpSopZ6itCUdGoUEkuyhUDXW9zfbgbcXxtQmlG5S3/AOCrkT6iiZknw5paurmq5JRmFbK5Z1SIyxq1727Ltfe57YXk+JTSUIql+4C8ZW5NhvOsloaOkZMwzGKIR/8AtJNVrCL8GyxrueRtfAYcuSTk4x3+l/yFOMUtspvq5MtjrUejqF8YfM0c0rgenzqP0ON7xnkcWpr+DPy1eiT0v17XZUwhqJmeEEBJlVQwP9RNwdu/IwryPAhkuUdMnHlcdMtTJ/iHPDCGzFEZJPKr+EmpbDctpA59TvjMn4bb+mi1GQKp0myd2rM8rqengC6pUldW2K7WUEkX+vNhbA5az/Rhi2/0ohfRuWim+r83Gd59PVxK0dKvkp47Wsg9vfnHofGwfIxqDdv2Uck+UrQMjjaQrCpbzDg84baQNM6J+Due02Vwfgc5XRS2DxS6SFF+dQ/Kx+2PM/EcDlk+bD/Zq+PlShxZfFPXUtTRGqpqiOSMjV4isCCPrx3xm8lX2D4uyTSFpRrIIU4OKs6TrROATQe/IGHqOhLbs1SeGgYHn62H1wuSDTbK862rqGOOZDLrYA/JJpAJG4v22v72xWWJzmmh/wAxQVMqPMetMloJJHaMZhU2IjhtaFe3H83bnGvj+HZsi/xX7lV+RFO3sWM++JOdVkfgzVy5fSqDppqRLEDi5tsP0Pti/g+F4obrl+bEy8lvrQjVuc1Uxv8AiZyp/pA3+u+NKOCEVVFdzb7YPeeRyLs7G9zra+DSSAb9mI9QG1irHcDg46jhx6Unlqf/AEzYTIC8bjctYElSODtc7+n0xUz41H+5/wB/UtYJuX0P/v5A3rmeq/i38PqleMU41OjC12Nz+gNh9cT4UY8OcfYnNafF+hZbbzXv7W74t0IDmQQJJI81TfSGAuDxte+/+cYRlbWkGl9xsjzYitpIqYMksqDQNfyKCbk32vYHn/5DFT5Sabl6GqdPQcyjNJTI6ZfO1KsVtbU8ugsx33HDADfj88V8mBNXJXY6GV9Idss+IWf5epi/iaT6AAyVFOCRe1hdbeo5v2xVfiQ7imv9jVlT7C8HxZro95IKCcKbF4y4J/Q/TAf0kv8AIJzh3REz74pVE1NIbU9DDGt5JSS+/ZFIFy1+w3+g3wEfDcpV2BLyIpfSVD1D1f40FU5m8JpzaOJV8SZ151MSdMYNztuxxq4PD4ta6/4/19ytPNYjPXSyE+CCt99iSxPqTycaKikV07C2X5bClI1bVgtHTjdb7SPvZfzt+uFSnLkox7YVLshVcaRKseka7NyNgbL/AM4bFtnPQLWOQm6q5ABJ8p49T7e+D5AbZ6VvmNh2sL8Y6yVYRy+qemqaadLiSFw4sObdt8RJcotP2HGTi7XZ/9k=";
+
+}  // anonymous namespace
+
+class FaceDetectionImplMacTest : public TestWithParam<bool> {
+ public:
+  ~FaceDetectionImplMacTest() override {}
+
+  void DetectCallback(mojom::FaceDetectionResultPtr results) {
+    Detection(results->bounding_boxes.size());
+  }
+  MOCK_METHOD1(Detection, void(size_t));
+
+  std::unique_ptr<FaceDetectionImplMac> impl_;
+  const base::MessageLoop message_loop_;
+};
+
+TEST_F(FaceDetectionImplMacTest, CreateAndDestroy) {
+  impl_ = base::MakeUnique<FaceDetectionImplMac>(
+      shape_detection::mojom::FaceDetectorOptions::New());
+}
+
+TEST_P(FaceDetectionImplMacTest, ScanOneFace) {
+  // Face detection test needs a GPU.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kUseGpuInTests)) {
+    return;
+  }
+
+  auto options = shape_detection::mojom::FaceDetectorOptions::New();
+  options->fast_mode = GetParam();
+  impl_ = base::MakeUnique<FaceDetectionImplMac>(std::move(options));
+
+  std::string image_as_jpeg;
+  ASSERT_TRUE(base::Base64Decode(kJpegImageInBase64, &image_as_jpeg));
+
+  std::unique_ptr<SkBitmap> image = gfx::JPEGCodec::Decode(
+      reinterpret_cast<const uint8_t*>(image_as_jpeg.data()),
+      image_as_jpeg.size());
+  ASSERT_TRUE(image);
+  ASSERT_EQ(kJpegImageWidth, image->width());
+  ASSERT_EQ(kJpegImageHeight, image->height());
+
+  const gfx::Size size(image->width(), image->height());
+  const int num_bytes = size.GetArea() * 4 /* bytes per pixel */;
+  ASSERT_EQ(num_bytes, image->computeSize64());
+
+  // Generate a new ScopedSharedBufferHandle of the aproppriate size, map it and
+  // copy the image pixels into it.
+  mojo::ScopedSharedBufferHandle handle =
+      mojo::SharedBufferHandle::Create(num_bytes);
+  ASSERT_TRUE(handle->is_valid());
+
+  mojo::ScopedSharedBufferMapping mapping = handle->Map(num_bytes);
+  ASSERT_TRUE(mapping);
+
+  memcpy(mapping.get(), image->getPixels(), num_bytes);
+
+  base::RunLoop run_loop;
+  base::Closure quit_closure = run_loop.QuitClosure();
+  // Send the image to Detect() and expect the response in callback.
+  EXPECT_CALL(*this, Detection(1)).WillOnce(RunClosure(quit_closure));
+  impl_->Detect(std::move(handle), size.width(), size.height(),
+                base::Bind(&FaceDetectionImplMacTest::DetectCallback,
+                           base::Unretained(this)));
+
+  run_loop.Run();
+}
+
+INSTANTIATE_TEST_CASE_P(, FaceDetectionImplMacTest, ValuesIn({true, false}));
+
+}  // shape_detection namespace
diff --git a/services/ui/display/BUILD.gn b/services/ui/display/BUILD.gn
index c0bd6e73..ddd6894 100644
--- a/services/ui/display/BUILD.gn
+++ b/services/ui/display/BUILD.gn
@@ -21,19 +21,26 @@
     "//ui/gfx",
   ]
 
-  if (use_ozone && is_chromeos) {
-    sources += [
-      "screen_manager_ozone_internal.cc",
-      "screen_manager_ozone_internal.h",
-    ]
+  if (use_ozone) {
+    if (is_chromeos) {
+      sources += [
+        "screen_manager_ozone_internal.cc",
+        "screen_manager_ozone_internal.h",
+      ]
 
-    deps += [
-      "//chromeos",
-      "//services/ui/public/interfaces/display",
-      "//skia",
-      "//ui/display/manager",
-      "//ui/ozone",
-    ]
+      deps += [
+        "//chromeos",
+        "//services/ui/public/interfaces/display",
+        "//skia",
+        "//ui/display/manager",
+        "//ui/ozone",
+      ]
+    } else {
+      sources += [
+        "screen_manager_ozone_external.cc",
+        "screen_manager_ozone_external.h",
+      ]
+    }
   } else {
     sources += [
       "screen_manager_stub_internal.cc",
diff --git a/services/ui/display/screen_manager_ozone_external.cc b/services/ui/display/screen_manager_ozone_external.cc
new file mode 100644
index 0000000..e3dfb5a
--- /dev/null
+++ b/services/ui/display/screen_manager_ozone_external.cc
@@ -0,0 +1,34 @@
+// 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 "services/ui/display/screen_manager_ozone_external.h"
+
+#include <memory>
+
+#include "services/service_manager/public/cpp/interface_registry.h"
+#include "ui/display/types/display_constants.h"
+
+namespace display {
+
+// static
+std::unique_ptr<ScreenManager> ScreenManager::Create() {
+  return base::MakeUnique<ScreenManagerOzoneExternal>();
+}
+
+ScreenManagerOzoneExternal::ScreenManagerOzoneExternal() {}
+
+ScreenManagerOzoneExternal::~ScreenManagerOzoneExternal() {}
+
+void ScreenManagerOzoneExternal::AddInterfaces(
+    service_manager::InterfaceRegistry* registry) {}
+
+void ScreenManagerOzoneExternal::Init(ScreenManagerDelegate* delegate) {}
+
+void ScreenManagerOzoneExternal::RequestCloseDisplay(int64_t display_id) {}
+
+int64_t ScreenManagerOzoneExternal::GetPrimaryDisplayId() const {
+  return kInvalidDisplayId;
+}
+
+}  // namespace display
diff --git a/services/ui/display/screen_manager_ozone_external.h b/services/ui/display/screen_manager_ozone_external.h
new file mode 100644
index 0000000..31a3b6c
--- /dev/null
+++ b/services/ui/display/screen_manager_ozone_external.h
@@ -0,0 +1,36 @@
+// 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 SERVICES_UI_DISPLAY_SCREEN_MANAGER_OZONE_EXTERNAL_H_
+#define SERVICES_UI_DISPLAY_SCREEN_MANAGER_OZONE_EXTERNAL_H_
+
+#include "services/ui/display/screen_manager.h"
+
+namespace display {
+
+// In external window mode, the purpose of having a ScreenManager
+// does not apply: there is not a ScreenManagerDelegate manager
+// responsible for creating Display instances.
+// Basically, in this mode WindowTreeHost creates the display instance.
+//
+// ScreenManagerOzoneExternal provides the stub out implementation
+// of ScreenManager for Ozone non-chromeos platforms.
+class ScreenManagerOzoneExternal : public ScreenManager {
+ public:
+  ScreenManagerOzoneExternal();
+  ~ScreenManagerOzoneExternal() override;
+
+ private:
+  // ScreenManager.
+  void AddInterfaces(service_manager::InterfaceRegistry* registry) override;
+  void Init(ScreenManagerDelegate* delegate) override;
+  int64_t GetPrimaryDisplayId() const override;
+  void RequestCloseDisplay(int64_t display_id) override;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenManagerOzoneExternal);
+};
+
+}  // namespace display
+
+#endif  // SERVICES_UI_DISPLAY_SCREEN_MANAGER_OZONE_EXTERNAL_H_
diff --git a/services/ui/gpu/interfaces/gpu_service.mojom b/services/ui/gpu/interfaces/gpu_service.mojom
index 6e0ac9b7..d6ca5fc 100644
--- a/services/ui/gpu/interfaces/gpu_service.mojom
+++ b/services/ui/gpu/interfaces/gpu_service.mojom
@@ -17,7 +17,7 @@
   EstablishGpuChannel(int32 client_id,
                       uint64 client_tracing_id,
                       bool is_gpu_host)
-      => (handle<message_pipe> channel_handle);
+      => (handle<message_pipe>? channel_handle);
 
   [Sync]
   CreateGpuMemoryBuffer(gfx.mojom.GpuMemoryBufferId id,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index fc44464b..e265227 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -242,7 +242,7 @@
       },
       {
         "swarming": {
-          "can_use_on_swarming_builders": false
+          "can_use_on_swarming_builders": true
         },
         "test": "media_service_unittests"
       },
@@ -416,13 +416,13 @@
       },
       {
         "swarming": {
-          "can_use_on_swarming_builders": false
+          "can_use_on_swarming_builders": true
         },
         "test": "views_mus_interactive_ui_tests"
       },
       {
         "swarming": {
-          "can_use_on_swarming_builders": false
+          "can_use_on_swarming_builders": true
         },
         "test": "views_mus_unittests"
       },
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index eedc346..fd8bb9b 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -5483,6 +5483,23 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.12"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -5833,6 +5850,24 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -6219,6 +6254,24 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false,
+          "dimension_sets": [
+            {
+              "gpu": "10de:0fe9",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -6618,6 +6671,28 @@
         "use_xvfb": false
       },
       {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.12"
+            },
+            {
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
+      },
+      {
         "override_compile_targets": [
           "tab_capture_end2end_tests_run"
         ],
@@ -7046,6 +7121,23 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false,
+          "dimension_sets": [
+            {
+              "gpu": "1002:679e",
+              "os": "Mac-10.10"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -7390,6 +7482,23 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false,
+          "dimension_sets": [
+            {
+              "gpu": "1002:679e",
+              "os": "Mac-10.10"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -7749,6 +7858,23 @@
         "use_xvfb": false
       },
       {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.12"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
+      },
+      {
         "override_compile_targets": [
           "tab_capture_end2end_tests_run"
         ],
@@ -8126,6 +8252,24 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -8472,6 +8616,24 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:0fe9",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -8820,6 +8982,24 @@
         "use_xvfb": false
       },
       {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
+      },
+      {
         "override_compile_targets": [
           "tab_capture_end2end_tests_run"
         ],
@@ -9210,6 +9390,24 @@
         "use_xvfb": false
       },
       {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:0fe9",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
+      },
+      {
         "override_compile_targets": [
           "tab_capture_end2end_tests_run"
         ],
@@ -9663,6 +9861,23 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.12"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -9730,6 +9945,24 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -9796,6 +10029,23 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.12"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -9863,6 +10113,24 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:0fe9",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -9931,6 +10199,24 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "1002:6821",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
@@ -9999,6 +10285,24 @@
         },
         "test": "gles2_conform_test",
         "use_xvfb": false
+      },
+      {
+        "args": [
+          "--gtest_filter=*Detection*",
+          "--use-gpu-in-tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:0fe9",
+              "hidpi": "1",
+              "os": "Mac"
+            }
+          ]
+        },
+        "test": "service_unittests",
+        "use_xvfb": false
       }
     ],
     "isolated_scripts": [
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 4b766d5..a9ac12d 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -11192,7 +11192,7 @@
           "dimension_sets": [
             {
               "gpu": "102b:0534",
-              "id": "build150-m1",
+              "id": "build149-m1",
               "os": "Ubuntu-14.04",
               "pool": "Chrome-perf"
             }
@@ -11221,7 +11221,7 @@
           "dimension_sets": [
             {
               "gpu": "102b:0534",
-              "id": "build150-m1",
+              "id": "build149-m1",
               "os": "Ubuntu-14.04",
               "pool": "Chrome-perf"
             }
@@ -23303,7 +23303,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "id": "build161-m1",
+              "id": "build162-m1",
               "os": "Mac-10.12",
               "pool": "Chrome-perf"
             }
@@ -23332,7 +23332,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "id": "build161-m1",
+              "id": "build162-m1",
               "os": "Mac-10.12",
               "pool": "Chrome-perf"
             }
@@ -26780,7 +26780,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "id": "build160-m1",
+              "id": "build162-m1",
               "os": "Mac-10.12",
               "pool": "Chrome-perf"
             }
@@ -26809,7 +26809,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:0a2e",
-              "id": "build160-m1",
+              "id": "build162-m1",
               "os": "Mac-10.12",
               "pool": "Chrome-perf"
             }
@@ -178889,7 +178889,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:161e",
-              "id": "build32-b1",
+              "id": "build31-b1",
               "os": "Windows-10-10240",
               "pool": "Chrome-perf"
             }
@@ -179032,7 +179032,7 @@
           "dimension_sets": [
             {
               "gpu": "8086:161e",
-              "id": "build32-b1",
+              "id": "build31-b1",
               "os": "Windows-10-10240",
               "pool": "Chrome-perf"
             }
diff --git a/testing/buildbot/filters/OWNERS b/testing/buildbot/filters/OWNERS
index ed0dda6..b9ed1d6e 100644
--- a/testing/buildbot/filters/OWNERS
+++ b/testing/buildbot/filters/OWNERS
@@ -9,3 +9,5 @@
 per-file browser-side-navigation*=nasko@chromium.org
 per-file browser-side-navigation*=scottmg@chromium.org
 per-file browser-side-navigation*=yzshen@chromium.org
+
+# COMPONENT: Infra>Platform>Buildbot
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 9a2a554..266ea8a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -2522,6 +2522,43 @@
             ]
         }
     ],
+    "TranslateServerStudy": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "SmartRendering",
+                    "params": {
+                        "server_params": "smrd"
+                    }
+                }
+            ]
+        }
+    ],
+    "TranslateUI2016Q2": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "win"
+            ],
+            "experiments": [
+                {
+                    "name": "TranslateUI2016Q2OnGroup",
+                    "enable_features": [
+                        "TranslateUI2016Q2"
+                    ]
+                }
+            ]
+        }
+    ],
     "TranslateUiLangTrial": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index ff02ea2..f054653 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -311,7 +311,7 @@
 crbug.com/658211 [ Win7 Debug ] fast/text/line-break-ascii.html [ Slow ]
 
 crbug.com/445194 fast/dom/shadow/focus-controller-recursion-crash.html [ Slow ]
-
+crbug.com/626703 external/wpt/selection/selectAllChildren.html [ Slow ]
 crbug.com/584807 printing/webgl-oversized-printing.html [ Slow ]
 crbug.com/584807 virtual/threaded/printing/webgl-oversized-printing.html [ Slow ]
 
@@ -344,10 +344,7 @@
 
 crbug.com/660492 [ Linux ] storage/indexeddb/structured-clone.html [ Slow ]
 
-# Usually plenty fast, but sometimes very slow on windows.
-crbug.com/678498 [ Win ] http/tests/serviceworker/foreign-fetch-cors.html [ Slow ]
-crbug.com/678498 [ Win ] virtual/mojo-loading/http/tests/serviceworker/foreign-fetch-cors.html [ Slow ]
-crbug.com/678498 [ Win ] virtual/service-worker-navigation-preload/http/tests/serviceworker/foreign-fetch-cors.html [ Slow ]
-crbug.com/678496 [ Win ] http/tests/serviceworker/foreign-fetch-basics.html [ Slow ]
-crbug.com/678496 [ Win ] virtual/mojo-loading/http/tests/serviceworker/foreign-fetch-basics.html [ Slow ]
-crbug.com/678496 [ Win ] virtual/service-worker-navigation-preload/http/tests/serviceworker/foreign-fetch-basics.html [ Slow ]
+# Foreign fetch tests make many requests, and create multiple browsing contexts,
+# which can be very slow.
+crbug.com/678498 external/wpt/service-workers/service-worker/foreign-fetch-cors.https.html [ Slow ]
+crbug.com/678496 external/wpt/service-workers/service-worker/foreign-fetch-basics.https.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index ace521f..48183017 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -956,6 +956,10 @@
 # MANIFEST.json contains any *-manual.*. https://github.com/w3c/web-platform-tests/issues/4137
 Bug(github) external/wpt/uievents/keyboard/key-manual.css [ Skip ]
 Bug(github) external/wpt/uievents/keyboard/key-manual.js [ Skip ]
+crbug.com/691887 [ Linux Win ] external/wpt/selection/extend-00.html [ NeedsRebaseline ]
+crbug.com/691887 [ Linux Win ] external/wpt/selection/extend-20.html [ NeedsRebaseline ]
+crbug.com/691887 [ Linux Win ] external/wpt/selection/extend-40.html [ NeedsRebaseline ]
+crbug.com/691887 [ Linux Win ] external/wpt/selection/selectAllChildren.html [ NeedsRebaseline ]
 
 crbug.com/387740 external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html [ Skip ]
 crbug.com/387740 external/wpt/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html [ Skip ]
@@ -1290,8 +1294,6 @@
 # benefit to running them again with gpu acceleration enabled.
 crbug.com/555703 [ Linux Mac Win ] virtual/media-gpu-accelerated [ Skip ]
 
-crbug.com/253763 fast/text-autosizing/first-line-scale-factor.html [ Failure ]
-
 crbug.com/613887 http/tests/preload/meta-viewport-link-headers.html [ Failure Pass ]
 crbug.com/613887 virtual/mojo-loading/http/tests/preload/meta-viewport-link-headers.html [ Failure Pass ]
 crbug.com/564403 [ Win Debug ] http/tests/inspector/service-workers/service-worker-manager.html [ Failure Pass Timeout ]
@@ -1955,7 +1957,6 @@
 
 # Other untriaged test failures, timeouts and crashes from newly-imported WPT tests.
 crbug.com/626703 external/wpt/html/syntax/parsing/template/creating-an-element-for-the-token/template-owner-document.html [ Pass Timeout ]
-crbug.com/626703 external/wpt/selection/selectAllChildren.html [ Pass Timeout ]
 crbug.com/666703 external/wpt/html/browsers/sandboxing/sandbox-disallow-same-origin.html [ Timeout ]
 crbug.com/626703 external/wpt/html/dom/documents/dom-tree-accessors/Document.currentScript.html [ Timeout ]
 crbug.com/626703 external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html [ Failure Pass ]
@@ -2003,22 +2004,22 @@
 crbug.com/655458 external/wpt/workers/semantics/structured-clone/shared.html [ Crash Failure Timeout ]
 
 crbug.com/490511 external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/pause-remove-from-document-networkState.html [ Timeout ]
-crbug.com/602693 external/wpt/service-workers/service-worker/client-navigate.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/clients-get-cross-origin.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-canvas-tainting-cache.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-canvas-tainting.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-cors-xhr.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-csp.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-event-async-respond-with.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-request-css-base-url.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/fetch-response-xhr.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/getregistrations.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/invalid-blobtype.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/invalid-header.https.html [ Skip ]
-crbug.com/602693 external/wpt/service-workers/service-worker/referer.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/client-navigate.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/clients-get-cross-origin.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/clients-matchall-client-types.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-canvas-tainting-cache.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-canvas-tainting.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-cors-xhr.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-csp.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-event-async-respond-with.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-event-respond-with-stops-propagation.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-request-css-base-url.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-request-xhr.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/fetch-response-xhr.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/getregistrations.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/invalid-blobtype.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/invalid-header.https.html [ Skip ]
+crbug.com/658997 external/wpt/service-workers/service-worker/referer.https.html [ Skip ]
 
 # mojo-loading: This is an experimental feature. failing virtual tests are
 # listed below.
@@ -2114,10 +2115,8 @@
 crbug.com/602693 external/wpt/service-workers/stub-4.7.2.1-install-event-section.html [ Failure ]
 crbug.com/602693 external/wpt/service-workers/stub-4.7.4.1-fetch-event-section.html [ Failure ]
 
-crbug.com/618616 external/wpt/service-workers/service-worker/fetch-event-redirect.https.html [ Pass Timeout ]
-
-# Untriaged service-worker timeout. Is it crbug.com/618616?
-crbug.com/618616 external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Timeout ]
+# This test requires a special browser flag and seems not suitable for a wpt test, see bug.
+crbug.com/691944 external/wpt/service-workers/service-worker/update-after-oneday.https.html [ Skip ]
 
 # These tests (erroneously) see a platform-specific User-Agent header
 crbug.com/595993 external/wpt/service-workers/service-worker/fetch-header-visibility.https.html [ Failure ]
@@ -2304,3 +2303,6 @@
 
 # Sheriff failures Feb 06 2017
 crbug.com/688515 [ Linux ] http/tests/media/video-play-stall.html [ Pass Failure ]
+
+# Sheriff failures Feb 13 2017
+crbug.com/691423 [ Mac ] fast/frames/location-change-no-file-access.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/bluetooth/characteristic/service-same-from-2-characteristics.html b/third_party/WebKit/LayoutTests/bluetooth/characteristic/service-same-from-2-characteristics.html
new file mode 100644
index 0000000..98abc5e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/characteristic/service-same-from-2-characteristics.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(() => {
+  return setBluetoothFakeAdapter('HeartRateAdapter')
+    .then(() => requestDeviceWithKeyDown({
+      filters: [{services: ['heart_rate']}]}))
+    .then(device => device.gatt.connect())
+    .then(gattServer => gattServer.getPrimaryService('heart_rate'))
+    .then(service => {
+      return Promise.all([service.getCharacteristic('body_sensor_location'),
+                          service.getCharacteristic('heart_rate_measurement')]);
+    }).then(characteristics => {
+      assert_equals(characteristics[0].service, characteristics[1].service);
+    });
+}, "Same parent service returned from multiple characteristics.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/characteristic/service-same-object.html b/third_party/WebKit/LayoutTests/bluetooth/characteristic/service-same-object.html
new file mode 100644
index 0000000..9027464
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/characteristic/service-same-object.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(() => {
+  return setBluetoothFakeAdapter('HeartRateAdapter')
+    .then(() => requestDeviceWithKeyDown({
+      filters: [{services: ['heart_rate']}]}))
+    .then(device => device.gatt.connect())
+    .then(gattServer => gattServer.getPrimaryService('heart_rate'))
+    .then(service => service.getCharacteristic('body_sensor_location'))
+    .then(characteristic => {
+      assert_equals(characteristic.service, characteristic.service);
+    });
+}, "[SameObject] test for BluetoothRemoteGATTCharacteristic's service.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/descriptor/characteristic-same-from-2-descriptors.html b/third_party/WebKit/LayoutTests/bluetooth/descriptor/characteristic-same-from-2-descriptors.html
new file mode 100644
index 0000000..fe0222a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/descriptor/characteristic-same-from-2-descriptors.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(() => {
+  return setBluetoothFakeAdapter('DisconnectingHealthThermometerAdapter')
+    .then(() => requestDeviceWithKeyDown({
+      filters: [{services: ['health_thermometer']}]}))
+    .then(device => device.gatt.connect())
+    .then(gattServer => gattServer.getPrimaryService('health_thermometer'))
+    .then(service => service.getCharacteristic('measurement_interval'))
+    .then(characteristic => {
+      return Promise.all([characteristic.getDescriptor('gatt.characteristic_user_description'),
+                          characteristic.getDescriptor('gatt.client_characteristic_configuration')]);
+    }).then(descriptors => {
+      assert_equals(descriptors[0].characteristic, descriptors[1].characteristic);
+    });
+}, "Same parent characteristic returned from multiple descriptors.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/descriptor/characteristic-same-object.html b/third_party/WebKit/LayoutTests/bluetooth/descriptor/characteristic-same-object.html
new file mode 100644
index 0000000..e2815a8a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/descriptor/characteristic-same-object.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(() => {
+  return setBluetoothFakeAdapter('DisconnectingHealthThermometerAdapter')
+    .then(() => requestDeviceWithKeyDown({
+      filters: [{services: ['health_thermometer']}]}))
+    .then(device => device.gatt.connect())
+    .then(gattServer => gattServer.getPrimaryService('health_thermometer'))
+    .then(service => service.getCharacteristic('measurement_interval'))
+    .then(characteristic => characteristic.getDescriptor('gatt.characteristic_user_description'))
+    .then(descriptor => {
+      assert_equals(descriptor.characteristic, descriptor.characteristic);
+    });
+}, "[SameObject] test for BluetoothRemoteGATTDescriptor's characteristic.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/server/device-same-object.html b/third_party/WebKit/LayoutTests/bluetooth/server/device-same-object.html
new file mode 100644
index 0000000..bbba6ddb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/server/device-same-object.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(() => {
+  return setBluetoothFakeAdapter('HeartRateAdapter')
+    .then(() => requestDeviceWithKeyDown({
+      filters: [{services: ['heart_rate']}]}))
+    .then(device => device.gatt.connect())
+    .then(gattServer => {
+      assert_equals(gattServer.device, gattServer.device);
+    });
+}, "[SameObject] test for BluetoothRemoteGATTServer's device.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/device-same-from-2-services.html b/third_party/WebKit/LayoutTests/bluetooth/service/device-same-from-2-services.html
new file mode 100644
index 0000000..4056825
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/service/device-same-from-2-services.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(() => {
+  return setBluetoothFakeAdapter('TwoHeartRateServicesAdapter')
+    .then(() => requestDeviceWithKeyDown({
+      filters: [{services: ['heart_rate']}]}))
+    .then(device => device.gatt.connect())
+    .then(gattServer => gattServer.getPrimaryServices('heart_rate'))
+    .then(services => {
+      assert_equals(services[0].device, services[1].device);
+    });
+}, "Same parent device returned from multiple services.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/service/device-same-object.html b/third_party/WebKit/LayoutTests/bluetooth/service/device-same-object.html
new file mode 100644
index 0000000..91388573
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/bluetooth/service/device-same-object.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(() => {
+  return setBluetoothFakeAdapter('HeartRateAdapter')
+    .then(() => requestDeviceWithKeyDown({
+      filters: [{services: ['heart_rate']}]}))
+    .then(device => device.gatt.connect())
+    .then(gattServer => gattServer.getPrimaryService('heart_rate'))
+    .then(service => {
+      assert_equals(service.device, service.device);
+    });
+}, "[SameObject] test for BluetoothRemoteGATTService's device.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/delete-br-001-expected.txt b/third_party/WebKit/LayoutTests/editing/deleting/delete-br-001-expected.txt
index 630af0b..44b0a807 100644
--- a/third_party/WebKit/LayoutTests/editing/deleting/delete-br-001-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/deleting/delete-br-001-expected.txt
@@ -6,13 +6,13 @@
 PASS selection.anchorOffset is 2
 PASS $("work").innerHTML is "abc<br id=\"a\"><br id=\"b\">def"
 PASS selection.type is "Caret"
-PASS selection.anchorOffset is 0
+PASS selection.anchorOffset is 3
 PASS $("work").innerHTML is "abc<br id=\"c\">def"
 PASS selection.type is "Caret"
 PASS selection.anchorOffset is 3
 PASS $("work").innerHTML is "abc<br id=\"a\">def"
 PASS selection.type is "Caret"
-PASS selection.anchorOffset is 0
+PASS selection.anchorOffset is 2
 PASS $("work").innerHTML is "abcdef"
 PASS selection.type is "Caret"
 PASS selection.anchorOffset is 3
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/delete-br-001.html b/third_party/WebKit/LayoutTests/editing/deleting/delete-br-001.html
index 8f3c0f4..d3774130 100644
--- a/third_party/WebKit/LayoutTests/editing/deleting/delete-br-001.html
+++ b/third_party/WebKit/LayoutTests/editing/deleting/delete-br-001.html
@@ -24,9 +24,9 @@
 
 testIt(0, 1, 3, 'abc<br id="b"><br id="c">def');
 testIt(1, 1, 2, 'abc<br id="a"><br id="c">def');
-testIt(2, 1, 0, 'abc<br id="a"><br id="b">def');
+testIt(2, 1, 3, 'abc<br id="a"><br id="b">def');
 testIt(1, 2, 3, 'abc<br id="c">def');
-testIt(2, 2, 0, 'abc<br id="a">def');
+testIt(2, 2, 2, 'abc<br id="a">def');
 testIt(2, 3, 3, 'abcdef');
 
 if (window.testRunner)
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/delete-character-003-expected.txt b/third_party/WebKit/LayoutTests/editing/deleting/delete-character-003-expected.txt
index 5f69066..fdbc383 100644
--- a/third_party/WebKit/LayoutTests/editing/deleting/delete-character-003-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/deleting/delete-character-003-expected.txt
@@ -43,14 +43,14 @@
 a<br><br>|b
 PASS sample.innerHTML is "a<br>b"
 PASS selection.type is "Caret"
-PASS selection.focusNode is sample.lastChild
-PASS selection.focusOffset is 0
+PASS selection.focusNode is sample
+PASS selection.focusOffset is 2
 
 a<br><br><br>|b
 PASS sample.innerHTML is "a<br><br>b"
 PASS selection.type is "Caret"
-PASS selection.focusNode is sample.lastChild
-PASS selection.focusOffset is 0
+PASS selection.focusNode is sample
+PASS selection.focusOffset is 3
 
 a<br>b|
 PASS sample.innerHTML is "a<br><br>"
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/delete-character-003.html b/third_party/WebKit/LayoutTests/editing/deleting/delete-character-003.html
index 87029a34..1678536e 100644
--- a/third_party/WebKit/LayoutTests/editing/deleting/delete-character-003.html
+++ b/third_party/WebKit/LayoutTests/editing/deleting/delete-character-003.html
@@ -40,8 +40,8 @@
 testIt('a<br><br>|<br><br>', 'a<br><br><br>', 'sample', 2);
 
 testIt('a<br>|b', 'ab', 'sample.firstChild', 1);
-testIt('a<br><br>|b', 'a<br>b', 'sample.lastChild', 0);
-testIt('a<br><br><br>|b', 'a<br><br>b', 'sample.lastChild', 0);
+testIt('a<br><br>|b', 'a<br>b', 'sample', 2);
+testIt('a<br><br><br>|b', 'a<br><br>b', 'sample', 3);
 
 testIt('a<br>b|', 'a<br><br>', 'sample', 2);
 testIt('a<br><br>b|', 'a<br><br><br>', 'sample', 3);
diff --git a/third_party/WebKit/LayoutTests/editing/deleting/forward-delete-empty-table-cell-expected.txt b/third_party/WebKit/LayoutTests/editing/deleting/forward-delete-empty-table-cell-expected.txt
index 491ad63d..6fb2fee 100644
--- a/third_party/WebKit/LayoutTests/editing/deleting/forward-delete-empty-table-cell-expected.txt
+++ b/third_party/WebKit/LayoutTests/editing/deleting/forward-delete-empty-table-cell-expected.txt
@@ -20,8 +20,9 @@
 |         "3"
 |       <td>
 |         id="fourth"
-|         <#selection-caret>
+|         <#selection-anchor>
 |         <br>
+|         <#selection-focus>
 |     "
 "
 |   "
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/move-up-down-should-skip-hidden-elements-expected.txt b/third_party/WebKit/LayoutTests/editing/execCommand/move-up-down-should-skip-hidden-elements-expected.txt
deleted file mode 100644
index 5e24858..0000000
--- a/third_party/WebKit/LayoutTests/editing/execCommand/move-up-down-should-skip-hidden-elements-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-First line of rendered text
-
-Test moving up and down through non-renderered elements. This test should execute quickly if it's working correctly; a timeout is a failure.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/editing/execCommand/move-up-down-should-skip-hidden-elements.html b/third_party/WebKit/LayoutTests/editing/execCommand/move-up-down-should-skip-hidden-elements.html
deleted file mode 100644
index cc5b8d9..0000000
--- a/third_party/WebKit/LayoutTests/editing/execCommand/move-up-down-should-skip-hidden-elements.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-<title>Test moving up and down through non-renderered elements.</title>
-</head>
-<body>
-<div id="before" hidden></div>
-<h1 id="first_line">First line of rendered text</h1>
-<div id="after" hidden></div>
-
-<p id="description"></p>
-<div id="console"></div>
-
-<script>
-description("Test moving up and down through non-renderered elements. This test should execute quickly if it's working correctly; a timeout is a failure.");
-
-var before = document.getElementById("before");
-var after = document.getElementById("after");
-for (var i = 0; i < 1000; i++) {
-    before.appendChild(document.createElement("meta"));
-    after.appendChild(document.createElement("meta"));
-}
-
-function selectFirstLine() {
-    var selection = document.getSelection();
-    selection.removeAllRanges();
-    var range = document.createRange();
-    range.selectNode(document.getElementById("first_line"));
-    selection.addRange(range);
-}
-
-for (var i = 0; i < 100; i++) {
-    selectFirstLine();
-    if (window.testRunner)
-        testRunner.execCommand("MoveUpAndModifySelection");
-
-    selectFirstLine();
-    if (window.testRunner)
-        testRunner.execCommand("MoveDownAndModifySelection");
-}
-
-before.textContent = "";
-after.textContent = "";
-
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json b/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json
index 136d3f3d..221b5c6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/wpt/MANIFEST.json
@@ -12342,11 +12342,6 @@
      {}
     ]
    ],
-   "html/semantics/forms/form-submission-0/submit-entity-body-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/forms/introduction-1/contains.json": [
     [
      {}
@@ -12467,11 +12462,6 @@
      {}
     ]
    ],
-   "html/semantics/forms/the-label-element/label-attributes-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/forms/the-label-element/labelable-elements-expected.txt": [
     [
      {}
@@ -14907,6 +14897,41 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/foreign-fetch-cors-worker.js": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/foreign-fetch-event-worker.js": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/foreign-fetch-helper-iframe.html": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/foreign-fetch-helper-script.js": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/foreign-fetch-helper-worker.js": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/foreign-fetch-helpers.js": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/foreign-fetch-worker.js": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/frame-for-getregistrations.html": [
     [
      {}
@@ -14927,6 +14952,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/install-worker-helper.html": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/interfaces-worker.sub.js": [
     [
      {}
@@ -15142,6 +15172,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/reply-to-message.html": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/request-end-to-end-worker.js": [
     [
      {}
@@ -30455,6 +30490,30 @@
      }
     ]
    ],
+   "service-workers/service-worker/foreign-fetch-basics.https.html": [
+    [
+     "/service-workers/service-worker/foreign-fetch-basics.https.html",
+     {}
+    ]
+   ],
+   "service-workers/service-worker/foreign-fetch-cors.https.html": [
+    [
+     "/service-workers/service-worker/foreign-fetch-cors.https.html",
+     {}
+    ]
+   ],
+   "service-workers/service-worker/foreign-fetch-event.https.html": [
+    [
+     "/service-workers/service-worker/foreign-fetch-event.https.html",
+     {}
+    ]
+   ],
+   "service-workers/service-worker/foreign-fetch-workers.https.html": [
+    [
+     "/service-workers/service-worker/foreign-fetch-workers.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/getregistration.https.html": [
     [
      "/service-workers/service-worker/getregistration.https.html",
@@ -34591,7 +34650,7 @@
    "support"
   ],
   "./MANIFEST.json": [
-   "3627cc58604c1dac4d80a81119a1ec865d71b576",
+   "2218448cc0bbce67ddc610f1025d3eac8c72474e",
    "support"
   ],
   "./README.md": [
@@ -37491,7 +37550,7 @@
    "testharness"
   ],
   "dom/nodes/Node-childNodes-expected.txt": [
-   "577855c6949ebc70ef6a849ad526a734042e119a",
+   "1e019a2f0efe24029bf1050d5e96659248b71a08",
    "support"
   ],
   "dom/nodes/Node-childNodes.html": [
@@ -48030,10 +48089,6 @@
    "92c8c30e186f0a94a962bb5c4be7acf0860b943e",
    "testharness"
   ],
-  "html/semantics/forms/form-submission-0/submit-entity-body-expected.txt": [
-   "40598e87f886906294a176573b4c22ea35cf574e",
-   "support"
-  ],
   "html/semantics/forms/form-submission-0/submit-entity-body.html": [
    "f73376af978f2fb89dcbd6e9092f113d90c7a3d6",
    "testharness"
@@ -48390,10 +48445,6 @@
    "851b1b794f820b1fb9b7ee57fe39f8f2977b7fe6",
    "testharness"
   ],
-  "html/semantics/forms/the-label-element/label-attributes-expected.txt": [
-   "97ad843a75ce3f3f9b917610a9ffed7dafb9f226",
-   "support"
-  ],
   "html/semantics/forms/the-label-element/label-attributes.html": [
    "bb00ee78b9fa2343d85dcaa13376a832d376617a",
    "testharness"
@@ -52039,7 +52090,7 @@
    "testharness"
   ],
   "selection/addRange-00-expected.txt": [
-   "67edff8d9542d5b9961bae7435b960d98ca5a64e",
+   "9b9f992e87e203b469e7b4b5394325d555b25f2c",
    "support"
   ],
   "selection/addRange-00.html": [
@@ -52047,7 +52098,7 @@
    "testharness"
   ],
   "selection/addRange-04-expected.txt": [
-   "f05966bba89babc8a150804e4a754566522b6826",
+   "3516afa2d2afca7a118527b9e9067c91c0c96706",
    "support"
   ],
   "selection/addRange-04.html": [
@@ -52055,7 +52106,7 @@
    "testharness"
   ],
   "selection/addRange-08-expected.txt": [
-   "83db5e9f0c6e61e61505811edde31ead87431307",
+   "e643c7d945d12761792a8c291e4b1ab007358978",
    "support"
   ],
   "selection/addRange-08.html": [
@@ -52063,7 +52114,7 @@
    "testharness"
   ],
   "selection/addRange-12-expected.txt": [
-   "c014d12e814743f36947486526fbb4e4ac9f29ec",
+   "fe251308c7f5b99a3a22a8c35b42940837585f94",
    "support"
   ],
   "selection/addRange-12.html": [
@@ -52071,7 +52122,7 @@
    "testharness"
   ],
   "selection/addRange-16-expected.txt": [
-   "daeb1430f615d79d7fd537197b66bdd53e5b0ff0",
+   "d228ef5d934830f94efe7ae1448411c9d6baa7bb",
    "support"
   ],
   "selection/addRange-16.html": [
@@ -52079,7 +52130,7 @@
    "testharness"
   ],
   "selection/addRange-20-expected.txt": [
-   "1ee92b07655fcaaf8e57ce470a1195d2dbfcd40e",
+   "5faa0f8f7dc09ac250ac02afe5fbfda25867d079",
    "support"
   ],
   "selection/addRange-20.html": [
@@ -52087,7 +52138,7 @@
    "testharness"
   ],
   "selection/addRange-24-expected.txt": [
-   "8b76b5cd328cc38982e877dd4148ecede0349aec",
+   "e9adff76e6ba6f119b896e2b0b5f82230755b96c",
    "support"
   ],
   "selection/addRange-24.html": [
@@ -52095,7 +52146,7 @@
    "testharness"
   ],
   "selection/addRange-28-expected.txt": [
-   "f5f25b0400d554dfce01e4ee270ac70c1c5be8a0",
+   "09d293430f2d6298fb3918337824e9503d09ce07",
    "support"
   ],
   "selection/addRange-28.html": [
@@ -52103,7 +52154,7 @@
    "testharness"
   ],
   "selection/addRange-32-expected.txt": [
-   "f449692cb0e4247a11ba29d7d33bad80acb03598",
+   "aaa694aeb16d10182af2a84b1db2f530ba5e55a6",
    "support"
   ],
   "selection/addRange-32.html": [
@@ -52111,7 +52162,7 @@
    "testharness"
   ],
   "selection/addRange-36-expected.txt": [
-   "e4159c7c0b991d97fde7e8aaef5b5cb3de496c30",
+   "5cc99c2c0bbb15ecf2f6d1402d4467c577f82538",
    "support"
   ],
   "selection/addRange-36.html": [
@@ -52119,7 +52170,7 @@
    "testharness"
   ],
   "selection/addRange-40-expected.txt": [
-   "826a8b3910aaeef3d7842e7f65d77797454c62c5",
+   "f98f04aa2196d8382ff4d0f9b58af6fe5913c055",
    "support"
   ],
   "selection/addRange-40.html": [
@@ -52127,7 +52178,7 @@
    "testharness"
   ],
   "selection/addRange-44-expected.txt": [
-   "62e794c2aee0b0d29fdfdbc468a611fc394dbdaf",
+   "e282a96eabba35226712b158a659417173de87ac",
    "support"
   ],
   "selection/addRange-44.html": [
@@ -52135,7 +52186,7 @@
    "testharness"
   ],
   "selection/addRange-48-expected.txt": [
-   "e484b6301e9c22c9ff488b262396f58cb364d036",
+   "677a89a721f24392acf417712b6b45c70439f5af",
    "support"
   ],
   "selection/addRange-48.html": [
@@ -52143,7 +52194,7 @@
    "testharness"
   ],
   "selection/addRange-52-expected.txt": [
-   "a693d009fbbe9dd1efb366df08621a061ac1d077",
+   "3e80c1898900ee18d12e74b2d64ff56f56e2ad47",
    "support"
   ],
   "selection/addRange-52.html": [
@@ -52151,7 +52202,7 @@
    "testharness"
   ],
   "selection/addRange-56-expected.txt": [
-   "b07be14d773735a2eb57be8b1af607afacea15fd",
+   "bd303ef859922d449562fbace376ee5653cce84d",
    "support"
   ],
   "selection/addRange-56.html": [
@@ -52163,7 +52214,7 @@
    "support"
   ],
   "selection/collapse-00-expected.txt": [
-   "8b4e75041f2b19203d0a8e91bd1ce664d1306c0f",
+   "ef38d258d6bf9550f91fa7123a31743d4e5b1e66",
    "support"
   ],
   "selection/collapse-00.html": [
@@ -52171,7 +52222,7 @@
    "testharness"
   ],
   "selection/collapse-30-expected.txt": [
-   "4de9bf6f3c50957f3c336b57534ac82deaf84767",
+   "48757a2117fc43f06db8dd9da497d09f9053546f",
    "support"
   ],
   "selection/collapse-30.html": [
@@ -52183,7 +52234,7 @@
    "support"
   ],
   "selection/collapseToStartEnd-expected.txt": [
-   "424a34f194b7649464b4d271206142df7da3bf4d",
+   "2aaccb3f3524f137ddd73d56aeb1aca14640c10a",
    "support"
   ],
   "selection/collapseToStartEnd.html": [
@@ -52207,7 +52258,7 @@
    "manual"
   ],
   "selection/extend-00-expected.txt": [
-   "d66939957d8f36c0d33c33ca07c39a6ed9710f1a",
+   "394fb85e6191d2c27cee440478486856c77764c2",
    "support"
   ],
   "selection/extend-00.html": [
@@ -52215,7 +52266,7 @@
    "testharness"
   ],
   "selection/extend-20-expected.txt": [
-   "8aaefb9260e65d8743e1d424fa0438715768e355",
+   "976b3c34f6f69b343dc93663c7ccad08b12225ae",
    "support"
   ],
   "selection/extend-20.html": [
@@ -52223,7 +52274,7 @@
    "testharness"
   ],
   "selection/extend-40-expected.txt": [
-   "4a0755f5c0d8af70327206382bb8c9ec99232e51",
+   "5c8577e59cd3604d78a2ba025c7bc4a880741c28",
    "support"
   ],
   "selection/extend-40.html": [
@@ -52267,7 +52318,7 @@
    "testharness"
   ],
   "selection/selectAllChildren-expected.txt": [
-   "1c0847ea872435a156964497a533eca4d1dad076",
+   "1bc19f352fbb4f5b32f6ad639a733577edfa7e2f",
    "support"
   ],
   "selection/selectAllChildren.html": [
@@ -52275,7 +52326,7 @@
    "testharness"
   ],
   "selection/setBaseAndExtent-expected.txt": [
-   "dacbe98c0b6760d76739a5c90b7403ffe0bf7652",
+   "7ee93ebe35799eb020254fe2cfb623ba361ac0e6",
    "support"
   ],
   "selection/setBaseAndExtent.html": [
@@ -52742,6 +52793,22 @@
    "9be9d969099e27be5edc15f6014ac2f06f81674c",
    "testharness"
   ],
+  "service-workers/service-worker/foreign-fetch-basics.https.html": [
+   "bdeacac856c837e86ae2870b465de63885c09169",
+   "testharness"
+  ],
+  "service-workers/service-worker/foreign-fetch-cors.https.html": [
+   "7a89ae20f4beafcdb7feba80f1a789f76cf0df93",
+   "testharness"
+  ],
+  "service-workers/service-worker/foreign-fetch-event.https.html": [
+   "8fbf910205f175a457846100deb34a01c02b00ab",
+   "testharness"
+  ],
+  "service-workers/service-worker/foreign-fetch-workers.https.html": [
+   "7d1ae10966dc452c0dd7c5e400eb88367733b03e",
+   "testharness"
+  ],
   "service-workers/service-worker/getregistration.https.html": [
    "989c30567eb1dd650dc7e2bf807e18961c991087",
    "testharness"
@@ -53027,7 +53094,7 @@
    "support"
   ],
   "service-workers/service-worker/resources/fetch-access-control.py": [
-   "fb2235ce343b51e958f73f7fc8d7ab7dbcc8f71e",
+   "e612c0f7457c8d15ff7d0e2515d8e967a8bb81b5",
    "support"
   ],
   "service-workers/service-worker/resources/fetch-canvas-tainting-iframe.html": [
@@ -53154,12 +53221,40 @@
    "a557b92d3119f43bbbe10d46effc240d7f11c784",
    "support"
   ],
+  "service-workers/service-worker/resources/foreign-fetch-cors-worker.js": [
+   "bf9c10deec71cfedece0e2308cc611e1572ed91d",
+   "support"
+  ],
+  "service-workers/service-worker/resources/foreign-fetch-event-worker.js": [
+   "7e9998ebcf657391c041d2904c06048214602ac2",
+   "support"
+  ],
+  "service-workers/service-worker/resources/foreign-fetch-helper-iframe.html": [
+   "42af5ea03adf25de9d5237a75e913ac726d72c3b",
+   "support"
+  ],
+  "service-workers/service-worker/resources/foreign-fetch-helper-script.js": [
+   "4ec922814bbf72fe0bf65baa6c8457633dda4834",
+   "support"
+  ],
+  "service-workers/service-worker/resources/foreign-fetch-helper-worker.js": [
+   "6b1493c253a8d7808358f3a3da35dd665c5c25db",
+   "support"
+  ],
+  "service-workers/service-worker/resources/foreign-fetch-helpers.js": [
+   "06dd6cb0bc4bac15f2f7c62d7ee4952d7a0f487e",
+   "support"
+  ],
+  "service-workers/service-worker/resources/foreign-fetch-worker.js": [
+   "1464189c2e0ab1344227c69363aef9d44df98848",
+   "support"
+  ],
   "service-workers/service-worker/resources/frame-for-getregistrations.html": [
    "c5f88c11333ff1faba5d57812a36553d174ab711",
    "support"
   ],
   "service-workers/service-worker/resources/get-host-info.sub.js": [
-   "b9310fbd533b9382c3413bbcf2d49f778d4737dd",
+   "1f9283d0305ea68589fd1a1b9ad9ab3a53b99595",
    "support"
   ],
   "service-workers/service-worker/resources/indexeddb-worker.js": [
@@ -53170,6 +53265,10 @@
    "b6949fcd3d82a99595356448fce6ac830366200e",
    "support"
   ],
+  "service-workers/service-worker/resources/install-worker-helper.html": [
+   "02b60da0017cf05e3452ee1ca8dfd8b8e327e707",
+   "support"
+  ],
   "service-workers/service-worker/resources/interfaces-worker.sub.js": [
    "67190b30c485fe743de1515fe5c593aad584fcb3",
    "support"
@@ -53342,6 +53441,10 @@
    "856419e5aa34cb3654ce7baf2908781347fe2de7",
    "support"
   ],
+  "service-workers/service-worker/resources/reply-to-message.html": [
+   "7fb39d9609893a0fbcada161c92dc3df40721f90",
+   "support"
+  ],
   "service-workers/service-worker/resources/request-end-to-end-worker.js": [
    "90e12e47594d86ca558d755880c80c1fba257a87",
    "support"
@@ -56835,7 +56938,7 @@
    "testharness"
   ],
   "workers/WorkerGlobalScope_importScripts_NosniffErr.htm": [
-   "fc4957ca4ea20d0bce364d19bb0b7001e9a60142",
+   "c67d281e78f9672e5f25fdde6b978e0fb7bd806e",
    "testharness"
   ],
   "workers/WorkerGlobalScope_setInterval.htm": [
@@ -56947,7 +57050,7 @@
    "testharness"
   ],
   "workers/Worker_NosniffErr.htm": [
-   "93694174588914798b9462334f40a289daa4d879",
+   "d5fc247d31c39b62a833f41d477dfd77734bdede",
    "testharness"
   ],
   "workers/Worker_basic.htm": [
@@ -57727,7 +57830,7 @@
    "support"
   ],
   "workers/support/ImportScriptsNosniffErr.js": [
-   "4c31ea9c0553deeb2b89ddcf9a7008625474d324",
+   "7075f0f5d8e5dc82859d8b86b9dd64c4e207c475",
    "support"
   ],
   "workers/support/Timer.js": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference-expected.txt
index 7b60f184..d5ec5f2c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/image-maps/image-map-processing-model/hash-name-reference-expected.txt
@@ -4,21 +4,21 @@
 PASS HTML (standards) IMG usemap="no-hash-id" 
 PASS HTML (standards) OBJECT usemap="no-hash-id" 
 PASS HTML (standards) IMG usemap="#hash-name" 
-FAIL HTML (standards) OBJECT usemap="#hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-na... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-na... but got Element node <object data="/images/threecolors.png" usemap="#hash-name...
 FAIL HTML (standards) IMG usemap="#hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-id... but got Element node <img src="/images/threecolors.png" usemap="#hash-id"></img>
-FAIL HTML (standards) OBJECT usemap="#hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-id... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-id... but got Element node <object data="/images/threecolors.png" usemap="#hash-id">...
 PASS HTML (standards) IMG usemap="#non-map-with-this-name" 
-FAIL HTML (standards) OBJECT usemap="#non-map-with-this-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#non-map-with-this-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <object data="/images/threecolors.png" usemap="#non-map-w...
 FAIL HTML (standards) IMG usemap="#non-map-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <img src="/images/threecolors.png" usemap="#non-map-with-...
-FAIL HTML (standards) OBJECT usemap="#non-map-with-this-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#non-map-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <object data="/images/threecolors.png" usemap="#non-map-w...
 PASS HTML (standards) IMG usemap="#two-maps-with-this-name" 
-FAIL HTML (standards) OBJECT usemap="#two-maps-with-this-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#two-maps-with-this-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 FAIL HTML (standards) IMG usemap="#two-maps-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <img src="/images/threecolors.png" usemap="#two-maps-with...
-FAIL HTML (standards) OBJECT usemap="#two-maps-with-this-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#two-maps-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 PASS HTML (standards) IMG usemap="#two-maps-with-this-name-or-id" 
-FAIL HTML (standards) OBJECT usemap="#two-maps-with-this-name-or-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#two-maps-with-this-name-or-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 FAIL HTML (standards) IMG usemap="#two-maps-with-this-id-or-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map...
-FAIL HTML (standards) OBJECT usemap="#two-maps-with-this-id-or-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#two-maps-with-this-id-or-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 FAIL HTML (standards) IMG usemap="hash-last#" assert_equals: expected Element node <img src="/images/threecolors.png" usemap="hash-last#"></... but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
 PASS HTML (standards) OBJECT usemap="hash-last#" 
 FAIL HTML (standards) IMG usemap="" assert_equals: expected Element node <img src="/images/threecolors.png" usemap=""></img> but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
@@ -26,30 +26,31 @@
 FAIL HTML (standards) IMG usemap="#" assert_equals: expected Element node <img src="/images/threecolors.png" usemap="#"></img> but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
 PASS HTML (standards) OBJECT usemap="#" 
 PASS HTML (standards) IMG usemap="# " 
-FAIL HTML (standards) OBJECT usemap="# " assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="# " assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# "></object>
 FAIL HTML (standards) IMG usemap="#\n" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-LF... but got Element node <img src="/images/threecolors.png" usemap="#
 "></img>
-FAIL HTML (standards) OBJECT usemap="#\n" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-LF... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#\n" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-LF... but got Element node <object data="/images/threecolors.png" usemap="#
+"></object>
 PASS HTML (standards) IMG usemap="#percent-escape-name-%41" 
 PASS HTML (standards) OBJECT usemap="#percent-escape-name-%41" 
 PASS HTML (standards) IMG usemap="#percent-escape-id-%41" 
 PASS HTML (standards) OBJECT usemap="#percent-escape-id-%41" 
 PASS HTML (standards) IMG usemap="#percent-escape-name-%42" 
-FAIL HTML (standards) OBJECT usemap="#percent-escape-name-%42" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#percent-escape-name-%42" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got Element node <object data="/images/threecolors.png" usemap="#percent-e...
 FAIL HTML (standards) IMG usemap="#percent-escape-id-%42" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got Element node <img src="/images/threecolors.png" usemap="#percent-escap...
-FAIL HTML (standards) OBJECT usemap="#percent-escape-id-%42" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="#percent-escape-id-%42" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got Element node <object data="/images/threecolors.png" usemap="#percent-e...
 PASS HTML (standards) IMG usemap="# hash-space-name" 
-FAIL HTML (standards) OBJECT usemap="# hash-space-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="# hash-space-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# hash-spa...
 FAIL HTML (standards) IMG usemap="# hash-space-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <img src="/images/threecolors.png" usemap="# hash-space-i...
-FAIL HTML (standards) OBJECT usemap="# hash-space-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="# hash-space-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# hash-spa...
 PASS HTML (standards) IMG usemap=" #space-before-hash-name" 
-FAIL HTML (standards) OBJECT usemap=" #space-before-hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap=" #space-before-hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got Element node <object data="/images/threecolors.png" usemap=" #space-be...
 FAIL HTML (standards) IMG usemap=" #space-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got Element node <img src="/images/threecolors.png" usemap=" #space-before...
-FAIL HTML (standards) OBJECT usemap=" #space-before-hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap=" #space-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got Element node <object data="/images/threecolors.png" usemap=" #space-be...
 PASS HTML (standards) IMG usemap="http://example.org/#garbage-before-hash-name" 
-FAIL HTML (standards) OBJECT usemap="http://example.org/#garbage-before-hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="http://example.org/#garbage-before-hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got Element node <object data="/images/threecolors.png" usemap="http://exa...
 FAIL HTML (standards) IMG usemap="http://example.org/#garbage-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got Element node <img src="/images/threecolors.png" usemap="http://example...
-FAIL HTML (standards) OBJECT usemap="http://example.org/#garbage-before-hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (standards) OBJECT usemap="http://example.org/#garbage-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got Element node <object data="/images/threecolors.png" usemap="http://exa...
 PASS HTML (standards) IMG usemap="#no-such-map" 
 PASS HTML (standards) OBJECT usemap="#no-such-map" 
 PASS HTML (standards) IMG usemap="#different-CASE-name" 
@@ -61,21 +62,21 @@
 PASS HTML (quirks) IMG usemap="no-hash-id" 
 PASS HTML (quirks) OBJECT usemap="no-hash-id" 
 PASS HTML (quirks) IMG usemap="#hash-name" 
-FAIL HTML (quirks) OBJECT usemap="#hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-na... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-na... but got Element node <object data="/images/threecolors.png" usemap="#hash-name...
 FAIL HTML (quirks) IMG usemap="#hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-id... but got Element node <img src="/images/threecolors.png" usemap="#hash-id"></img>
-FAIL HTML (quirks) OBJECT usemap="#hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-id... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-id... but got Element node <object data="/images/threecolors.png" usemap="#hash-id">...
 PASS HTML (quirks) IMG usemap="#non-map-with-this-name" 
-FAIL HTML (quirks) OBJECT usemap="#non-map-with-this-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#non-map-with-this-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <object data="/images/threecolors.png" usemap="#non-map-w...
 FAIL HTML (quirks) IMG usemap="#non-map-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <img src="/images/threecolors.png" usemap="#non-map-with-...
-FAIL HTML (quirks) OBJECT usemap="#non-map-with-this-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#non-map-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <object data="/images/threecolors.png" usemap="#non-map-w...
 PASS HTML (quirks) IMG usemap="#two-maps-with-this-name" 
-FAIL HTML (quirks) OBJECT usemap="#two-maps-with-this-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#two-maps-with-this-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 FAIL HTML (quirks) IMG usemap="#two-maps-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <img src="/images/threecolors.png" usemap="#two-maps-with...
-FAIL HTML (quirks) OBJECT usemap="#two-maps-with-this-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#two-maps-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 PASS HTML (quirks) IMG usemap="#two-maps-with-this-name-or-id" 
-FAIL HTML (quirks) OBJECT usemap="#two-maps-with-this-name-or-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#two-maps-with-this-name-or-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 FAIL HTML (quirks) IMG usemap="#two-maps-with-this-id-or-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map...
-FAIL HTML (quirks) OBJECT usemap="#two-maps-with-this-id-or-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#two-maps-with-this-id-or-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 FAIL HTML (quirks) IMG usemap="hash-last#" assert_equals: expected Element node <img src="/images/threecolors.png" usemap="hash-last#"></... but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
 PASS HTML (quirks) OBJECT usemap="hash-last#" 
 FAIL HTML (quirks) IMG usemap="" assert_equals: expected Element node <img src="/images/threecolors.png" usemap=""></img> but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
@@ -83,30 +84,31 @@
 FAIL HTML (quirks) IMG usemap="#" assert_equals: expected Element node <img src="/images/threecolors.png" usemap="#"></img> but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
 PASS HTML (quirks) OBJECT usemap="#" 
 PASS HTML (quirks) IMG usemap="# " 
-FAIL HTML (quirks) OBJECT usemap="# " assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="# " assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# "></object>
 FAIL HTML (quirks) IMG usemap="#\n" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-LF... but got Element node <img src="/images/threecolors.png" usemap="#
 "></img>
-FAIL HTML (quirks) OBJECT usemap="#\n" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-LF... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#\n" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-LF... but got Element node <object data="/images/threecolors.png" usemap="#
+"></object>
 PASS HTML (quirks) IMG usemap="#percent-escape-name-%41" 
 PASS HTML (quirks) OBJECT usemap="#percent-escape-name-%41" 
 PASS HTML (quirks) IMG usemap="#percent-escape-id-%41" 
 PASS HTML (quirks) OBJECT usemap="#percent-escape-id-%41" 
 PASS HTML (quirks) IMG usemap="#percent-escape-name-%42" 
-FAIL HTML (quirks) OBJECT usemap="#percent-escape-name-%42" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#percent-escape-name-%42" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got Element node <object data="/images/threecolors.png" usemap="#percent-e...
 FAIL HTML (quirks) IMG usemap="#percent-escape-id-%42" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got Element node <img src="/images/threecolors.png" usemap="#percent-escap...
-FAIL HTML (quirks) OBJECT usemap="#percent-escape-id-%42" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="#percent-escape-id-%42" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got Element node <object data="/images/threecolors.png" usemap="#percent-e...
 PASS HTML (quirks) IMG usemap="# hash-space-name" 
-FAIL HTML (quirks) OBJECT usemap="# hash-space-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="# hash-space-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# hash-spa...
 FAIL HTML (quirks) IMG usemap="# hash-space-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <img src="/images/threecolors.png" usemap="# hash-space-i...
-FAIL HTML (quirks) OBJECT usemap="# hash-space-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="# hash-space-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# hash-spa...
 PASS HTML (quirks) IMG usemap=" #space-before-hash-name" 
-FAIL HTML (quirks) OBJECT usemap=" #space-before-hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap=" #space-before-hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got Element node <object data="/images/threecolors.png" usemap=" #space-be...
 FAIL HTML (quirks) IMG usemap=" #space-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got Element node <img src="/images/threecolors.png" usemap=" #space-before...
-FAIL HTML (quirks) OBJECT usemap=" #space-before-hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap=" #space-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got Element node <object data="/images/threecolors.png" usemap=" #space-be...
 PASS HTML (quirks) IMG usemap="http://example.org/#garbage-before-hash-name" 
-FAIL HTML (quirks) OBJECT usemap="http://example.org/#garbage-before-hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="http://example.org/#garbage-before-hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got Element node <object data="/images/threecolors.png" usemap="http://exa...
 FAIL HTML (quirks) IMG usemap="http://example.org/#garbage-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got Element node <img src="/images/threecolors.png" usemap="http://example...
-FAIL HTML (quirks) OBJECT usemap="http://example.org/#garbage-before-hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got (function) function "[object HTMLObjectElement]"
+FAIL HTML (quirks) OBJECT usemap="http://example.org/#garbage-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got Element node <object data="/images/threecolors.png" usemap="http://exa...
 PASS HTML (quirks) IMG usemap="#no-such-map" 
 PASS HTML (quirks) OBJECT usemap="#no-such-map" 
 PASS HTML (quirks) IMG usemap="#different-CASE-name" 
@@ -118,21 +120,21 @@
 FAIL XHTML img usemap="no-hash-id" assert_equals: expected Element node <img src="/images/threecolors.png" usemap="no-hash-id"></... but got Element node <area shape="rect" coords="0,0,99,50" href="#area-no-hash...
 PASS XHTML object usemap="no-hash-id" 
 PASS XHTML img usemap="#hash-name" 
-FAIL XHTML object usemap="#hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-na... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-na... but got Element node <object data="/images/threecolors.png" usemap="#hash-name...
 PASS XHTML img usemap="#hash-id" 
-FAIL XHTML object usemap="#hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-id... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-id... but got Element node <object data="/images/threecolors.png" usemap="#hash-id">...
 PASS XHTML img usemap="#non-map-with-this-name" 
-FAIL XHTML object usemap="#non-map-with-this-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#non-map-with-this-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <object data="/images/threecolors.png" usemap="#non-map-w...
 FAIL XHTML img usemap="#non-map-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <img src="/images/threecolors.png" usemap="#non-map-with-...
-FAIL XHTML object usemap="#non-map-with-this-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#non-map-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-non-map... but got Element node <object data="/images/threecolors.png" usemap="#non-map-w...
 PASS XHTML img usemap="#two-maps-with-this-name" 
-FAIL XHTML object usemap="#two-maps-with-this-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#two-maps-with-this-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 PASS XHTML img usemap="#two-maps-with-this-id" 
-FAIL XHTML object usemap="#two-maps-with-this-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#two-maps-with-this-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 PASS XHTML img usemap="#two-maps-with-this-name-or-id" 
-FAIL XHTML object usemap="#two-maps-with-this-name-or-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#two-maps-with-this-name-or-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 PASS XHTML img usemap="#two-maps-with-this-id-or-name" 
-FAIL XHTML object usemap="#two-maps-with-this-id-or-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#two-maps-with-this-id-or-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-two-map... but got Element node <object data="/images/threecolors.png" usemap="#two-maps-...
 FAIL XHTML img usemap="hash-last#" assert_equals: expected Element node <img src="/images/threecolors.png" usemap="hash-last#"></... but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
 PASS XHTML object usemap="hash-last#" 
 FAIL XHTML img usemap="" assert_equals: expected Element node <img src="/images/threecolors.png" usemap=""></img> but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
@@ -140,29 +142,30 @@
 FAIL XHTML img usemap="#" assert_equals: expected Element node <img src="/images/threecolors.png" usemap="#"></img> but got Element node <area shape="rect" coords="0,0,99,50" href="#area-empty-u...
 PASS XHTML object usemap="#" 
 PASS XHTML img usemap="# " 
-FAIL XHTML object usemap="# " assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="# " assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# "></object>
 PASS XHTML img usemap="#\n" 
-FAIL XHTML object usemap="#\n" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-LF... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#\n" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-LF... but got Element node <object data="/images/threecolors.png" usemap="#
+"></object>
 PASS XHTML img usemap="#percent-escape-name-%41" 
 PASS XHTML object usemap="#percent-escape-name-%41" 
 PASS XHTML img usemap="#percent-escape-id-%41" 
 PASS XHTML object usemap="#percent-escape-id-%41" 
 PASS XHTML img usemap="#percent-escape-name-%42" 
-FAIL XHTML object usemap="#percent-escape-name-%42" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#percent-escape-name-%42" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got Element node <object data="/images/threecolors.png" usemap="#percent-e...
 PASS XHTML img usemap="#percent-escape-id-%42" 
-FAIL XHTML object usemap="#percent-escape-id-%42" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="#percent-escape-id-%42" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-percent... but got Element node <object data="/images/threecolors.png" usemap="#percent-e...
 PASS XHTML img usemap="# hash-space-name" 
-FAIL XHTML object usemap="# hash-space-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="# hash-space-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# hash-spa...
 PASS XHTML img usemap="# hash-space-id" 
-FAIL XHTML object usemap="# hash-space-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="# hash-space-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-hash-sp... but got Element node <object data="/images/threecolors.png" usemap="# hash-spa...
 PASS XHTML img usemap=" #space-before-hash-name" 
-FAIL XHTML object usemap=" #space-before-hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap=" #space-before-hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got Element node <object data="/images/threecolors.png" usemap=" #space-be...
 PASS XHTML img usemap=" #space-before-hash-id" 
-FAIL XHTML object usemap=" #space-before-hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap=" #space-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-space-b... but got Element node <object data="/images/threecolors.png" usemap=" #space-be...
 PASS XHTML img usemap="http://example.org/#garbage-before-hash-name" 
-FAIL XHTML object usemap="http://example.org/#garbage-before-hash-name" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="http://example.org/#garbage-before-hash-name" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got Element node <object data="/images/threecolors.png" usemap="http://exa...
 PASS XHTML img usemap="http://example.org/#garbage-before-hash-id" 
-FAIL XHTML object usemap="http://example.org/#garbage-before-hash-id" assert_equals: expected (object) Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got (function) function "[object HTMLObjectElement]"
+FAIL XHTML object usemap="http://example.org/#garbage-before-hash-id" assert_equals: expected Element node <area shape="rect" coords="0,0,99,50" href="#area-garbage... but got Element node <object data="/images/threecolors.png" usemap="http://exa...
 PASS XHTML img usemap="#no-such-map" 
 PASS XHTML object usemap="#no-such-map" 
 PASS XHTML img usemap="#different-CASE-name" 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/historical-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/historical-expected.txt
deleted file mode 100644
index d294903b..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-embed-element/historical-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL embed legacycaller should not be supported assert_equals: typeof expected "object" but got "function"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/historical-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/historical-expected.txt
deleted file mode 100644
index 7c5ac5a..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/historical-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL object legacycaller should not be supported assert_equals: typeof expected "object" but got "function"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/usemap-casing-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/usemap-casing-expected.txt
index 6ee967cb..3fa02e6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/usemap-casing-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/the-object-element/usemap-casing-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-FAIL Object with usemap of #sanityCheck should match the area with map named sanityCheck assert_equals: expected (object) Element node <area shape="rect" coords="0,0,300,300"></area> but got (function) function "[object HTMLObjectElement]"
+FAIL Object with usemap of #sanityCheck should match the area with map named sanityCheck assert_equals: expected Element node <area shape="rect" coords="0,0,300,300"></area> but got Element node <object data="/images/threecolors.png" usemap="#sanityChe...
 PASS Object with usemap of #sImPlE should not match any of the areas 
 PASS Object with usemap of #paSSfield-killroyß should not match any of the areas 
 PASS Object with usemap of #глупый should not match any of the areas 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerout_pen-manual.html b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerout_pen-manual.html
index 3973948..5e38952 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerout_pen-manual.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/pointerevents/pointerevent_pointerout_pen-manual.html
@@ -28,7 +28,7 @@
             function run() {
                 var target0 = document.getElementById("target0");
 
-                // When a pen stylus leaves the hover range detectable by the digitizer the pointerout event must be dispatched. 
+                // When a pen stylus leaves the hover range detectable by the digitizer the pointerout event must be dispatched.
                 // TA: 7.2
                 on_event(target0, "pointerout", function (event) {
                     detected_pointertypes[event.pointerType] = true;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/collapse-00-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/collapse-00-expected.txt
index d75a699..d1de6a9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/collapse-00-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/collapse-00-expected.txt
@@ -1204,25 +1204,26 @@
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 6 [paras[0].firstChild, 10] 
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 7 [paras[0].firstChild, 65535] 
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 8 [paras[1].firstChild, -1] 
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 9 [paras[1].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 10 [paras[1].firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 11 [paras[1].firstChild, 2] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 12 [paras[1].firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 13 [paras[1].firstChild, 9] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 9 [paras[1].firstChild, 0] 
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 10 [paras[1].firstChild, 1] assert_equals: focusOffset must equal the offset we collapse()d to expected 1 but got 0
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 11 [paras[1].firstChild, 2] assert_equals: focusOffset must equal the offset we collapse()d to expected 2 but got 0
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 12 [paras[1].firstChild, 8] assert_equals: focusOffset must equal the offset we collapse()d to expected 8 but got 0
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 13 [paras[1].firstChild, 9] assert_equals: focusOffset must equal the offset we collapse()d to expected 9 but got 0
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 14 [paras[1].firstChild, 10] 
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 24 [document.documentElement, -1] 
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1239,10 +1240,14 @@
 "
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1251,12 +1256,16 @@
 "
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 37 [paras[0], 2] 
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 38 [paras[1], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+</p> but got Text node "Ijklmnop
+"
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+</p> but got Text node "Ijklmnop
+"
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 40 [paras[1], 2] 
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1273,35 +1282,62 @@
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 53 [comment, 96] 
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 59 [xmlDoc, -1] 
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 62 [xmlDoc, 5] 
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 83 [doctype, 0] 
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1318,25 +1354,26 @@
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 6 [paras[0].firstChild, 10] 
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 7 [paras[0].firstChild, 65535] 
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 8 [paras[1].firstChild, -1] 
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 9 [paras[1].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 10 [paras[1].firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 11 [paras[1].firstChild, 2] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 12 [paras[1].firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 13 [paras[1].firstChild, 9] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 9 [paras[1].firstChild, 0] assert_equals: focusOffset must equal the offset we collapse()d to expected 0 but got 1
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 10 [paras[1].firstChild, 1] assert_equals: focusOffset and anchorOffset must be equal after collapse() expected 0 but got 1
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 11 [paras[1].firstChild, 2] assert_equals: focusOffset must equal the offset we collapse()d to expected 2 but got 1
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 12 [paras[1].firstChild, 8] assert_equals: focusOffset must equal the offset we collapse()d to expected 8 but got 1
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 13 [paras[1].firstChild, 9] assert_equals: focusOffset must equal the offset we collapse()d to expected 9 but got 1
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 14 [paras[1].firstChild, 10] 
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 24 [document.documentElement, -1] 
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1353,10 +1390,14 @@
 "
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1365,12 +1406,16 @@
 "
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 37 [paras[0], 2] 
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 38 [paras[1], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+</p> but got Text node "Ijklmnop
+"
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+</p> but got Text node "Ijklmnop
+"
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 40 [paras[1], 2] 
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1387,35 +1432,62 @@
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 53 [comment, 96] 
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 59 [xmlDoc, -1] 
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 62 [xmlDoc, 5] 
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 83 [doctype, 0] 
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1432,25 +1504,26 @@
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 6 [paras[0].firstChild, 10] 
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 7 [paras[0].firstChild, 65535] 
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 8 [paras[1].firstChild, -1] 
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 9 [paras[1].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 10 [paras[1].firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 11 [paras[1].firstChild, 2] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 12 [paras[1].firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 13 [paras[1].firstChild, 9] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 9 [paras[1].firstChild, 0] assert_equals: focusOffset must equal the offset we collapse()d to expected 0 but got 8
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 10 [paras[1].firstChild, 1] assert_equals: focusOffset must equal the offset we collapse()d to expected 1 but got 8
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 11 [paras[1].firstChild, 2] assert_equals: focusOffset must equal the offset we collapse()d to expected 2 but got 8
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 12 [paras[1].firstChild, 8] assert_equals: focusOffset and anchorOffset must be equal after collapse() expected 2 but got 8
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 13 [paras[1].firstChild, 9] assert_equals: focusOffset must equal the offset we collapse()d to expected 9 but got 8
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 14 [paras[1].firstChild, 10] 
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 24 [document.documentElement, -1] 
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1467,10 +1540,14 @@
 "
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1479,12 +1556,16 @@
 "
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 37 [paras[0], 2] 
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 38 [paras[1], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+</p> but got Text node "Ijklmnop
+"
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+</p> but got Text node "Ijklmnop
+"
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 40 [paras[1], 2] 
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1501,35 +1582,62 @@
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 53 [comment, 96] 
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 59 [xmlDoc, -1] 
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 62 [xmlDoc, 5] 
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 83 [doctype, 0] 
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1546,25 +1654,26 @@
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 6 [paras[0].firstChild, 10] 
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 7 [paras[0].firstChild, 65535] 
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 8 [paras[1].firstChild, -1] 
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 9 [paras[1].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 10 [paras[1].firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 11 [paras[1].firstChild, 2] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 12 [paras[1].firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 13 [paras[1].firstChild, 9] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 9 [paras[1].firstChild, 0] assert_equals: focusOffset must equal the offset we collapse()d to expected 0 but got 9
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 10 [paras[1].firstChild, 1] assert_equals: focusOffset must equal the offset we collapse()d to expected 1 but got 9
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 11 [paras[1].firstChild, 2] assert_equals: focusOffset must equal the offset we collapse()d to expected 2 but got 9
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 12 [paras[1].firstChild, 8] assert_equals: focusOffset must equal the offset we collapse()d to expected 8 but got 9
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 13 [paras[1].firstChild, 9] assert_equals: focusOffset and anchorOffset must be equal after collapse() expected 2 but got 9
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 14 [paras[1].firstChild, 10] 
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 24 [document.documentElement, -1] 
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1581,10 +1690,14 @@
 "
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1593,12 +1706,16 @@
 "
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 37 [paras[0], 2] 
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 38 [paras[1], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+</p> but got Text node "Ijklmnop
+"
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+</p> but got Text node "Ijklmnop
+"
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 40 [paras[1], 2] 
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1615,35 +1732,62 @@
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 53 [comment, 96] 
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 59 [xmlDoc, -1] 
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 62 [xmlDoc, 5] 
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 83 [doctype, 0] 
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -2336,7 +2480,9 @@
 PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], point 86 [foreignDoctype, 0] 
 PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], point 87 [xmlDoctype, 0] 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 0 [paras[0].firstChild, -1] 
-PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 1 [paras[0].firstChild, 0] 
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 1 [paras[0].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Äb̈c̈d̈ëf̈g̈ḧ
+" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must equal the offset we collapse()d to expected 1 but got 2
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 3 [paras[0].firstChild, 2] 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 4 [paras[0].firstChild, 8] 
@@ -2356,46 +2502,42 @@
 " but got Text node "Qrstuvwx"
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 14 [paras[1].firstChild, 10] 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 24 [document.documentElement, -1] 
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 26 [document.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 25 [document.documentElement, 0] assert_equals: focusOffset must equal the offset we collapse()d to expected 0 but got 1
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 26 [document.documentElement, 1] assert_equals: focusOffset and anchorOffset must be equal after collapse() expected 0 but got 1
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 27 [document.documentElement, 2] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
 <me... but got Text node "Qrstuvwx"
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 28 [document.documentElement, 7] 
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 29 [document.head, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title>Selection.collapse() tests</title>
-<meta nam... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<meta nam... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 36 [paras[0], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2405,82 +2547,82 @@
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 40 [paras[1], 2] 
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p><p id="b" s... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 44 [testDiv, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 45 [document, -1] 
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 48 [document, 2] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Qrstuvwx"
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 49 [document, 3] 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 50 [comment, -1] 
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 53 [comment, 96] 
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 59 [xmlDoc, -1] 
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 62 [xmlDoc, 5] 
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], point 83 [doctype, 0] 
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -2509,13 +2651,19 @@
 " but got Text node "Qrstuvwx"
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 14 [paras[1].firstChild, 10] 
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 24 [document.documentElement, -1] 
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -2532,10 +2680,14 @@
 "
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2548,8 +2700,10 @@
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 40 [paras[1], 2] 
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2566,35 +2720,62 @@
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 53 [comment, 96] 
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 59 [xmlDoc, -1] 
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 62 [xmlDoc, 5] 
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], point 83 [doctype, 0] 
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -2623,13 +2804,19 @@
 " but got Text node "Qrstuvwx"
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 14 [paras[1].firstChild, 10] 
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 24 [document.documentElement, -1] 
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -2646,10 +2833,14 @@
 "
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2662,8 +2853,10 @@
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 40 [paras[1], 2] 
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2680,35 +2873,62 @@
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 53 [comment, 96] 
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 59 [xmlDoc, -1] 
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 62 [xmlDoc, 5] 
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
+FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection.collapse() tests</title>
+<me...
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 83 [doctype, 0] 
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -2717,7 +2937,9 @@
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 86 [foreignDoctype, 0] 
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], point 87 [xmlDoctype, 0] 
 PASS Range 18 [document.head, 1, document.head, 1], point 0 [paras[0].firstChild, -1] 
-PASS Range 18 [document.head, 1, document.head, 1], point 1 [paras[0].firstChild, 0] 
+FAIL Range 18 [document.head, 1, document.head, 1], point 1 [paras[0].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Äb̈c̈d̈ëf̈g̈ḧ
+" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 FAIL Range 18 [document.head, 1, document.head, 1], point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must equal the offset we collapse()d to expected 1 but got 2
 PASS Range 18 [document.head, 1, document.head, 1], point 3 [paras[0].firstChild, 2] 
 PASS Range 18 [document.head, 1, document.head, 1], point 4 [paras[0].firstChild, 8] 
@@ -2737,46 +2959,44 @@
 " but got Text node "Qrstuvwx"
 PASS Range 18 [document.head, 1, document.head, 1], point 14 [paras[1].firstChild, 10] 
 PASS Range 18 [document.head, 1, document.head, 1], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 18 [document.head, 1, document.head, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 18 [document.head, 1, document.head, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 PASS Range 18 [document.head, 1, document.head, 1], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 18 [document.head, 1, document.head, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 18 [document.head, 1, document.head, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 PASS Range 18 [document.head, 1, document.head, 1], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 18 [document.head, 1, document.head, 1], point 24 [document.documentElement, -1] 
 FAIL Range 18 [document.head, 1, document.head, 1], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<me... but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 FAIL Range 18 [document.head, 1, document.head, 1], point 26 [document.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<me... but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 FAIL Range 18 [document.head, 1, document.head, 1], point 27 [document.documentElement, 2] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
 <me... but got Text node "Qrstuvwx"
 PASS Range 18 [document.head, 1, document.head, 1], point 28 [document.documentElement, 7] 
-FAIL Range 18 [document.head, 1, document.head, 1], point 29 [document.head, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title>Selection.collapse() tests</title>
-<meta nam... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 18 [document.head, 1, document.head, 1], point 29 [document.head, 1] 
 FAIL Range 18 [document.head, 1, document.head, 1], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 18 [document.head, 1, document.head, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 18 [document.head, 1, document.head, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 FAIL Range 18 [document.head, 1, document.head, 1], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 FAIL Range 18 [document.head, 1, document.head, 1], point 36 [paras[0], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2786,82 +3006,82 @@
 FAIL Range 18 [document.head, 1, document.head, 1], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 18 [document.head, 1, document.head, 1], point 40 [paras[1], 2] 
-FAIL Range 18 [document.head, 1, document.head, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 18 [document.head, 1, document.head, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 FAIL Range 18 [document.head, 1, document.head, 1], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p><p id="b" s... but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 FAIL Range 18 [document.head, 1, document.head, 1], point 44 [testDiv, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS Range 18 [document.head, 1, document.head, 1], point 45 [document, -1] 
-FAIL Range 18 [document.head, 1, document.head, 1], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 18 [document.head, 1, document.head, 1], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 FAIL Range 18 [document.head, 1, document.head, 1], point 48 [document, 2] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Qrstuvwx"
 PASS Range 18 [document.head, 1, document.head, 1], point 49 [document, 3] 
 PASS Range 18 [document.head, 1, document.head, 1], point 50 [comment, -1] 
 FAIL Range 18 [document.head, 1, document.head, 1], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 18 [document.head, 1, document.head, 1], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 18 [document.head, 1, document.head, 1], point 53 [comment, 96] 
-FAIL Range 18 [document.head, 1, document.head, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 18 [document.head, 1, document.head, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 PASS Range 18 [document.head, 1, document.head, 1], point 59 [xmlDoc, -1] 
-FAIL Range 18 [document.head, 1, document.head, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 18 [document.head, 1, document.head, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 PASS Range 18 [document.head, 1, document.head, 1], point 62 [xmlDoc, 5] 
-FAIL Range 18 [document.head, 1, document.head, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 18 [document.head, 1, document.head, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
+FAIL Range 18 [document.head, 1, document.head, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <head><title>Selection.collapse() tests</title>
+<meta nam...
 PASS Range 18 [document.head, 1, document.head, 1], point 83 [doctype, 0] 
 FAIL Range 18 [document.head, 1, document.head, 1], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -2890,13 +3110,19 @@
 " but got Text node "Qrstuvwx"
 PASS Range 19 [document.body, 0, document.body, 1], point 14 [paras[1].firstChild, 10] 
 PASS Range 19 [document.body, 0, document.body, 1], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 19 [document.body, 0, document.body, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 19 [document.body, 0, document.body, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 19 [document.body, 0, document.body, 1], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 19 [document.body, 0, document.body, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 19 [document.body, 0, document.body, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 19 [document.body, 0, document.body, 1], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 19 [document.body, 0, document.body, 1], point 24 [document.documentElement, -1] 
 FAIL Range 19 [document.body, 0, document.body, 1], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -2913,10 +3139,14 @@
 "
 FAIL Range 19 [document.body, 0, document.body, 1], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 19 [document.body, 0, document.body, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 19 [document.body, 0, document.body, 1], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2929,8 +3159,10 @@
 FAIL Range 19 [document.body, 0, document.body, 1], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 19 [document.body, 0, document.body, 1], point 40 [paras[1], 2] 
-FAIL Range 19 [document.body, 0, document.body, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 19 [document.body, 0, document.body, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 19 [document.body, 0, document.body, 1], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2947,35 +3179,62 @@
 FAIL Range 19 [document.body, 0, document.body, 1], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 19 [document.body, 0, document.body, 1], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 19 [document.body, 0, document.body, 1], point 53 [comment, 96] 
-FAIL Range 19 [document.body, 0, document.body, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 19 [document.body, 0, document.body, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 19 [document.body, 0, document.body, 1], point 59 [xmlDoc, -1] 
-FAIL Range 19 [document.body, 0, document.body, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 19 [document.body, 0, document.body, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 19 [document.body, 0, document.body, 1], point 62 [xmlDoc, 5] 
-FAIL Range 19 [document.body, 0, document.body, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 19 [document.body, 0, document.body, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 19 [document.body, 0, document.body, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 19 [document.body, 0, document.body, 1], point 83 [doctype, 0] 
 FAIL Range 19 [document.body, 0, document.body, 1], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -3326,7 +3585,9 @@
 PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], point 86 [foreignDoctype, 0] 
 PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], point 87 [xmlDoctype, 0] 
 PASS Range 23 [paras[0], 0, paras[0], 0], point 0 [paras[0].firstChild, -1] 
-PASS Range 23 [paras[0], 0, paras[0], 0], point 1 [paras[0].firstChild, 0] 
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 1 [paras[0].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Äb̈c̈d̈ëf̈g̈ḧ
+" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must equal the offset we collapse()d to expected 1 but got 2
 PASS Range 23 [paras[0], 0, paras[0], 0], point 3 [paras[0].firstChild, 2] 
 PASS Range 23 [paras[0], 0, paras[0], 0], point 4 [paras[0].firstChild, 8] 
@@ -3346,46 +3607,44 @@
 " but got Text node "Qrstuvwx"
 PASS Range 23 [paras[0], 0, paras[0], 0], point 14 [paras[1].firstChild, 10] 
 PASS Range 23 [paras[0], 0, paras[0], 0], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 23 [paras[0], 0, paras[0], 0], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 23 [paras[0], 0, paras[0], 0], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 23 [paras[0], 0, paras[0], 0], point 24 [document.documentElement, -1] 
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<me... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 26 [document.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<me... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 27 [document.documentElement, 2] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
 <me... but got Text node "Qrstuvwx"
 PASS Range 23 [paras[0], 0, paras[0], 0], point 28 [document.documentElement, 7] 
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 29 [document.head, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title>Selection.collapse() tests</title>
-<meta nam... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<meta nam... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+PASS Range 23 [paras[0], 0, paras[0], 0], point 35 [paras[0], 0] 
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 36 [paras[0], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3395,82 +3654,82 @@
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 23 [paras[0], 0, paras[0], 0], point 40 [paras[1], 2] 
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p><p id="b" s... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 44 [testDiv, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS Range 23 [paras[0], 0, paras[0], 0], point 45 [document, -1] 
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 48 [document, 2] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Qrstuvwx"
 PASS Range 23 [paras[0], 0, paras[0], 0], point 49 [document, 3] 
 PASS Range 23 [paras[0], 0, paras[0], 0], point 50 [comment, -1] 
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 23 [paras[0], 0, paras[0], 0], point 53 [comment, 96] 
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 23 [paras[0], 0, paras[0], 0], point 59 [xmlDoc, -1] 
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 23 [paras[0], 0, paras[0], 0], point 62 [xmlDoc, 5] 
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 23 [paras[0], 0, paras[0], 0], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 23 [paras[0], 0, paras[0], 0], point 83 [doctype, 0] 
 FAIL Range 23 [paras[0], 0, paras[0], 0], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -3499,19 +3758,19 @@
 " but got Text node "Qrstuvwx"
 PASS Range 24 [paras[0], 0, paras[0], 1], point 14 [paras[1].firstChild, 10] 
 PASS Range 24 [paras[0], 0, paras[0], 1], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 24 [paras[0], 0, paras[0], 1], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 24 [paras[0], 0, paras[0], 1], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 24 [paras[0], 0, paras[0], 1], point 24 [document.documentElement, -1] 
 FAIL Range 24 [paras[0], 0, paras[0], 1], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -3528,14 +3787,14 @@
 "
 FAIL Range 24 [paras[0], 0, paras[0], 1], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 24 [paras[0], 0, paras[0], 1], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3548,10 +3807,10 @@
 FAIL Range 24 [paras[0], 0, paras[0], 1], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 24 [paras[0], 0, paras[0], 1], point 40 [paras[1], 2] 
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL Range 24 [paras[0], 0, paras[0], 1], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3568,62 +3827,62 @@
 FAIL Range 24 [paras[0], 0, paras[0], 1], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 24 [paras[0], 0, paras[0], 1], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 24 [paras[0], 0, paras[0], 1], point 53 [comment, 96] 
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 24 [paras[0], 0, paras[0], 1], point 59 [xmlDoc, -1] 
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 24 [paras[0], 0, paras[0], 1], point 62 [xmlDoc, 5] 
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL Range 24 [paras[0], 0, paras[0], 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS Range 24 [paras[0], 0, paras[0], 1], point 83 [doctype, 0] 
 FAIL Range 24 [paras[0], 0, paras[0], 1], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -3880,13 +4139,19 @@
 " but got Text node "Qrstuvwx"
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 14 [paras[1].firstChild, 10] 
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 24 [document.documentElement, -1] 
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -3903,10 +4168,14 @@
 "
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3919,8 +4188,10 @@
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 40 [paras[1], 2] 
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3937,35 +4208,62 @@
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 53 [comment, 96] 
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 59 [xmlDoc, -1] 
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 62 [xmlDoc, 5] 
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 83 [doctype, 0] 
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -3994,13 +4292,19 @@
 " but got Text node "Qrstuvwx"
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 14 [paras[1].firstChild, 10] 
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 24 [document.documentElement, -1] 
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -4017,10 +4321,14 @@
 "
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4033,8 +4341,10 @@
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 40 [paras[1], 2] 
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4051,35 +4361,62 @@
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 53 [comment, 96] 
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 59 [xmlDoc, -1] 
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Ijklmnop
+"
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 62 [xmlDoc, 5] 
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="c">Qrstuvwx</p>
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="c">Qrstuvwx</p>
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 83 [doctype, 0] 
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -4108,13 +4445,13 @@
 " but got Text node "Qrstuvwx"
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 14 [paras[1].firstChild, 10] 
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 24 [document.documentElement, -1] 
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -4131,10 +4468,10 @@
 "
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4147,8 +4484,8 @@
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 40 [paras[1], 2] 
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4165,35 +4502,35 @@
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 53 [comment, 96] 
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 59 [xmlDoc, -1] 
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 62 [xmlDoc, 5] 
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
+FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], point 83 [doctype, 0] 
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/collapse-30-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/collapse-30-expected.txt
index 88d3865a..1a96929 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/collapse-30-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/collapse-30-expected.txt
@@ -554,13 +554,13 @@
 " but got Text node "Qrstuvwx"
 PASS Range 31 [testDiv, 2, paras[4], 1], point 14 [paras[1].firstChild, 10] 
 PASS Range 31 [testDiv, 2, paras[4], 1], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <p id="e" style="display:none">Ghijklmn</p>
 PASS Range 31 [testDiv, 2, paras[4], 1], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <p id="e" style="display:none">Ghijklmn</p>
 PASS Range 31 [testDiv, 2, paras[4], 1], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 31 [testDiv, 2, paras[4], 1], point 24 [document.documentElement, -1] 
 FAIL Range 31 [testDiv, 2, paras[4], 1], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -577,10 +577,10 @@
 "
 FAIL Range 31 [testDiv, 2, paras[4], 1], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="e" style="display:none">Ghijklmn</p>
 FAIL Range 31 [testDiv, 2, paras[4], 1], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -593,8 +593,8 @@
 FAIL Range 31 [testDiv, 2, paras[4], 1], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 31 [testDiv, 2, paras[4], 1], point 40 [paras[1], 2] 
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <p id="e" style="display:none">Ghijklmn</p>
 FAIL Range 31 [testDiv, 2, paras[4], 1], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -611,35 +611,35 @@
 FAIL Range 31 [testDiv, 2, paras[4], 1], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 31 [testDiv, 2, paras[4], 1], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 31 [testDiv, 2, paras[4], 1], point 53 [comment, 96] 
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="e" style="display:none">Ghijklmn</p>
 PASS Range 31 [testDiv, 2, paras[4], 1], point 59 [xmlDoc, -1] 
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <p id="e" style="display:none">Ghijklmn</p>
 PASS Range 31 [testDiv, 2, paras[4], 1], point 62 [xmlDoc, 5] 
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="e" style="display:none">Ghijklmn</p>
+FAIL Range 31 [testDiv, 2, paras[4], 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <p id="e" style="display:none">Ghijklmn</p>
 PASS Range 31 [testDiv, 2, paras[4], 1], point 83 [doctype, 0] 
 FAIL Range 31 [testDiv, 2, paras[4], 1], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -762,7 +762,9 @@
 PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], point 86 [foreignDoctype, 0] 
 PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], point 87 [xmlDoctype, 0] 
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 0 [paras[0].firstChild, -1] 
-PASS Range 33 [document.documentElement, 1, document.body, 0], point 1 [paras[0].firstChild, 0] 
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 1 [paras[0].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Äb̈c̈d̈ëf̈g̈ḧ
+" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must equal the offset we collapse()d to expected 1 but got 2
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 3 [paras[0].firstChild, 2] 
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 4 [paras[0].firstChild, 8] 
@@ -782,46 +784,46 @@
 " but got Text node "Qrstuvwx"
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 14 [paras[1].firstChild, 10] 
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 24 [document.documentElement, -1] 
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<me... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 26 [document.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<me... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 27 [document.documentElement, 2] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
 <me... but got Text node "Qrstuvwx"
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 28 [document.documentElement, 7] 
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 29 [document.head, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title>Selection.collapse() tests</title>
-<meta nam... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<meta nam... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 36 [paras[0], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -831,82 +833,82 @@
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 40 [paras[1], 2] 
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p><p id="b" s... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 44 [testDiv, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 45 [document, -1] 
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 48 [document, 2] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Qrstuvwx"
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 49 [document, 3] 
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 50 [comment, -1] 
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 53 [comment, 96] 
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 59 [xmlDoc, -1] 
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 62 [xmlDoc, 5] 
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 PASS Range 33 [document.documentElement, 1, document.body, 0], point 83 [doctype, 0] 
 FAIL Range 33 [document.documentElement, 1, document.body, 0], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1029,7 +1031,8 @@
 PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], point 86 [foreignDoctype, 0] 
 PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], point 87 [xmlDoctype, 0] 
 PASS Range 35 [document, 0, document, 1], point 0 [paras[0].firstChild, -1] 
-PASS Range 35 [document, 0, document, 1], point 1 [paras[0].firstChild, 0] 
+FAIL Range 35 [document, 0, document, 1], point 1 [paras[0].firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Äb̈c̈d̈ëf̈g̈ḧ
+" but got Document node with 2 children
 FAIL Range 35 [document, 0, document, 1], point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must equal the offset we collapse()d to expected 1 but got 2
 PASS Range 35 [document, 0, document, 1], point 3 [paras[0].firstChild, 2] 
 PASS Range 35 [document, 0, document, 1], point 4 [paras[0].firstChild, 8] 
@@ -1049,46 +1052,32 @@
 " but got Text node "Qrstuvwx"
 PASS Range 35 [document, 0, document, 1], point 14 [paras[1].firstChild, 10] 
 PASS Range 35 [document, 0, document, 1], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 35 [document, 0, document, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
 PASS Range 35 [document, 0, document, 1], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 35 [document, 0, document, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
 PASS Range 35 [document, 0, document, 1], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 35 [document, 0, document, 1], point 24 [document.documentElement, -1] 
 FAIL Range 35 [document, 0, document, 1], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<me... but got Document node with 2 children
 FAIL Range 35 [document, 0, document, 1], point 26 [document.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<me... but got Document node with 2 children
 FAIL Range 35 [document, 0, document, 1], point 27 [document.documentElement, 2] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
 <me... but got Text node "Qrstuvwx"
 PASS Range 35 [document, 0, document, 1], point 28 [document.documentElement, 7] 
 FAIL Range 35 [document, 0, document, 1], point 29 [document.head, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title>Selection.collapse() tests</title>
-<meta nam... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+<meta nam... but got Document node with 2 children
 FAIL Range 35 [document, 0, document, 1], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 35 [document, 0, document, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Document node with 2 children
 FAIL Range 35 [document, 0, document, 1], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p> but got Document node with 2 children
 FAIL Range 35 [document, 0, document, 1], point 36 [paras[0], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1098,82 +1087,50 @@
 FAIL Range 35 [document, 0, document, 1], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 35 [document, 0, document, 1], point 40 [paras[1], 2] 
-FAIL Range 35 [document, 0, document, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL Range 35 [document, 0, document, 1], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+</p><p id="b" s... but got Document node with 2 children
 FAIL Range 35 [document, 0, document, 1], point 44 [testDiv, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS Range 35 [document, 0, document, 1], point 45 [document, -1] 
-FAIL Range 35 [document, 0, document, 1], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1], point 46 [document, 0] assert_equals: focusOffset must equal the offset we collapse()d to expected 0 but got 1
+FAIL Range 35 [document, 0, document, 1], point 47 [document, 1] assert_equals: focusOffset and anchorOffset must be equal after collapse() expected 0 but got 1
 FAIL Range 35 [document, 0, document, 1], point 48 [document, 2] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Qrstuvwx"
 PASS Range 35 [document, 0, document, 1], point 49 [document, 3] 
 PASS Range 35 [document, 0, document, 1], point 50 [comment, -1] 
 FAIL Range 35 [document, 0, document, 1], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 35 [document, 0, document, 1], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 35 [document, 0, document, 1], point 53 [comment, 96] 
-FAIL Range 35 [document, 0, document, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 PASS Range 35 [document, 0, document, 1], point 59 [xmlDoc, -1] 
-FAIL Range 35 [document, 0, document, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Document node with 2 children
 PASS Range 35 [document, 0, document, 1], point 62 [xmlDoc, 5] 
-FAIL Range 35 [document, 0, document, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
+FAIL Range 35 [document, 0, document, 1], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
 PASS Range 35 [document, 0, document, 1], point 83 [doctype, 0] 
 FAIL Range 35 [document, 0, document, 1], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1202,13 +1159,13 @@
 " but got Text node "Qrstuvwx"
 PASS Range 36 [document, 0, document, 2], point 14 [paras[1].firstChild, 10] 
 PASS Range 36 [document, 0, document, 2], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 36 [document, 0, document, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 36 [document, 0, document, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
 PASS Range 36 [document, 0, document, 2], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 36 [document, 0, document, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 36 [document, 0, document, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
 PASS Range 36 [document, 0, document, 2], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 36 [document, 0, document, 2], point 24 [document.documentElement, -1] 
 FAIL Range 36 [document, 0, document, 2], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1225,10 +1182,10 @@
 "
 FAIL Range 36 [document, 0, document, 2], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 36 [document, 0, document, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Document node with 2 children
 FAIL Range 36 [document, 0, document, 2], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1241,8 +1198,8 @@
 FAIL Range 36 [document, 0, document, 2], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 36 [document, 0, document, 2], point 40 [paras[1], 2] 
-FAIL Range 36 [document, 0, document, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 36 [document, 0, document, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL Range 36 [document, 0, document, 2], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1259,35 +1216,35 @@
 FAIL Range 36 [document, 0, document, 2], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 36 [document, 0, document, 2], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 36 [document, 0, document, 2], point 53 [comment, 96] 
-FAIL Range 36 [document, 0, document, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 36 [document, 0, document, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 PASS Range 36 [document, 0, document, 2], point 59 [xmlDoc, -1] 
-FAIL Range 36 [document, 0, document, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 36 [document, 0, document, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Document node with 2 children
 PASS Range 36 [document, 0, document, 2], point 62 [xmlDoc, 5] 
-FAIL Range 36 [document, 0, document, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 36 [document, 0, document, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
+FAIL Range 36 [document, 0, document, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
 PASS Range 36 [document, 0, document, 2], point 83 [doctype, 0] 
 FAIL Range 36 [document, 0, document, 2], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1316,13 +1273,13 @@
 " but got Text node "Qrstuvwx"
 PASS Range 37 [document, 1, document, 2], point 14 [paras[1].firstChild, 10] 
 PASS Range 37 [document, 1, document, 2], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 37 [document, 1, document, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 37 [document, 1, document, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Document node with 2 children
 PASS Range 37 [document, 1, document, 2], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 37 [document, 1, document, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 37 [document, 1, document, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Document node with 2 children
 PASS Range 37 [document, 1, document, 2], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 37 [document, 1, document, 2], point 24 [document.documentElement, -1] 
 FAIL Range 37 [document, 1, document, 2], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1339,10 +1296,10 @@
 "
 FAIL Range 37 [document, 1, document, 2], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 37 [document, 1, document, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Document node with 2 children
 FAIL Range 37 [document, 1, document, 2], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1355,8 +1312,8 @@
 FAIL Range 37 [document, 1, document, 2], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 37 [document, 1, document, 2], point 40 [paras[1], 2] 
-FAIL Range 37 [document, 1, document, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 37 [document, 1, document, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL Range 37 [document, 1, document, 2], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1373,35 +1330,35 @@
 FAIL Range 37 [document, 1, document, 2], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 37 [document, 1, document, 2], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 37 [document, 1, document, 2], point 53 [comment, 96] 
-FAIL Range 37 [document, 1, document, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 37 [document, 1, document, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 PASS Range 37 [document, 1, document, 2], point 59 [xmlDoc, -1] 
-FAIL Range 37 [document, 1, document, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 37 [document, 1, document, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Document node with 2 children
 PASS Range 37 [document, 1, document, 2], point 62 [xmlDoc, 5] 
-FAIL Range 37 [document, 1, document, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 37 [document, 1, document, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
+FAIL Range 37 [document, 1, document, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Document node with 2 children
 PASS Range 37 [document, 1, document, 2], point 83 [doctype, 0] 
 FAIL Range 37 [document, 1, document, 2], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1430,13 +1387,13 @@
 " but got Text node "Qrstuvwx"
 PASS Range 38 [testDiv, 0, comment, 5], point 14 [paras[1].firstChild, 10] 
 PASS Range 38 [testDiv, 0, comment, 5], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 38 [testDiv, 0, comment, 5], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 38 [testDiv, 0, comment, 5], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
 PASS Range 38 [testDiv, 0, comment, 5], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 38 [testDiv, 0, comment, 5], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 38 [testDiv, 0, comment, 5], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
 PASS Range 38 [testDiv, 0, comment, 5], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 38 [testDiv, 0, comment, 5], point 24 [document.documentElement, -1] 
 FAIL Range 38 [testDiv, 0, comment, 5], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1453,10 +1410,10 @@
 "
 FAIL Range 38 [testDiv, 0, comment, 5], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 38 [testDiv, 0, comment, 5], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Comment node <!--Alphabet soup?-->
 FAIL Range 38 [testDiv, 0, comment, 5], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1469,8 +1426,8 @@
 FAIL Range 38 [testDiv, 0, comment, 5], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 38 [testDiv, 0, comment, 5], point 40 [paras[1], 2] 
-FAIL Range 38 [testDiv, 0, comment, 5], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 38 [testDiv, 0, comment, 5], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Comment node <!--Alphabet soup?-->
 FAIL Range 38 [testDiv, 0, comment, 5], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1487,35 +1444,35 @@
 FAIL Range 38 [testDiv, 0, comment, 5], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 38 [testDiv, 0, comment, 5], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 38 [testDiv, 0, comment, 5], point 53 [comment, 96] 
-FAIL Range 38 [testDiv, 0, comment, 5], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 38 [testDiv, 0, comment, 5], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Comment node <!--Alphabet soup?-->
 PASS Range 38 [testDiv, 0, comment, 5], point 59 [xmlDoc, -1] 
-FAIL Range 38 [testDiv, 0, comment, 5], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 38 [testDiv, 0, comment, 5], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Comment node <!--Alphabet soup?-->
 PASS Range 38 [testDiv, 0, comment, 5], point 62 [xmlDoc, 5] 
-FAIL Range 38 [testDiv, 0, comment, 5], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 38 [testDiv, 0, comment, 5], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 38 [testDiv, 0, comment, 5], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
 PASS Range 38 [testDiv, 0, comment, 5], point 83 [doctype, 0] 
 FAIL Range 38 [testDiv, 0, comment, 5], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1544,13 +1501,13 @@
 " but got Text node "Qrstuvwx"
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 14 [paras[1].firstChild, 10] 
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 24 [document.documentElement, -1] 
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1567,10 +1524,10 @@
 "
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Comment node <!--Alphabet soup?-->
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1583,8 +1540,8 @@
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 40 [paras[1], 2] 
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Comment node <!--Alphabet soup?-->
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1601,35 +1558,35 @@
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 53 [comment, 96] 
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Comment node <!--Alphabet soup?-->
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 59 [xmlDoc, -1] 
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Comment node <!--Alphabet soup?-->
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 62 [xmlDoc, 5] 
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], point 83 [doctype, 0] 
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
@@ -1658,13 +1615,13 @@
 " but got Text node "Qrstuvwx"
 PASS Range 40 [paras[3], 1, comment, 8], point 14 [paras[1].firstChild, 10] 
 PASS Range 40 [paras[3], 1, comment, 8], point 15 [paras[1].firstChild, 65535] 
-FAIL Range 40 [paras[3], 1, comment, 8], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8], point 16 [detachedPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 17 [detachedPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 18 [detachedPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Opqrstuv" but got Comment node <!--Alphabet soup?-->
 PASS Range 40 [paras[3], 1, comment, 8], point 19 [detachedPara1.firstChild, 9] 
-FAIL Range 40 [paras[3], 1, comment, 8], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8], point 20 [foreignPara1.firstChild, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 21 [foreignPara1.firstChild, 1] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 22 [foreignPara1.firstChild, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Efghijkl" but got Comment node <!--Alphabet soup?-->
 PASS Range 40 [paras[3], 1, comment, 8], point 23 [foreignPara1.firstChild, 9] 
 PASS Range 40 [paras[3], 1, comment, 8], point 24 [document.documentElement, -1] 
 FAIL Range 40 [paras[3], 1, comment, 8], point 25 [document.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
@@ -1674,17 +1631,17 @@
 <me... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 40 [paras[3], 1, comment, 8], point 27 [document.documentElement, 2] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title>Selection.collapse() tests</title>
-<me... but got Text node "Qrstuvwx"
+<me... but got Comment node <!--Alphabet soup?-->
 PASS Range 40 [paras[3], 1, comment, 8], point 28 [document.documentElement, 7] 
 FAIL Range 40 [paras[3], 1, comment, 8], point 29 [document.head, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title>Selection.collapse() tests</title>
 <meta nam... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 40 [paras[3], 1, comment, 8], point 30 [document.body, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+</p><p id... but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 31 [foreignDoc.documentElement, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 32 [foreignDoc.documentElement, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 33 [foreignDoc.head, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <head><title></title></head> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 34 [foreignDoc.body, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Comment node <!--Alphabet soup?-->
 FAIL Range 40 [paras[3], 1, comment, 8], point 35 [paras[0], 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -1697,53 +1654,53 @@
 FAIL Range 40 [paras[3], 1, comment, 8], point 39 [paras[1], 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p id="b" style="display:none">Ijklmnop
 </p> but got Text node "Qrstuvwx"
 PASS Range 40 [paras[3], 1, comment, 8], point 40 [paras[1], 2] 
-FAIL Range 40 [paras[3], 1, comment, 8], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8], point 41 [detachedPara1, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 42 [detachedPara1, 1] assert_equals: focusNode must equal the node we collapse()d to expected Element node <p>Opqrstuv</p> but got Comment node <!--Alphabet soup?-->
 FAIL Range 40 [paras[3], 1, comment, 8], point 43 [testDiv, 0] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 40 [paras[3], 1, comment, 8], point 44 [testDiv, 3] assert_equals: focusNode must equal the node we collapse()d to expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+</p><p id="b" s... but got Comment node <!--Alphabet soup?-->
 PASS Range 40 [paras[3], 1, comment, 8], point 45 [document, -1] 
 FAIL Range 40 [paras[3], 1, comment, 8], point 46 [document, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 40 [paras[3], 1, comment, 8], point 47 [document, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 40 [paras[3], 1, comment, 8], point 48 [document, 2] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8], point 48 [document, 2] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 2 children but got Comment node <!--Alphabet soup?-->
 PASS Range 40 [paras[3], 1, comment, 8], point 49 [document, 3] 
 PASS Range 40 [paras[3], 1, comment, 8], point 50 [comment, -1] 
-FAIL Range 40 [paras[3], 1, comment, 8], point 51 [comment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 52 [comment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8], point 51 [comment, 0] assert_equals: focusOffset must equal the offset we collapse()d to expected 0 but got 8
+FAIL Range 40 [paras[3], 1, comment, 8], point 52 [comment, 4] assert_equals: focusOffset must equal the offset we collapse()d to expected 4 but got 8
 PASS Range 40 [paras[3], 1, comment, 8], point 53 [comment, 96] 
-FAIL Range 40 [paras[3], 1, comment, 8], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8], point 54 [foreignDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 55 [foreignDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 3 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 56 [foreignComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 57 [foreignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 58 [foreignTextNode, 36] assert_equals: focusNode must equal the node we collapse()d to expected Text node "I admit that I harbor doubts about whether we really need..." but got Comment node <!--Alphabet soup?-->
 PASS Range 40 [paras[3], 1, comment, 8], point 59 [xmlDoc, -1] 
-FAIL Range 40 [paras[3], 1, comment, 8], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8], point 60 [xmlDoc, 0] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 61 [xmlDoc, 1] assert_equals: focusNode must equal the node we collapse()d to expected Document node with 4 children but got Comment node <!--Alphabet soup?-->
 PASS Range 40 [paras[3], 1, comment, 8], point 62 [xmlDoc, 5] 
-FAIL Range 40 [paras[3], 1, comment, 8], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8], point 63 [xmlComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 64 [xmlComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 65 [processingInstruction, 0] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 66 [processingInstruction, 5] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 67 [processingInstruction, 9] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 68 [detachedTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 69 [detachedTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Uvwxyzab" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 70 [detachedForeignTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 71 [detachedForeignTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Cdefghij" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 72 [detachedXmlTextNode, 0] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 73 [detachedXmlTextNode, 8] assert_equals: focusNode must equal the node we collapse()d to expected Text node "Klmnopqr" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 74 [detachedProcessingInstruction, 12] assert_equals: focusNode must equal the node we collapse()d to expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 75 [detachedComment, 3] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 76 [detachedComment, 5] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--Stuvwxyz--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 77 [detachedForeignComment, 0] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 78 [detachedForeignComment, 4] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--אריה יהודה--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 79 [detachedXmlComment, 2] assert_equals: focusNode must equal the node we collapse()d to expected Comment node <!--בן חיים אליעזר--> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 80 [docfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 81 [foreignDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8], point 82 [xmlDocfrag, 0] assert_equals: focusNode must equal the node we collapse()d to expected DocumentFragment node with 0 children but got Comment node <!--Alphabet soup?-->
 PASS Range 40 [paras[3], 1, comment, 8], point 83 [doctype, 0] 
 FAIL Range 40 [paras[3], 1, comment, 8], point 84 [doctype, -17] assert_throws: Must throw INVALID_NODE_TYPE_ERR when collapse()ing if the node is a DocumentType function "function () {
             selection.collapse(point[0], point[1]);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/collapseToStartEnd-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/collapseToStartEnd-expected.txt
index 016d82e0..7e9f76d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/collapseToStartEnd-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/collapseToStartEnd-expected.txt
@@ -27,22 +27,14 @@
 PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8] collapseToEnd() 
 PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9] collapseToStart() 
 FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9] collapseToEnd() assert_equals: focusOffset must equal the original end offset expected 9 but got 10
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] collapseToStart() assert_equals: focusNode must equal the original start node expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] collapseToEnd() assert_equals: focusNode must equal the original end node expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] collapseToStart() assert_equals: focusNode must equal the original start node expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] collapseToEnd() assert_equals: focusNode must equal the original end node expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] collapseToStart() assert_equals: focusNode must equal the original start node expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] collapseToEnd() assert_equals: focusNode must equal the original end node expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] collapseToStart() assert_equals: focusNode must equal the original start node expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] collapseToEnd() assert_equals: focusNode must equal the original end node expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] collapseToStart() 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] collapseToEnd() 
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] collapseToStart() assert_equals: focusOffset must equal the original start offset expected 0 but got 1
+FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] collapseToEnd() assert_equals: anchorOffset must equal the original end offset expected 1 but got 0
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] collapseToStart() assert_equals: focusOffset must equal the original start offset expected 2 but got 8
+FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] collapseToEnd() assert_equals: anchorOffset must equal the original end offset expected 8 but got 2
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] collapseToStart() assert_equals: focusOffset must equal the original start offset expected 2 but got 9
+FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] collapseToEnd() assert_equals: anchorOffset must equal the original end offset expected 9 but got 2
 FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] collapseToStart() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] collapseToEnd() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] collapseToStart() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
@@ -55,20 +47,16 @@
 FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] collapseToEnd() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] collapseToStart() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] collapseToEnd() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <html><head><title>Selection.collapseTo(Start|End)() test... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1] collapseToEnd() assert_equals: focusNode must equal the original end node expected Element node <html><head><title>Selection.collapseTo(Start|End)() test... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1] collapseToStart() assert_equals: focusOffset must equal the original start offset expected 0 but got 1
+FAIL Range 15 [document.documentElement, 0, document.documentElement, 1] collapseToEnd() assert_equals: anchorOffset must equal the original end offset expected 1 but got 0
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <html><head><title>Selection.collapseTo(Start|End)() test... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2] collapseToEnd() assert_equals: focusNode must equal the original end node expected Element node <html><head><title>Selection.collapseTo(Start|End)() test... but got Text node "Qrstuvwx"
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <html><head><title>Selection.collapseTo(Start|End)() test... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2] collapseToEnd() assert_equals: focusNode must equal the original end node expected Element node <html><head><title>Selection.collapseTo(Start|End)() test... but got Text node "Qrstuvwx"
-FAIL Range 18 [document.head, 1, document.head, 1] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <head><title>Selection.collapseTo(Start|End)() tests</tit... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1] collapseToEnd() assert_equals: focusNode must equal the original end node expected Element node <head><title>Selection.collapseTo(Start|End)() tests</tit... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 18 [document.head, 1, document.head, 1] collapseToStart() 
+PASS Range 18 [document.head, 1, document.head, 1] collapseToEnd() 
 FAIL Range 19 [document.body, 0, document.body, 1] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -80,12 +68,8 @@
 FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1] collapseToEnd() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0] collapseToStart() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0] collapseToEnd() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
-FAIL Range 23 [paras[0], 0, paras[0], 0] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0] collapseToEnd() assert_equals: focusNode must equal the original end node expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 23 [paras[0], 0, paras[0], 0] collapseToStart() 
+PASS Range 23 [paras[0], 0, paras[0], 0] collapseToEnd() 
 FAIL Range 24 [paras[0], 0, paras[0], 1] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -114,17 +98,14 @@
 FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS Range 32 [testDiv, 1, paras[2].firstChild, 5] collapseToEnd() 
-FAIL Range 33 [document.documentElement, 1, document.body, 0] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <html><head><title>Selection.collapseTo(Start|End)() test... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0] collapseToEnd() assert_equals: focusNode must equal the original end node expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 33 [document.documentElement, 1, document.body, 0] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <html><head><title>Selection.collapseTo(Start|End)() test... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
+FAIL Range 33 [document.documentElement, 1, document.body, 0] collapseToEnd() assert_equals: anchorNode must equal the original end node expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Element node <html><head><title>Selection.collapseTo(Start|End)() test...
 FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0] collapseToStart() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0] collapseToEnd() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
-FAIL Range 35 [document, 0, document, 1] collapseToStart() assert_equals: focusNode must equal the original start node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1] collapseToEnd() assert_equals: focusNode must equal the original end node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL Range 35 [document, 0, document, 1] collapseToStart() assert_equals: focusOffset must equal the original start offset expected 0 but got 1
+FAIL Range 35 [document, 0, document, 1] collapseToEnd() assert_equals: anchorOffset must equal the original end offset expected 1 but got 0
 FAIL Range 36 [document, 0, document, 2] collapseToStart() assert_equals: focusNode must equal the original start node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 36 [document, 0, document, 2] collapseToEnd() assert_equals: focusNode must equal the original end node expected Document node with 2 children but got Text node "Qrstuvwx"
@@ -137,8 +118,8 @@
 FAIL Range 38 [testDiv, 0, comment, 5] collapseToEnd() assert_equals: focusNode must equal the original end node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 PASS Range 39 [paras[2].firstChild, 4, comment, 2] collapseToStart() 
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2] collapseToEnd() assert_equals: focusNode must equal the original end node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8] collapseToEnd() assert_equals: focusNode must equal the original end node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL Range 40 [paras[3], 1, comment, 8] collapseToStart() assert_equals: focusNode must equal the original start node expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Comment node <!--Alphabet soup?-->
+FAIL Range 40 [paras[3], 1, comment, 8] collapseToEnd() assert_equals: anchorNode must equal the original end node expected Comment node <!--Alphabet soup?--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL Range 41 [foreignDoc, 0, foreignDoc, 0] collapseToStart() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 41 [foreignDoc, 0, foreignDoc, 0] collapseToEnd() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
 FAIL Range 42 [foreignDoc, 1, foreignComment, 2] collapseToStart() assert_equals: Sanity check: rangeCount must equal 1 after addRange() expected 1 but got 0
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/extend-00-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/extend-00-expected.txt
index 3ef16885..06a5830 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/extend-00-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/extend-00-expected.txt
@@ -1293,98 +1293,154 @@
 PASS extend() forwards with range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9] and point 87 [xmlDoctype, 0] 
 FAIL extend() backwards with range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9] and point 87 [xmlDoctype, 0] assert_equals: Sanity check: endOffset must be correct expected 9 but got 10
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 0 [paras[0].firstChild, -1] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 7 [paras[0].firstChild, 65535] 
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 8 [paras[1].firstChild, -1] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 14 [paras[1].firstChild, 10] 
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 15 [paras[1].firstChild, 65535] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 19 [detachedPara1.firstChild, 9] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 23 [foreignPara1.firstChild, 9] 
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 24 [document.documentElement, -1] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 28 [document.documentElement, 7] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 37 [paras[0], 2] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 40 [paras[1], 2] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 45 [document, -1] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 49 [document, 3] 
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 50 [comment, -1] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 53 [comment, 96] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 59 [xmlDoc, -1] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Ijklmnop
+"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 62 [xmlDoc, 5] 
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
+FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 PASS extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 83 [doctype, 0] 
 FAIL extend() with range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] and point 84 [doctype, -17] assert_throws: extend() to a doctype must throw InvalidNodeTypeError function "function () {
             selection.extend(node, offset);
@@ -1395,22 +1451,28 @@
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 7 [paras[0].firstChild, 65535] 
@@ -1419,23 +1481,23 @@
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
@@ -1445,25 +1507,31 @@
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 23 [foreignPara1.firstChild, 9] 
@@ -1472,81 +1540,96 @@
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 45 [document, -1] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 49 [document, 3] 
@@ -1555,100 +1638,129 @@
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 50 [comment, -1] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 53 [comment, 96] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] and point 83 [doctype, 0] 
@@ -1671,22 +1783,28 @@
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 7 [paras[0].firstChild, 65535] 
@@ -1695,23 +1813,23 @@
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
@@ -1721,25 +1839,31 @@
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 23 [foreignPara1.firstChild, 9] 
@@ -1748,81 +1872,96 @@
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 45 [document, -1] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 49 [document, 3] 
@@ -1831,100 +1970,129 @@
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 50 [comment, -1] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 53 [comment, 96] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] and point 83 [doctype, 0] 
@@ -1947,22 +2115,28 @@
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 7 [paras[0].firstChild, 65535] 
@@ -1971,23 +2145,23 @@
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
@@ -1997,25 +2171,31 @@
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 23 [foreignPara1.firstChild, 9] 
@@ -2024,81 +2204,96 @@
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 45 [document, -1] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 49 [document, 3] 
@@ -2107,100 +2302,129 @@
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 50 [comment, -1] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Ijklmnop
+" but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 53 [comment, 96] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Ijklmnop
+"
 FAIL extend() backwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
 PASS extend() forwards with range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] and point 83 [doctype, 0] 
@@ -3104,27 +3328,39 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3136,28 +3372,33 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3169,18 +3410,18 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3188,18 +3429,18 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3211,20 +3452,21 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3232,45 +3474,46 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
@@ -3279,13 +3522,15 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3293,24 +3538,25 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3318,17 +3564,21 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3340,11 +3590,15 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3352,28 +3606,28 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3381,13 +3635,13 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3395,103 +3649,103 @@
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 15 [document.documentElement, 0, document.documentElement, 1] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3521,27 +3775,39 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3553,28 +3819,33 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3586,18 +3857,18 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3605,18 +3876,18 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3628,20 +3899,21 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3649,45 +3921,46 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
@@ -3696,13 +3969,15 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3710,24 +3985,25 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3735,17 +4011,21 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3757,11 +4037,15 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3769,28 +4053,28 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3798,13 +4082,13 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3812,103 +4096,103 @@
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 16 [document.documentElement, 0, document.documentElement, 2] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3938,27 +4222,39 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3970,28 +4266,33 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4003,18 +4304,18 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4022,18 +4323,18 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4045,20 +4346,21 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4066,45 +4368,46 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
@@ -4113,13 +4416,15 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4127,24 +4432,25 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4152,17 +4458,21 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4174,11 +4484,15 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4186,28 +4500,28 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4215,13 +4529,13 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4229,103 +4543,103 @@
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 17 [document.documentElement, 1, document.documentElement, 2] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4352,151 +4666,181 @@
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 0 [paras[0].firstChild, -1] 
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 1 [paras[0].firstChild, 0] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 3 [paras[0].firstChild, 2] 
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 4 [paras[0].firstChild, 8] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 6 [paras[0].firstChild, 10] 
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 7 [paras[0].firstChild, 65535] 
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 8 [paras[1].firstChild, -1] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 14 [paras[1].firstChild, 10] 
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 15 [paras[1].firstChild, 65535] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 19 [detachedPara1.firstChild, 9] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 23 [foreignPara1.firstChild, 9] 
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 24 [document.documentElement, -1] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
-PASS extend() with range 18 [document.head, 1, document.head, 1] and point 28 [document.documentElement, 7] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
 <meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+PASS extend() with range 18 [document.head, 1, document.head, 1] and point 7 [paras[0].firstChild, 65535] 
+PASS extend() with range 18 [document.head, 1, document.head, 1] and point 8 [paras[1].firstChild, -1] 
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+PASS extend() with range 18 [document.head, 1, document.head, 1] and point 14 [paras[1].firstChild, 10] 
+PASS extend() with range 18 [document.head, 1, document.head, 1] and point 15 [paras[1].firstChild, 65535] 
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+PASS extend() with range 18 [document.head, 1, document.head, 1] and point 19 [detachedPara1.firstChild, 9] 
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+PASS extend() with range 18 [document.head, 1, document.head, 1] and point 23 [foreignPara1.firstChild, 9] 
+PASS extend() with range 18 [document.head, 1, document.head, 1] and point 24 [document.documentElement, -1] 
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+PASS extend() with range 18 [document.head, 1, document.head, 1] and point 28 [document.documentElement, 7] 
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 37 [paras[0], 2] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 40 [paras[1], 2] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 45 [document, -1] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 49 [document, 3] 
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 50 [comment, -1] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <head><title>Selection extend() tests</title>
+<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 53 [comment, 96] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 59 [xmlDoc, -1] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 62 [xmlDoc, 5] 
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
+FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <head><title>Selection extend() tests</title>
+<meta chars...
 PASS extend() with range 18 [document.head, 1, document.head, 1] and point 83 [doctype, 0] 
 FAIL extend() with range 18 [document.head, 1, document.head, 1] and point 84 [doctype, -17] assert_throws: extend() to a doctype must throw InvalidNodeTypeError function "function () {
             selection.extend(node, offset);
@@ -4508,27 +4852,39 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 19 [document.body, 0, document.body, 1] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 19 [document.body, 0, document.body, 1] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 19 [document.body, 0, document.body, 1] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 19 [document.body, 0, document.body, 1] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4540,28 +4896,33 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4573,18 +4934,18 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4592,18 +4953,18 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4615,20 +4976,21 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4636,45 +4998,46 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
@@ -4683,13 +5046,15 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4697,24 +5062,25 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4722,17 +5088,21 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4744,11 +5114,15 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4756,28 +5130,28 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4785,13 +5159,13 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4799,103 +5173,103 @@
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 19 [document.body, 0, document.body, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id...
 FAIL extend() backwards with range 19 [document.body, 0, document.body, 1] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/extend-20-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/extend-20-expected.txt
index fe113545..3dd637a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/extend-20-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/extend-20-expected.txt
@@ -528,151 +528,181 @@
 FAIL extend() with range 22 [foreignDoc.body, 0, foreignDoc.body, 0] and point 86 [foreignDoctype, 0] assert_equals: Sanity check: rangeCount must be correct expected 1 but got 0
 FAIL extend() with range 22 [foreignDoc.body, 0, foreignDoc.body, 0] and point 87 [xmlDoctype, 0] assert_equals: Sanity check: rangeCount must be correct expected 1 but got 0
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 0 [paras[0].firstChild, -1] 
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 1 [paras[0].firstChild, 0] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 3 [paras[0].firstChild, 2] 
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 4 [paras[0].firstChild, 8] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 6 [paras[0].firstChild, 10] 
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 7 [paras[0].firstChild, 65535] 
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 8 [paras[1].firstChild, -1] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 14 [paras[1].firstChild, 10] 
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 15 [paras[1].firstChild, 65535] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 19 [detachedPara1.firstChild, 9] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 23 [foreignPara1.firstChild, 9] 
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 24 [document.documentElement, -1] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
-PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 28 [document.documentElement, 7] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 7 [paras[0].firstChild, 65535] 
+PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 8 [paras[1].firstChild, -1] 
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 14 [paras[1].firstChild, 10] 
+PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 15 [paras[1].firstChild, 65535] 
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 19 [detachedPara1.firstChild, 9] 
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 23 [foreignPara1.firstChild, 9] 
+PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 24 [document.documentElement, -1] 
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 28 [document.documentElement, 7] 
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 37 [paras[0], 2] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 40 [paras[1], 2] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 45 [document, -1] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 49 [document, 3] 
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 50 [comment, -1] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 53 [comment, 96] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 59 [xmlDoc, -1] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 62 [xmlDoc, 5] 
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
+FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 PASS extend() with range 23 [paras[0], 0, paras[0], 0] and point 83 [doctype, 0] 
 FAIL extend() with range 23 [paras[0], 0, paras[0], 0] and point 84 [doctype, -17] assert_throws: extend() to a doctype must throw InvalidNodeTypeError function "function () {
             selection.extend(node, offset);
@@ -684,27 +714,39 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -716,28 +758,33 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -749,18 +796,18 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -768,18 +815,18 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -791,20 +838,21 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -812,44 +860,45 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
@@ -859,13 +908,15 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -873,24 +924,25 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -898,17 +950,21 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -920,11 +976,15 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -932,28 +992,28 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -961,13 +1021,13 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -975,103 +1035,103 @@
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 24 [paras[0], 0, paras[0], 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 24 [paras[0], 0, paras[0], 1] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2021,36 +2081,31 @@
 " but got Element node <p id="c">Qrstuvwx</p>
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 7 [paras[0].firstChild, 65535] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 7 [paras[0].firstChild, 65535] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 9 [paras[1].firstChild, 0] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 10 [paras[1].firstChild, 1] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 11 [paras[1].firstChild, 2] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 12 [paras[1].firstChild, 8] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 13 [paras[1].firstChild, 9] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 14 [paras[1].firstChild, 10] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 14 [paras[1].firstChild, 10] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
@@ -2080,25 +2135,17 @@
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 23 [foreignPara1.firstChild, 9] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 25 [document.documentElement, 0] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 26 [document.documentElement, 1] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 27 [document.documentElement, 2] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 29 [document.head, 1] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 29 [document.head, 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 30 [document.body, 3] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 30 [document.body, 3] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2112,21 +2159,15 @@
 FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 35 [paras[0], 0] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 35 [paras[0], 0] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 36 [paras[0], 1] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 36 [paras[0], 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 37 [paras[0], 2] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 38 [paras[1], 0] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 38 [paras[1], 0] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 39 [paras[1], 1] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 39 [paras[1], 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 40 [paras[1], 2] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
@@ -2136,30 +2177,25 @@
 FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 43 [testDiv, 0] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 43 [testDiv, 0] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 44 [testDiv, 3] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 44 [testDiv, 3] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 45 [document, -1] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 45 [document, -1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 46 [document, 0] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 46 [document, 0] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 47 [document, 1] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 47 [document, 1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 48 [document, 2] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 48 [document, 2] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 49 [document, 3] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 49 [document, 3] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 50 [comment, -1] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 50 [comment, -1] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 51 [comment, 0] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 51 [comment, 0] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
-FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 52 [comment, 4] assert_equals: anchorOffset must not change if the node passed to extend() has the same root as the original range expected 3 but got 4
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 52 [comment, 4] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
 PASS extend() forwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 53 [comment, 96] 
 FAIL extend() backwards with range 29 [paras[0].firstChild, 3, paras[3], 1] and point 53 [comment, 96] assert_equals: Sanity check: startOffset must be correct expected 3 but got 4
@@ -2264,27 +2300,39 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2296,28 +2344,33 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2329,18 +2382,18 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2348,18 +2401,18 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2371,20 +2424,21 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2392,44 +2446,45 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
@@ -2439,13 +2494,15 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2453,24 +2510,25 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2478,17 +2536,21 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2500,11 +2562,15 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2512,28 +2578,28 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2541,13 +2607,13 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2555,103 +2621,103 @@
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p>
 FAIL extend() backwards with range 30 [paras[0], 0, paras[0].firstChild, 7] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -2680,22 +2746,28 @@
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 7 [paras[0].firstChild, 65535] 
@@ -2704,24 +2776,24 @@
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 14 [paras[1].firstChild, 10] 
@@ -2730,25 +2802,31 @@
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 23 [foreignPara1.firstChild, 9] 
@@ -2757,81 +2835,96 @@
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 45 [document, -1] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 49 [document, 3] 
@@ -2840,100 +2933,129 @@
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 50 [comment, -1] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 53 [comment, 96] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 31 [testDiv, 2, paras[4], 1] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 31 [testDiv, 2, paras[4], 1] and point 83 [doctype, 0] 
@@ -2956,22 +3078,28 @@
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 7 [paras[0].firstChild, 65535] 
@@ -2980,24 +3108,24 @@
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 14 [paras[1].firstChild, 10] 
@@ -3006,25 +3134,31 @@
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 23 [foreignPara1.firstChild, 9] 
@@ -3033,81 +3167,96 @@
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 45 [document, -1] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Text node "Qrstuvwx" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Element node <p id="c">Qrstuvwx</p>
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 49 [document, 3] 
@@ -3116,100 +3265,129 @@
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 50 [comment, -1] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 53 [comment, 96] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Qrstuvwx"
 PASS extend() forwards with range 32 [testDiv, 1, paras[2].firstChild, 5] and point 83 [doctype, 0] 
@@ -3233,27 +3411,39 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3265,28 +3455,33 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3298,18 +3493,18 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3317,18 +3512,18 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3340,20 +3535,21 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3361,45 +3557,46 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
@@ -3408,13 +3605,15 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3422,24 +3621,25 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3447,17 +3647,21 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3469,11 +3673,15 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <html><head><title>Selection extend() tests</title>
+<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3481,28 +3689,28 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3510,13 +3718,13 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3524,103 +3732,103 @@
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 33 [document.documentElement, 1, document.body, 0] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <html><head><title>Selection extend() tests</title>
+<meta...
 FAIL extend() backwards with range 33 [document.documentElement, 1, document.body, 0] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <html><head><title>Selection extend() tests</title>
 <meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -3825,22 +4033,28 @@
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 35 [document, 0, document, 1] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 35 [document, 0, document, 1] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 35 [document, 0, document, 1] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 35 [document, 0, document, 1] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 7 [paras[0].firstChild, 65535] 
@@ -3849,24 +4063,24 @@
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 14 [paras[1].firstChild, 10] 
@@ -3875,31 +4089,25 @@
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 23 [foreignPara1.firstChild, 9] 
@@ -3908,101 +4116,90 @@
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 45 [document, -1] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 49 [document, 3] 
@@ -4011,127 +4208,102 @@
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 50 [comment, -1] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 53 [comment, 96] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 35 [document, 0, document, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 35 [document, 0, document, 1] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 35 [document, 0, document, 1] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 35 [document, 0, document, 1] and point 83 [doctype, 0] 
@@ -4154,22 +4326,28 @@
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 36 [document, 0, document, 2] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 36 [document, 0, document, 2] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 36 [document, 0, document, 2] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 36 [document, 0, document, 2] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 7 [paras[0].firstChild, 65535] 
@@ -4178,24 +4356,24 @@
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 14 [paras[1].firstChild, 10] 
@@ -4204,31 +4382,25 @@
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 23 [foreignPara1.firstChild, 9] 
@@ -4237,101 +4409,90 @@
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 45 [document, -1] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 49 [document, 3] 
@@ -4340,127 +4501,102 @@
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 50 [comment, -1] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 53 [comment, 96] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 36 [document, 0, document, 2] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 36 [document, 0, document, 2] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 36 [document, 0, document, 2] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 36 [document, 0, document, 2] and point 83 [doctype, 0] 
@@ -4483,22 +4619,28 @@
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 37 [document, 1, document, 2] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 37 [document, 1, document, 2] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 37 [document, 1, document, 2] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 37 [document, 1, document, 2] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 7 [paras[0].firstChild, 65535] 
@@ -4507,24 +4649,24 @@
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 14 [paras[1].firstChild, 10] 
@@ -4533,31 +4675,25 @@
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 23 [foreignPara1.firstChild, 9] 
@@ -4566,101 +4702,90 @@
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 45 [document, -1] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 49 [document, 3] 
@@ -4669,127 +4794,102 @@
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 50 [comment, -1] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 53 [comment, 96] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 37 [document, 1, document, 2] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 37 [document, 1, document, 2] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Document node with 2 children
 FAIL extend() backwards with range 37 [document, 1, document, 2] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 PASS extend() forwards with range 37 [document, 1, document, 2] and point 83 [doctype, 0] 
@@ -4813,27 +4913,39 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 38 [testDiv, 0, comment, 5] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 38 [testDiv, 0, comment, 5] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 38 [testDiv, 0, comment, 5] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-PASS extend() forwards with range 38 [testDiv, 0, comment, 5] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4845,28 +4957,33 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4878,18 +4995,18 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4897,18 +5014,18 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4920,20 +5037,21 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -4941,45 +5059,46 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
@@ -4988,13 +5107,15 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Element node <p id="c">Qrstuvwx</p>
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -5002,24 +5123,25 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -5027,17 +5149,21 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -5049,11 +5175,15 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
+"
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -5061,28 +5191,28 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -5090,13 +5220,13 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -5104,103 +5234,103 @@
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 38 [testDiv, 0, comment, 5] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
+</p><p id="b" s...
 FAIL extend() backwards with range 38 [testDiv, 0, comment, 5] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/extend-40-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/extend-40-expected.txt
index 1f91601..b320917 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/extend-40-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/extend-40-expected.txt
@@ -353,193 +353,169 @@
 This is a testharness.js-based test.
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 0 [paras[0].firstChild, -1] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 0 [paras[0].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 1 [paras[0].firstChild, 0] 
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 1 [paras[0].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 1 [paras[0].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 2 [paras[0].firstChild, 1] assert_equals: focusOffset must be the offset passed to extend() expected 1 but got 2
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 2 [paras[0].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 2 [paras[0].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 3 [paras[0].firstChild, 2] 
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 3 [paras[0].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 3 [paras[0].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 4 [paras[0].firstChild, 8] 
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 4 [paras[0].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 4 [paras[0].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 5 [paras[0].firstChild, 9] assert_equals: focusOffset must be the offset passed to extend() expected 9 but got 10
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 5 [paras[0].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 5 [paras[0].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 6 [paras[0].firstChild, 10] 
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 6 [paras[0].firstChild, 10] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 6 [paras[0].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 7 [paras[0].firstChild, 65535] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 7 [paras[0].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 8 [paras[1].firstChild, -1] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 8 [paras[1].firstChild, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 9 [paras[1].firstChild, 0] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 9 [paras[1].firstChild, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 9 [paras[1].firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 10 [paras[1].firstChild, 1] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 10 [paras[1].firstChild, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 10 [paras[1].firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 11 [paras[1].firstChild, 2] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 11 [paras[1].firstChild, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 11 [paras[1].firstChild, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 12 [paras[1].firstChild, 8] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 12 [paras[1].firstChild, 8] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 12 [paras[1].firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 13 [paras[1].firstChild, 9] assert_equals: focusNode must be the node passed to extend() expected Text node "Ijklmnop
-" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 13 [paras[1].firstChild, 9] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 13 [paras[1].firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 14 [paras[1].firstChild, 10] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 14 [paras[1].firstChild, 10] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 15 [paras[1].firstChild, 65535] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 15 [paras[1].firstChild, 65535] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 16 [detachedPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 16 [detachedPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 17 [detachedPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 17 [detachedPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 18 [detachedPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Opqrstuv" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 18 [detachedPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 19 [detachedPara1.firstChild, 9] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 19 [detachedPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 20 [foreignPara1.firstChild, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 20 [foreignPara1.firstChild, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 21 [foreignPara1.firstChild, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 21 [foreignPara1.firstChild, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 22 [foreignPara1.firstChild, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Efghijkl" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 22 [foreignPara1.firstChild, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 23 [foreignPara1.firstChild, 9] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 23 [foreignPara1.firstChild, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 24 [document.documentElement, -1] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 24 [document.documentElement, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 25 [document.documentElement, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 25 [document.documentElement, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 25 [document.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 26 [document.documentElement, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 26 [document.documentElement, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 26 [document.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 27 [document.documentElement, 2] assert_equals: focusNode must be the node passed to extend() expected Element node <html><head><title>Selection extend() tests</title>
-<meta... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 27 [document.documentElement, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 27 [document.documentElement, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 28 [document.documentElement, 7] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 28 [document.documentElement, 7] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 29 [document.head, 1] assert_equals: focusNode must be the node passed to extend() expected Element node <head><title>Selection extend() tests</title>
-<meta chars... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 29 [document.head, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 29 [document.head, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 30 [document.body, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 30 [document.body, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 30 [document.body, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 31 [foreignDoc.documentElement, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 31 [foreignDoc.documentElement, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 32 [foreignDoc.documentElement, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 32 [foreignDoc.documentElement, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 33 [foreignDoc.head, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <head><title></title></head> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 33 [foreignDoc.head, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 34 [foreignDoc.body, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 34 [foreignDoc.body, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 35 [paras[0], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 35 [paras[0], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 35 [paras[0], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 36 [paras[0], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 36 [paras[0], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 36 [paras[0], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 37 [paras[0], 2] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 37 [paras[0], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 38 [paras[1], 0] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 38 [paras[1], 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 38 [paras[1], 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 39 [paras[1], 1] assert_equals: focusNode must be the node passed to extend() expected Element node <p id="b" style="display:none">Ijklmnop
-</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 39 [paras[1], 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 39 [paras[1], 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 40 [paras[1], 2] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 40 [paras[1], 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 41 [detachedPara1, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 41 [detachedPara1, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 42 [detachedPara1, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Element node <p>Opqrstuv</p> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 42 [detachedPara1, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 43 [testDiv, 0] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 43 [testDiv, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 43 [testDiv, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 44 [testDiv, 3] assert_equals: focusNode must be the node passed to extend() expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
-</p><p id="b" s... but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 44 [testDiv, 3] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 44 [testDiv, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 45 [document, -1] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 45 [document, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 46 [document, 0] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 46 [document, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 46 [document, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 47 [document, 1] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 47 [document, 1] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 47 [document, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 48 [document, 2] assert_equals: focusNode must be the node passed to extend() expected Document node with 2 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 48 [document, 2] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 48 [document, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 49 [document, 3] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 49 [document, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 50 [comment, -1] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 50 [comment, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 51 [comment, 0] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 51 [comment, 0] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 51 [comment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 52 [comment, 4] assert_equals: focusNode must be the node passed to extend() expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 52 [comment, 4] assert_equals: anchorNode must not change if the node passed to extend() has the same root as the original range expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 52 [comment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 53 [comment, 96] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 53 [comment, 96] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 54 [foreignDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 54 [foreignDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 55 [foreignDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 3 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 55 [foreignDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 56 [foreignComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 56 [foreignComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 57 [foreignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 57 [foreignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 58 [foreignTextNode, 36] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "I admit that I harbor doubts about whether we really need..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 58 [foreignTextNode, 36] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 59 [xmlDoc, -1] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 59 [xmlDoc, -1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 60 [xmlDoc, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 60 [xmlDoc, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 61 [xmlDoc, 1] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Document node with 4 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 61 [xmlDoc, 1] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 62 [xmlDoc, 5] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 62 [xmlDoc, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 63 [xmlComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 63 [xmlComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 64 [xmlComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 64 [xmlComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 65 [processingInstruction, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 65 [processingInstruction, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 66 [processingInstruction, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 66 [processingInstruction, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 67 [processingInstruction, 9] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 67 [processingInstruction, 9] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 68 [detachedTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 68 [detachedTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 69 [detachedTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Uvwxyzab" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 69 [detachedTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 70 [detachedForeignTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 70 [detachedForeignTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 71 [detachedForeignTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Cdefghij" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 71 [detachedForeignTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 72 [detachedXmlTextNode, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 72 [detachedXmlTextNode, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 73 [detachedXmlTextNode, 8] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Text node "Klmnopqr" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 73 [detachedXmlTextNode, 8] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 74 [detachedProcessingInstruction, 12] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 74 [detachedProcessingInstruction, 12] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 75 [detachedComment, 3] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 75 [detachedComment, 3] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 76 [detachedComment, 5] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--Stuvwxyz--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 76 [detachedComment, 5] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 77 [detachedForeignComment, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 77 [detachedForeignComment, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 78 [detachedForeignComment, 4] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--אריה יהודה--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 78 [detachedForeignComment, 4] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 79 [detachedXmlComment, 2] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected Comment node <!--בן חיים אליעזר--> but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 79 [detachedXmlComment, 2] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 80 [docfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 80 [docfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 81 [foreignDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 81 [foreignDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
-FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+FAIL extend() forwards with range 40 [paras[3], 1, comment, 8] and point 82 [xmlDocfrag, 0] assert_equals: anchorNode must be the node passed to extend() if it has a different root from the original range expected DocumentFragment node with 0 children but got Element node <p id="d" style="display:none">Yzabcdef</p>
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 82 [xmlDocfrag, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 PASS extend() forwards with range 40 [paras[3], 1, comment, 8] and point 83 [doctype, 0] 
 FAIL extend() backwards with range 40 [paras[3], 1, comment, 8] and point 83 [doctype, 0] assert_equals: Sanity check: startContainer must be correct expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/isCollapsed-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/isCollapsed-expected.txt
index 45afbf2..f30bbf6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/isCollapsed-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/isCollapsed-expected.txt
@@ -14,16 +14,16 @@
 PASS Range 2 [paras[0].firstChild, 2, paras[0].firstChild, 8] 
 PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 9] 
 PASS Range 4 [paras[1].firstChild, 0, paras[1].firstChild, 0] 
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 1] assert_equals: Value of isCollapsed expected false but got true
-FAIL Range 6 [paras[1].firstChild, 2, paras[1].firstChild, 8] assert_equals: Value of isCollapsed expected false but got true
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 9] assert_equals: Value of isCollapsed expected false but got true
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 1] 
+PASS Range 6 [paras[1].firstChild, 2, paras[1].firstChild, 8] 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 9] 
 PASS Range 8 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] 
 FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] assert_equals: Value of isCollapsed expected false but got true
 FAIL Range 10 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8] assert_equals: Value of isCollapsed expected false but got true
 PASS Range 11 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] 
 FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] assert_equals: Value of isCollapsed expected false but got true
 FAIL Range 13 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] assert_equals: Value of isCollapsed expected false but got true
-FAIL Range 14 [document.documentElement, 0, document.documentElement, 1] assert_equals: Value of isCollapsed expected false but got true
+PASS Range 14 [document.documentElement, 0, document.documentElement, 1] 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 2] 
 PASS Range 16 [document.documentElement, 1, document.documentElement, 2] 
 PASS Range 17 [document.head, 1, document.head, 1] 
@@ -41,14 +41,14 @@
 PASS Range 29 [paras[0], 0, paras[0].firstChild, 7] 
 PASS Range 30 [testDiv, 2, paras[4], 1] 
 PASS Range 31 [testDiv, 1, paras[2].firstChild, 5] 
-FAIL Range 32 [document.documentElement, 1, document.body, 0] assert_equals: Value of isCollapsed expected false but got true
+PASS Range 32 [document.documentElement, 1, document.body, 0] 
 FAIL Range 33 [foreignDoc.documentElement, 1, foreignDoc.body, 0] assert_equals: Value of isCollapsed expected false but got true
-FAIL Range 34 [document, 0, document, 1] assert_equals: Value of isCollapsed expected false but got true
+PASS Range 34 [document, 0, document, 1] 
 PASS Range 35 [document, 0, document, 2] 
 PASS Range 36 [document, 1, document, 2] 
 PASS Range 37 [testDiv, 0, comment, 5] 
 PASS Range 38 [paras[2].firstChild, 4, comment, 2] 
-FAIL Range 39 [paras[3], 1, comment, 8] assert_equals: Value of isCollapsed expected false but got true
+PASS Range 39 [paras[3], 1, comment, 8] 
 PASS Range 40 [foreignDoc, 0, foreignDoc, 0] 
 FAIL Range 41 [foreignDoc, 1, foreignComment, 2] assert_equals: Value of isCollapsed expected false but got true
 FAIL Range 42 [foreignDoc.body, 0, foreignTextNode, 36] assert_equals: Value of isCollapsed expected false but got true
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/removeAllRanges-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/removeAllRanges-expected.txt
index ae625b5f..dd7639a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/removeAllRanges-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/removeAllRanges-expected.txt
@@ -8,123 +8,123 @@
 CONSOLE ERROR: line 944: The given range isn't in document.
 CONSOLE ERROR: line 944: The given range isn't in document.
 This is a testharness.js-based test.
-FAIL Range 0 [] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 0 [] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 0 [] forwards 
+PASS Range 0 [] backwards 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0] forwards 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0] backwards 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1] forwards 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1] backwards 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8] forwards 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8] backwards 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9] forwards 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9] backwards 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] forwards 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0] backwards 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] forwards 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1] backwards 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] forwards 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8] backwards 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] forwards 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9] backwards 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] forwards 
 FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] forwards 
 FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8] forwards 
 FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] forwards 
 FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] forwards 
 FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] forwards 
 FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 18 [document.head, 1, document.head, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 18 [document.head, 1, document.head, 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 19 [document.body, 0, document.body, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 19 [document.body, 0, document.body, 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1] forwards 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1] backwards 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2] forwards 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2] backwards 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2] forwards 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2] backwards 
+PASS Range 18 [document.head, 1, document.head, 1] forwards 
+PASS Range 18 [document.head, 1, document.head, 1] backwards 
+PASS Range 19 [document.body, 0, document.body, 1] forwards 
+PASS Range 19 [document.body, 0, document.body, 1] backwards 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] forwards 
 FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1] forwards 
 FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0] forwards 
 FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 23 [paras[0], 0, paras[0], 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 23 [paras[0], 0, paras[0], 0] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 24 [paras[0], 0, paras[0], 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 24 [paras[0], 0, paras[0], 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 23 [paras[0], 0, paras[0], 0] forwards 
+PASS Range 23 [paras[0], 0, paras[0], 0] backwards 
+PASS Range 24 [paras[0], 0, paras[0], 1] forwards 
+PASS Range 24 [paras[0], 0, paras[0], 1] backwards 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0] forwards 
 FAIL Range 25 [detachedPara1, 0, detachedPara1, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1] forwards 
 FAIL Range 26 [detachedPara1, 0, detachedPara1, 1] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 31 [testDiv, 2, paras[4], 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 31 [testDiv, 2, paras[4], 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 33 [document.documentElement, 1, document.body, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 33 [document.documentElement, 1, document.body, 0] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0] forwards 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0] backwards 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8] forwards 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8] backwards 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1] forwards 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1] backwards 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7] forwards 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7] backwards 
+PASS Range 31 [testDiv, 2, paras[4], 1] forwards 
+PASS Range 31 [testDiv, 2, paras[4], 1] backwards 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5] forwards 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5] backwards 
+PASS Range 33 [document.documentElement, 1, document.body, 0] forwards 
+PASS Range 33 [document.documentElement, 1, document.body, 0] backwards 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0] forwards 
 FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 35 [document, 0, document, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 35 [document, 0, document, 1] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 36 [document, 0, document, 2] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 36 [document, 0, document, 2] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 37 [document, 1, document, 2] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 37 [document, 1, document, 2] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 38 [testDiv, 0, comment, 5] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 38 [testDiv, 0, comment, 5] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 40 [paras[3], 1, comment, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 40 [paras[3], 1, comment, 8] backwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 35 [document, 0, document, 1] forwards 
+PASS Range 35 [document, 0, document, 1] backwards 
+PASS Range 36 [document, 0, document, 2] forwards 
+PASS Range 36 [document, 0, document, 2] backwards 
+PASS Range 37 [document, 1, document, 2] forwards 
+PASS Range 37 [document, 1, document, 2] backwards 
+PASS Range 38 [testDiv, 0, comment, 5] forwards 
+PASS Range 38 [testDiv, 0, comment, 5] backwards 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2] forwards 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2] backwards 
+PASS Range 40 [paras[3], 1, comment, 8] forwards 
+PASS Range 40 [paras[3], 1, comment, 8] backwards 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0] forwards 
 FAIL Range 41 [foreignDoc, 0, foreignDoc, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 42 [foreignDoc, 1, foreignComment, 2] forwards 
 FAIL Range 42 [foreignDoc, 1, foreignComment, 2] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36] forwards 
 FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0] forwards 
 FAIL Range 44 [xmlDoc, 0, xmlDoc, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 45 [xmlDoc, 1, xmlComment, 0] forwards 
 FAIL Range 45 [xmlDoc, 1, xmlComment, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8] forwards 
 FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] forwards 
 FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] forwards 
 FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] forwards 
 FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] forwards 
 FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 51 [detachedComment, 3, detachedComment, 4] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 51 [detachedComment, 3, detachedComment, 4] forwards 
 FAIL Range 51 [detachedComment, 3, detachedComment, 4] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 52 [detachedComment, 5, detachedComment, 5] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 52 [detachedComment, 5, detachedComment, 5] forwards 
 FAIL Range 52 [detachedComment, 5, detachedComment, 5] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1] forwards 
 FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4] forwards 
 FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6] forwards 
 FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 56 [docfrag, 0, docfrag, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 56 [docfrag, 0, docfrag, 0] forwards 
 FAIL Range 56 [docfrag, 0, docfrag, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0] forwards 
 FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0] forwards assert_equals: After removeAllRanges(), addRange() must be forwards, so focusOffset must equal endOffset rather than startOffset expected 1 but got 2
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0] forwards 
 FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0] backwards Failed to execute 'extend' on 'Selection': This Selection object doesn't have any Ranges.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/selectAllChildren-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/selectAllChildren-expected.txt
index dfb4e772..ecc3f27 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/selectAllChildren-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/selectAllChildren-expected.txt
@@ -349,40 +349,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 0 [], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 0 [], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 0 [], node 4 foreignPara1 
+PASS Range 0 [], node 5 foreignPara1.firstChild 
+PASS Range 0 [], node 6 detachedPara1 
+PASS Range 0 [], node 7 detachedPara1.firstChild 
+PASS Range 0 [], node 8 detachedPara1 
+PASS Range 0 [], node 9 detachedPara1.firstChild 
 FAIL Range 0 [], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 0 [], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 0 [], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 0 [], node 12 detachedDiv 
+PASS Range 0 [], node 13 detachedPara2 
+PASS Range 0 [], node 14 foreignDoc 
+PASS Range 0 [], node 15 foreignPara2 
+PASS Range 0 [], node 16 xmlDoc 
+PASS Range 0 [], node 17 xmlElement 
+PASS Range 0 [], node 18 detachedXmlElement 
+PASS Range 0 [], node 19 detachedTextNode 
+PASS Range 0 [], node 20 foreignTextNode 
+PASS Range 0 [], node 21 detachedForeignTextNode 
+PASS Range 0 [], node 22 xmlTextNode 
+PASS Range 0 [], node 23 detachedXmlTextNode 
+PASS Range 0 [], node 24 processingInstruction 
+PASS Range 0 [], node 25 detachedProcessingInstruction 
 FAIL Range 0 [], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 0 [], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 0 [], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 0 [], node 27 detachedComment 
+PASS Range 0 [], node 28 foreignComment 
+PASS Range 0 [], node 29 detachedForeignComment 
+PASS Range 0 [], node 30 xmlComment 
+PASS Range 0 [], node 31 detachedXmlComment 
+PASS Range 0 [], node 32 docfrag 
+PASS Range 0 [], node 33 foreignDocfrag 
+PASS Range 0 [], node 34 xmlDocfrag 
 PASS Range 0 [], node 35 doctype 
 PASS Range 0 [], node 36 foreignDoctype 
 PASS Range 0 [], node 37 xmlDoctype 
@@ -394,68 +394,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 4 foreignPara1 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 5 foreignPara1.firstChild 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 6 detachedPara1 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 7 detachedPara1.firstChild 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 8 detachedPara1 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 9 detachedPara1.firstChild 
 FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 12 detachedDiv 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 13 detachedPara2 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 14 foreignDoc 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 15 foreignPara2 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 16 xmlDoc 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 17 xmlElement 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 18 detachedXmlElement 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 19 detachedTextNode 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 20 foreignTextNode 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 21 detachedForeignTextNode 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 22 xmlTextNode 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 23 detachedXmlTextNode 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 24 processingInstruction 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 25 detachedProcessingInstruction 
 FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 27 detachedComment 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 28 foreignComment 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 29 detachedForeignComment 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 30 xmlComment 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 31 detachedXmlComment 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 32 docfrag 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 33 foreignDocfrag 
+PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 34 xmlDocfrag 
 PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 35 doctype 
 PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 36 foreignDoctype 
 PASS Range 1 [paras[0].firstChild, 0, paras[0].firstChild, 0], node 37 xmlDoctype 
@@ -467,68 +439,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 4 foreignPara1 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 5 foreignPara1.firstChild 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 6 detachedPara1 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 7 detachedPara1.firstChild 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 8 detachedPara1 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 9 detachedPara1.firstChild 
 FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 12 detachedDiv 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 13 detachedPara2 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 14 foreignDoc 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 15 foreignPara2 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 16 xmlDoc 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 17 xmlElement 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 18 detachedXmlElement 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 19 detachedTextNode 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 20 foreignTextNode 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 21 detachedForeignTextNode 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 22 xmlTextNode 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 23 detachedXmlTextNode 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 24 processingInstruction 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 25 detachedProcessingInstruction 
 FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 27 detachedComment 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 28 foreignComment 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 29 detachedForeignComment 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 30 xmlComment 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 31 detachedXmlComment 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 32 docfrag 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 33 foreignDocfrag 
+PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 34 xmlDocfrag 
 PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 35 doctype 
 PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 36 foreignDoctype 
 PASS Range 2 [paras[0].firstChild, 0, paras[0].firstChild, 1], node 37 xmlDoctype 
@@ -540,68 +484,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 4 foreignPara1 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 5 foreignPara1.firstChild 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 6 detachedPara1 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 7 detachedPara1.firstChild 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 8 detachedPara1 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 9 detachedPara1.firstChild 
 FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 12 detachedDiv 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 13 detachedPara2 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 14 foreignDoc 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 15 foreignPara2 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 16 xmlDoc 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 17 xmlElement 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 18 detachedXmlElement 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 19 detachedTextNode 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 20 foreignTextNode 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 21 detachedForeignTextNode 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 22 xmlTextNode 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 23 detachedXmlTextNode 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 24 processingInstruction 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 25 detachedProcessingInstruction 
 FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 27 detachedComment 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 28 foreignComment 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 29 detachedForeignComment 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 30 xmlComment 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 31 detachedXmlComment 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 32 docfrag 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 33 foreignDocfrag 
+PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 34 xmlDocfrag 
 PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 35 doctype 
 PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 36 foreignDoctype 
 PASS Range 3 [paras[0].firstChild, 2, paras[0].firstChild, 8], node 37 xmlDoctype 
@@ -613,68 +529,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 4 foreignPara1 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 5 foreignPara1.firstChild 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 6 detachedPara1 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 7 detachedPara1.firstChild 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 8 detachedPara1 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 9 detachedPara1.firstChild 
 FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 12 detachedDiv 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 13 detachedPara2 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 14 foreignDoc 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 15 foreignPara2 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 16 xmlDoc 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 17 xmlElement 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 18 detachedXmlElement 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 19 detachedTextNode 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 20 foreignTextNode 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 21 detachedForeignTextNode 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 22 xmlTextNode 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 23 detachedXmlTextNode 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 24 processingInstruction 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 25 detachedProcessingInstruction 
 FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 27 detachedComment 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 28 foreignComment 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 29 detachedForeignComment 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 30 xmlComment 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 31 detachedXmlComment 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 32 docfrag 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 33 foreignDocfrag 
+PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 34 xmlDocfrag 
 PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 35 doctype 
 PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 36 foreignDoctype 
 PASS Range 4 [paras[0].firstChild, 2, paras[0].firstChild, 9], node 37 xmlDoctype 
@@ -686,40 +574,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 4 foreignPara1 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 5 foreignPara1.firstChild 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 6 detachedPara1 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 7 detachedPara1.firstChild 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 8 detachedPara1 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 9 detachedPara1.firstChild 
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 12 detachedDiv 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 13 detachedPara2 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 14 foreignDoc 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 15 foreignPara2 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 16 xmlDoc 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 17 xmlElement 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 18 detachedXmlElement 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 19 detachedTextNode 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 20 foreignTextNode 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 21 detachedForeignTextNode 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 22 xmlTextNode 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 23 detachedXmlTextNode 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 24 processingInstruction 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 25 detachedProcessingInstruction 
 FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 27 detachedComment 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 28 foreignComment 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 29 detachedForeignComment 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 30 xmlComment 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 31 detachedXmlComment 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 32 docfrag 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 33 foreignDocfrag 
+PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 34 xmlDocfrag 
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 35 doctype 
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 36 foreignDoctype 
 PASS Range 5 [paras[1].firstChild, 0, paras[1].firstChild, 0], node 37 xmlDoctype 
@@ -731,40 +619,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 4 foreignPara1 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 5 foreignPara1.firstChild 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 6 detachedPara1 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 7 detachedPara1.firstChild 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 8 detachedPara1 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 9 detachedPara1.firstChild 
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 12 detachedDiv 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 13 detachedPara2 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 14 foreignDoc 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 15 foreignPara2 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 16 xmlDoc 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 17 xmlElement 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 18 detachedXmlElement 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 19 detachedTextNode 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 20 foreignTextNode 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 21 detachedForeignTextNode 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 22 xmlTextNode 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 23 detachedXmlTextNode 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 24 processingInstruction 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 25 detachedProcessingInstruction 
 FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 27 detachedComment 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 28 foreignComment 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 29 detachedForeignComment 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 30 xmlComment 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 31 detachedXmlComment 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 32 docfrag 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 33 foreignDocfrag 
+PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 34 xmlDocfrag 
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 35 doctype 
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 36 foreignDoctype 
 PASS Range 6 [paras[1].firstChild, 0, paras[1].firstChild, 1], node 37 xmlDoctype 
@@ -776,40 +664,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 4 foreignPara1 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 5 foreignPara1.firstChild 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 6 detachedPara1 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 7 detachedPara1.firstChild 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 8 detachedPara1 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 9 detachedPara1.firstChild 
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 12 detachedDiv 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 13 detachedPara2 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 14 foreignDoc 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 15 foreignPara2 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 16 xmlDoc 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 17 xmlElement 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 18 detachedXmlElement 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 19 detachedTextNode 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 20 foreignTextNode 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 21 detachedForeignTextNode 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 22 xmlTextNode 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 23 detachedXmlTextNode 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 24 processingInstruction 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 25 detachedProcessingInstruction 
 FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 27 detachedComment 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 28 foreignComment 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 29 detachedForeignComment 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 30 xmlComment 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 31 detachedXmlComment 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 32 docfrag 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 33 foreignDocfrag 
+PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 34 xmlDocfrag 
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 35 doctype 
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 36 foreignDoctype 
 PASS Range 7 [paras[1].firstChild, 2, paras[1].firstChild, 8], node 37 xmlDoctype 
@@ -821,40 +709,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 4 foreignPara1 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 5 foreignPara1.firstChild 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 6 detachedPara1 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 7 detachedPara1.firstChild 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 8 detachedPara1 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 9 detachedPara1.firstChild 
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 12 detachedDiv 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 13 detachedPara2 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 14 foreignDoc 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 15 foreignPara2 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 16 xmlDoc 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 17 xmlElement 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 18 detachedXmlElement 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 19 detachedTextNode 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 20 foreignTextNode 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 21 detachedForeignTextNode 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 22 xmlTextNode 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 23 detachedXmlTextNode 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 24 processingInstruction 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 25 detachedProcessingInstruction 
 FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 27 detachedComment 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 28 foreignComment 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 29 detachedForeignComment 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 30 xmlComment 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 31 detachedXmlComment 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 32 docfrag 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 33 foreignDocfrag 
+PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 34 xmlDocfrag 
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 35 doctype 
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 36 foreignDoctype 
 PASS Range 8 [paras[1].firstChild, 2, paras[1].firstChild, 9], node 37 xmlDoctype 
@@ -866,40 +754,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 4 foreignPara1 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 5 foreignPara1.firstChild 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 6 detachedPara1 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 7 detachedPara1.firstChild 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 8 detachedPara1 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 9 detachedPara1.firstChild 
 FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 12 detachedDiv 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 13 detachedPara2 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 14 foreignDoc 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 15 foreignPara2 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 16 xmlDoc 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 17 xmlElement 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 18 detachedXmlElement 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 19 detachedTextNode 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 20 foreignTextNode 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 21 detachedForeignTextNode 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 22 xmlTextNode 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 23 detachedXmlTextNode 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 24 processingInstruction 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 25 detachedProcessingInstruction 
 FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 27 detachedComment 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 28 foreignComment 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 29 detachedForeignComment 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 30 xmlComment 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 31 detachedXmlComment 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 32 docfrag 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 33 foreignDocfrag 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 34 xmlDocfrag 
 PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 35 doctype 
 PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 36 foreignDoctype 
 PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], node 37 xmlDoctype 
@@ -911,40 +799,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 4 foreignPara1 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 5 foreignPara1.firstChild 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 6 detachedPara1 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 7 detachedPara1.firstChild 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 8 detachedPara1 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 9 detachedPara1.firstChild 
 FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 12 detachedDiv 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 13 detachedPara2 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 14 foreignDoc 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 15 foreignPara2 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 16 xmlDoc 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 17 xmlElement 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 18 detachedXmlElement 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 19 detachedTextNode 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 20 foreignTextNode 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 21 detachedForeignTextNode 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 22 xmlTextNode 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 23 detachedXmlTextNode 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 24 processingInstruction 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 25 detachedProcessingInstruction 
 FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 27 detachedComment 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 28 foreignComment 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 29 detachedForeignComment 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 30 xmlComment 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 31 detachedXmlComment 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 32 docfrag 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 33 foreignDocfrag 
+PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 34 xmlDocfrag 
 PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 35 doctype 
 PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 36 foreignDoctype 
 PASS Range 10 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1], node 37 xmlDoctype 
@@ -956,40 +844,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 4 foreignPara1 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 5 foreignPara1.firstChild 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 6 detachedPara1 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 7 detachedPara1.firstChild 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 8 detachedPara1 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 9 detachedPara1.firstChild 
 FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 12 detachedDiv 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 13 detachedPara2 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 14 foreignDoc 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 15 foreignPara2 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 16 xmlDoc 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 17 xmlElement 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 18 detachedXmlElement 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 19 detachedTextNode 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 20 foreignTextNode 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 21 detachedForeignTextNode 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 22 xmlTextNode 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 23 detachedXmlTextNode 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 24 processingInstruction 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 25 detachedProcessingInstruction 
 FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 27 detachedComment 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 28 foreignComment 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 29 detachedForeignComment 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 30 xmlComment 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 31 detachedXmlComment 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 32 docfrag 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 33 foreignDocfrag 
+PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 34 xmlDocfrag 
 PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 35 doctype 
 PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 36 foreignDoctype 
 PASS Range 11 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], node 37 xmlDoctype 
@@ -1001,40 +889,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 4 foreignPara1 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 5 foreignPara1.firstChild 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 6 detachedPara1 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 7 detachedPara1.firstChild 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 8 detachedPara1 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 9 detachedPara1.firstChild 
 FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 12 detachedDiv 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 13 detachedPara2 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 14 foreignDoc 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 15 foreignPara2 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 16 xmlDoc 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 17 xmlElement 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 18 detachedXmlElement 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 19 detachedTextNode 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 20 foreignTextNode 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 21 detachedForeignTextNode 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 22 xmlTextNode 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 23 detachedXmlTextNode 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 24 processingInstruction 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 25 detachedProcessingInstruction 
 FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 27 detachedComment 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 28 foreignComment 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 29 detachedForeignComment 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 30 xmlComment 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 31 detachedXmlComment 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 32 docfrag 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 33 foreignDocfrag 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 34 xmlDocfrag 
 PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 35 doctype 
 PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 36 foreignDoctype 
 PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0], node 37 xmlDoctype 
@@ -1046,40 +934,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 4 foreignPara1 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 5 foreignPara1.firstChild 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 6 detachedPara1 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 7 detachedPara1.firstChild 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 8 detachedPara1 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 9 detachedPara1.firstChild 
 FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 12 detachedDiv 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 13 detachedPara2 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 14 foreignDoc 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 15 foreignPara2 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 16 xmlDoc 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 17 xmlElement 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 18 detachedXmlElement 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 19 detachedTextNode 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 20 foreignTextNode 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 21 detachedForeignTextNode 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 22 xmlTextNode 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 23 detachedXmlTextNode 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 24 processingInstruction 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 25 detachedProcessingInstruction 
 FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 27 detachedComment 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 28 foreignComment 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 29 detachedForeignComment 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 30 xmlComment 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 31 detachedXmlComment 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 32 docfrag 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 33 foreignDocfrag 
+PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 34 xmlDocfrag 
 PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 35 doctype 
 PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 36 foreignDoctype 
 PASS Range 13 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1], node 37 xmlDoctype 
@@ -1091,40 +979,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 4 foreignPara1 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 5 foreignPara1.firstChild 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 6 detachedPara1 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 7 detachedPara1.firstChild 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 8 detachedPara1 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 9 detachedPara1.firstChild 
 FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 12 detachedDiv 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 13 detachedPara2 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 14 foreignDoc 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 15 foreignPara2 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 16 xmlDoc 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 17 xmlElement 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 18 detachedXmlElement 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 19 detachedTextNode 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 20 foreignTextNode 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 21 detachedForeignTextNode 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 22 xmlTextNode 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 23 detachedXmlTextNode 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 24 processingInstruction 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 25 detachedProcessingInstruction 
 FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 27 detachedComment 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 28 foreignComment 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 29 detachedForeignComment 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 30 xmlComment 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 31 detachedXmlComment 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 32 docfrag 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 33 foreignDocfrag 
+PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 34 xmlDocfrag 
 PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 35 doctype 
 PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 36 foreignDoctype 
 PASS Range 14 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8], node 37 xmlDoctype 
@@ -1136,68 +1024,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 4 foreignPara1 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 5 foreignPara1.firstChild 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 6 detachedPara1 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 7 detachedPara1.firstChild 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 8 detachedPara1 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 9 detachedPara1.firstChild 
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 12 detachedDiv 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 13 detachedPara2 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 14 foreignDoc 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 15 foreignPara2 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 16 xmlDoc 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 17 xmlElement 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 18 detachedXmlElement 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 19 detachedTextNode 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 20 foreignTextNode 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 21 detachedForeignTextNode 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 22 xmlTextNode 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 23 detachedXmlTextNode 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 24 processingInstruction 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 25 detachedProcessingInstruction 
 FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 15 [document.documentElement, 0, document.documentElement, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 27 detachedComment 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 28 foreignComment 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 29 detachedForeignComment 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 30 xmlComment 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 31 detachedXmlComment 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 32 docfrag 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 33 foreignDocfrag 
+PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 34 xmlDocfrag 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 35 doctype 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 36 foreignDoctype 
 PASS Range 15 [document.documentElement, 0, document.documentElement, 1], node 37 xmlDoctype 
@@ -1209,68 +1069,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 4 foreignPara1 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 5 foreignPara1.firstChild 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 6 detachedPara1 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 7 detachedPara1.firstChild 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 8 detachedPara1 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 9 detachedPara1.firstChild 
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 12 detachedDiv 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 13 detachedPara2 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 14 foreignDoc 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 15 foreignPara2 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 16 xmlDoc 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 17 xmlElement 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 18 detachedXmlElement 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 19 detachedTextNode 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 20 foreignTextNode 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 21 detachedForeignTextNode 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 22 xmlTextNode 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 23 detachedXmlTextNode 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 24 processingInstruction 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 25 detachedProcessingInstruction 
 FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 16 [document.documentElement, 0, document.documentElement, 2], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 27 detachedComment 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 28 foreignComment 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 29 detachedForeignComment 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 30 xmlComment 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 31 detachedXmlComment 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 32 docfrag 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 33 foreignDocfrag 
+PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 34 xmlDocfrag 
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 35 doctype 
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 36 foreignDoctype 
 PASS Range 16 [document.documentElement, 0, document.documentElement, 2], node 37 xmlDoctype 
@@ -1282,68 +1114,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 4 foreignPara1 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 5 foreignPara1.firstChild 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 6 detachedPara1 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 7 detachedPara1.firstChild 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 8 detachedPara1 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 9 detachedPara1.firstChild 
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 12 detachedDiv 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 13 detachedPara2 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 14 foreignDoc 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 15 foreignPara2 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 16 xmlDoc 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 17 xmlElement 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 18 detachedXmlElement 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 19 detachedTextNode 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 20 foreignTextNode 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 21 detachedForeignTextNode 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 22 xmlTextNode 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 23 detachedXmlTextNode 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 24 processingInstruction 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 25 detachedProcessingInstruction 
 FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 17 [document.documentElement, 1, document.documentElement, 2], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 27 detachedComment 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 28 foreignComment 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 29 detachedForeignComment 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 30 xmlComment 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 31 detachedXmlComment 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 32 docfrag 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 33 foreignDocfrag 
+PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 34 xmlDocfrag 
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 35 doctype 
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 36 foreignDoctype 
 PASS Range 17 [document.documentElement, 1, document.documentElement, 2], node 37 xmlDoctype 
@@ -1355,68 +1159,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 18 [document.head, 1, document.head, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 18 [document.head, 1, document.head, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 18 [document.head, 1, document.head, 1], node 4 foreignPara1 
+PASS Range 18 [document.head, 1, document.head, 1], node 5 foreignPara1.firstChild 
+PASS Range 18 [document.head, 1, document.head, 1], node 6 detachedPara1 
+PASS Range 18 [document.head, 1, document.head, 1], node 7 detachedPara1.firstChild 
+PASS Range 18 [document.head, 1, document.head, 1], node 8 detachedPara1 
+PASS Range 18 [document.head, 1, document.head, 1], node 9 detachedPara1.firstChild 
 FAIL Range 18 [document.head, 1, document.head, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 18 [document.head, 1, document.head, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 18 [document.head, 1, document.head, 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 18 [document.head, 1, document.head, 1], node 12 detachedDiv 
+PASS Range 18 [document.head, 1, document.head, 1], node 13 detachedPara2 
+PASS Range 18 [document.head, 1, document.head, 1], node 14 foreignDoc 
+PASS Range 18 [document.head, 1, document.head, 1], node 15 foreignPara2 
+PASS Range 18 [document.head, 1, document.head, 1], node 16 xmlDoc 
+PASS Range 18 [document.head, 1, document.head, 1], node 17 xmlElement 
+PASS Range 18 [document.head, 1, document.head, 1], node 18 detachedXmlElement 
+PASS Range 18 [document.head, 1, document.head, 1], node 19 detachedTextNode 
+PASS Range 18 [document.head, 1, document.head, 1], node 20 foreignTextNode 
+PASS Range 18 [document.head, 1, document.head, 1], node 21 detachedForeignTextNode 
+PASS Range 18 [document.head, 1, document.head, 1], node 22 xmlTextNode 
+PASS Range 18 [document.head, 1, document.head, 1], node 23 detachedXmlTextNode 
+PASS Range 18 [document.head, 1, document.head, 1], node 24 processingInstruction 
+PASS Range 18 [document.head, 1, document.head, 1], node 25 detachedProcessingInstruction 
 FAIL Range 18 [document.head, 1, document.head, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 18 [document.head, 1, document.head, 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 18 [document.head, 1, document.head, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 18 [document.head, 1, document.head, 1], node 27 detachedComment 
+PASS Range 18 [document.head, 1, document.head, 1], node 28 foreignComment 
+PASS Range 18 [document.head, 1, document.head, 1], node 29 detachedForeignComment 
+PASS Range 18 [document.head, 1, document.head, 1], node 30 xmlComment 
+PASS Range 18 [document.head, 1, document.head, 1], node 31 detachedXmlComment 
+PASS Range 18 [document.head, 1, document.head, 1], node 32 docfrag 
+PASS Range 18 [document.head, 1, document.head, 1], node 33 foreignDocfrag 
+PASS Range 18 [document.head, 1, document.head, 1], node 34 xmlDocfrag 
 PASS Range 18 [document.head, 1, document.head, 1], node 35 doctype 
 PASS Range 18 [document.head, 1, document.head, 1], node 36 foreignDoctype 
 PASS Range 18 [document.head, 1, document.head, 1], node 37 xmlDoctype 
@@ -1428,68 +1204,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 19 [document.body, 0, document.body, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 19 [document.body, 0, document.body, 1], node 4 foreignPara1 
+PASS Range 19 [document.body, 0, document.body, 1], node 5 foreignPara1.firstChild 
+PASS Range 19 [document.body, 0, document.body, 1], node 6 detachedPara1 
+PASS Range 19 [document.body, 0, document.body, 1], node 7 detachedPara1.firstChild 
+PASS Range 19 [document.body, 0, document.body, 1], node 8 detachedPara1 
+PASS Range 19 [document.body, 0, document.body, 1], node 9 detachedPara1.firstChild 
 FAIL Range 19 [document.body, 0, document.body, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 19 [document.body, 0, document.body, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 19 [document.body, 0, document.body, 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 19 [document.body, 0, document.body, 1], node 12 detachedDiv 
+PASS Range 19 [document.body, 0, document.body, 1], node 13 detachedPara2 
+PASS Range 19 [document.body, 0, document.body, 1], node 14 foreignDoc 
+PASS Range 19 [document.body, 0, document.body, 1], node 15 foreignPara2 
+PASS Range 19 [document.body, 0, document.body, 1], node 16 xmlDoc 
+PASS Range 19 [document.body, 0, document.body, 1], node 17 xmlElement 
+PASS Range 19 [document.body, 0, document.body, 1], node 18 detachedXmlElement 
+PASS Range 19 [document.body, 0, document.body, 1], node 19 detachedTextNode 
+PASS Range 19 [document.body, 0, document.body, 1], node 20 foreignTextNode 
+PASS Range 19 [document.body, 0, document.body, 1], node 21 detachedForeignTextNode 
+PASS Range 19 [document.body, 0, document.body, 1], node 22 xmlTextNode 
+PASS Range 19 [document.body, 0, document.body, 1], node 23 detachedXmlTextNode 
+PASS Range 19 [document.body, 0, document.body, 1], node 24 processingInstruction 
+PASS Range 19 [document.body, 0, document.body, 1], node 25 detachedProcessingInstruction 
 FAIL Range 19 [document.body, 0, document.body, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 19 [document.body, 0, document.body, 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 19 [document.body, 0, document.body, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 19 [document.body, 0, document.body, 1], node 27 detachedComment 
+PASS Range 19 [document.body, 0, document.body, 1], node 28 foreignComment 
+PASS Range 19 [document.body, 0, document.body, 1], node 29 detachedForeignComment 
+PASS Range 19 [document.body, 0, document.body, 1], node 30 xmlComment 
+PASS Range 19 [document.body, 0, document.body, 1], node 31 detachedXmlComment 
+PASS Range 19 [document.body, 0, document.body, 1], node 32 docfrag 
+PASS Range 19 [document.body, 0, document.body, 1], node 33 foreignDocfrag 
+PASS Range 19 [document.body, 0, document.body, 1], node 34 xmlDocfrag 
 PASS Range 19 [document.body, 0, document.body, 1], node 35 doctype 
 PASS Range 19 [document.body, 0, document.body, 1], node 36 foreignDoctype 
 PASS Range 19 [document.body, 0, document.body, 1], node 37 xmlDoctype 
@@ -1501,40 +1249,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 4 foreignPara1 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 5 foreignPara1.firstChild 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 6 detachedPara1 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 7 detachedPara1.firstChild 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 8 detachedPara1 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 9 detachedPara1.firstChild 
 FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 12 detachedDiv 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 13 detachedPara2 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 14 foreignDoc 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 15 foreignPara2 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 16 xmlDoc 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 17 xmlElement 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 18 detachedXmlElement 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 19 detachedTextNode 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 20 foreignTextNode 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 21 detachedForeignTextNode 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 22 xmlTextNode 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 23 detachedXmlTextNode 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 24 processingInstruction 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 25 detachedProcessingInstruction 
 FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 27 detachedComment 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 28 foreignComment 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 29 detachedForeignComment 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 30 xmlComment 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 31 detachedXmlComment 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 32 docfrag 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 33 foreignDocfrag 
+PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 34 xmlDocfrag 
 PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 35 doctype 
 PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 36 foreignDoctype 
 PASS Range 20 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1], node 37 xmlDoctype 
@@ -1546,40 +1294,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 4 foreignPara1 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 5 foreignPara1.firstChild 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 6 detachedPara1 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 7 detachedPara1.firstChild 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 8 detachedPara1 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 9 detachedPara1.firstChild 
 FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 12 detachedDiv 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 13 detachedPara2 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 14 foreignDoc 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 15 foreignPara2 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 16 xmlDoc 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 17 xmlElement 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 18 detachedXmlElement 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 19 detachedTextNode 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 20 foreignTextNode 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 21 detachedForeignTextNode 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 22 xmlTextNode 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 23 detachedXmlTextNode 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 24 processingInstruction 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 25 detachedProcessingInstruction 
 FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 27 detachedComment 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 28 foreignComment 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 29 detachedForeignComment 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 30 xmlComment 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 31 detachedXmlComment 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 32 docfrag 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 33 foreignDocfrag 
+PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 34 xmlDocfrag 
 PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 35 doctype 
 PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 36 foreignDoctype 
 PASS Range 21 [foreignDoc.head, 1, foreignDoc.head, 1], node 37 xmlDoctype 
@@ -1591,40 +1339,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 4 foreignPara1 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 5 foreignPara1.firstChild 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 6 detachedPara1 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 7 detachedPara1.firstChild 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 8 detachedPara1 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 9 detachedPara1.firstChild 
 FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 12 detachedDiv 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 13 detachedPara2 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 14 foreignDoc 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 15 foreignPara2 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 16 xmlDoc 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 17 xmlElement 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 18 detachedXmlElement 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 19 detachedTextNode 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 20 foreignTextNode 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 21 detachedForeignTextNode 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 22 xmlTextNode 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 23 detachedXmlTextNode 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 24 processingInstruction 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 25 detachedProcessingInstruction 
 FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 27 detachedComment 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 28 foreignComment 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 29 detachedForeignComment 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 30 xmlComment 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 31 detachedXmlComment 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 32 docfrag 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 33 foreignDocfrag 
+PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 34 xmlDocfrag 
 PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 35 doctype 
 PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 36 foreignDoctype 
 PASS Range 22 [foreignDoc.body, 0, foreignDoc.body, 0], node 37 xmlDoctype 
@@ -1636,68 +1384,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 23 [paras[0], 0, paras[0], 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 23 [paras[0], 0, paras[0], 0], node 4 foreignPara1 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 5 foreignPara1.firstChild 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 6 detachedPara1 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 7 detachedPara1.firstChild 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 8 detachedPara1 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 9 detachedPara1.firstChild 
 FAIL Range 23 [paras[0], 0, paras[0], 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 23 [paras[0], 0, paras[0], 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 23 [paras[0], 0, paras[0], 0], node 12 detachedDiv 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 13 detachedPara2 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 14 foreignDoc 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 15 foreignPara2 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 16 xmlDoc 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 17 xmlElement 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 18 detachedXmlElement 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 19 detachedTextNode 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 20 foreignTextNode 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 21 detachedForeignTextNode 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 22 xmlTextNode 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 23 detachedXmlTextNode 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 24 processingInstruction 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 25 detachedProcessingInstruction 
 FAIL Range 23 [paras[0], 0, paras[0], 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 23 [paras[0], 0, paras[0], 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 23 [paras[0], 0, paras[0], 0], node 27 detachedComment 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 28 foreignComment 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 29 detachedForeignComment 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 30 xmlComment 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 31 detachedXmlComment 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 32 docfrag 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 33 foreignDocfrag 
+PASS Range 23 [paras[0], 0, paras[0], 0], node 34 xmlDocfrag 
 PASS Range 23 [paras[0], 0, paras[0], 0], node 35 doctype 
 PASS Range 23 [paras[0], 0, paras[0], 0], node 36 foreignDoctype 
 PASS Range 23 [paras[0], 0, paras[0], 0], node 37 xmlDoctype 
@@ -1709,68 +1429,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 24 [paras[0], 0, paras[0], 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 24 [paras[0], 0, paras[0], 1], node 4 foreignPara1 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 5 foreignPara1.firstChild 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 6 detachedPara1 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 7 detachedPara1.firstChild 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 8 detachedPara1 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 9 detachedPara1.firstChild 
 FAIL Range 24 [paras[0], 0, paras[0], 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 24 [paras[0], 0, paras[0], 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 24 [paras[0], 0, paras[0], 1], node 12 detachedDiv 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 13 detachedPara2 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 14 foreignDoc 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 15 foreignPara2 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 16 xmlDoc 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 17 xmlElement 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 18 detachedXmlElement 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 19 detachedTextNode 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 20 foreignTextNode 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 21 detachedForeignTextNode 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 22 xmlTextNode 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 23 detachedXmlTextNode 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 24 processingInstruction 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 25 detachedProcessingInstruction 
 FAIL Range 24 [paras[0], 0, paras[0], 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 24 [paras[0], 0, paras[0], 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 24 [paras[0], 0, paras[0], 1], node 27 detachedComment 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 28 foreignComment 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 29 detachedForeignComment 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 30 xmlComment 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 31 detachedXmlComment 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 32 docfrag 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 33 foreignDocfrag 
+PASS Range 24 [paras[0], 0, paras[0], 1], node 34 xmlDocfrag 
 PASS Range 24 [paras[0], 0, paras[0], 1], node 35 doctype 
 PASS Range 24 [paras[0], 0, paras[0], 1], node 36 foreignDoctype 
 PASS Range 24 [paras[0], 0, paras[0], 1], node 37 xmlDoctype 
@@ -1782,40 +1474,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 4 foreignPara1 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 5 foreignPara1.firstChild 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 6 detachedPara1 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 7 detachedPara1.firstChild 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 8 detachedPara1 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 9 detachedPara1.firstChild 
 FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 12 detachedDiv 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 13 detachedPara2 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 14 foreignDoc 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 15 foreignPara2 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 16 xmlDoc 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 17 xmlElement 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 18 detachedXmlElement 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 19 detachedTextNode 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 20 foreignTextNode 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 21 detachedForeignTextNode 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 22 xmlTextNode 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 23 detachedXmlTextNode 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 24 processingInstruction 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 25 detachedProcessingInstruction 
 FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 27 detachedComment 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 28 foreignComment 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 29 detachedForeignComment 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 30 xmlComment 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 31 detachedXmlComment 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 32 docfrag 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 33 foreignDocfrag 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 34 xmlDocfrag 
 PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 35 doctype 
 PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 36 foreignDoctype 
 PASS Range 25 [detachedPara1, 0, detachedPara1, 0], node 37 xmlDoctype 
@@ -1827,40 +1519,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 4 foreignPara1 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 5 foreignPara1.firstChild 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 6 detachedPara1 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 7 detachedPara1.firstChild 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 8 detachedPara1 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 9 detachedPara1.firstChild 
 FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 12 detachedDiv 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 13 detachedPara2 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 14 foreignDoc 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 15 foreignPara2 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 16 xmlDoc 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 17 xmlElement 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 18 detachedXmlElement 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 19 detachedTextNode 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 20 foreignTextNode 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 21 detachedForeignTextNode 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 22 xmlTextNode 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 23 detachedXmlTextNode 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 24 processingInstruction 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 25 detachedProcessingInstruction 
 FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 26 [detachedPara1, 0, detachedPara1, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 27 detachedComment 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 28 foreignComment 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 29 detachedForeignComment 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 30 xmlComment 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 31 detachedXmlComment 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 32 docfrag 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 33 foreignDocfrag 
+PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 34 xmlDocfrag 
 PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 35 doctype 
 PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 36 foreignDoctype 
 PASS Range 26 [detachedPara1, 0, detachedPara1, 1], node 37 xmlDoctype 
@@ -1872,68 +1564,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 4 foreignPara1 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 5 foreignPara1.firstChild 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 6 detachedPara1 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 7 detachedPara1.firstChild 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 8 detachedPara1 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 9 detachedPara1.firstChild 
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 12 detachedDiv 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 13 detachedPara2 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 14 foreignDoc 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 15 foreignPara2 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 16 xmlDoc 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 17 xmlElement 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 18 detachedXmlElement 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 19 detachedTextNode 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 20 foreignTextNode 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 21 detachedForeignTextNode 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 22 xmlTextNode 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 23 detachedXmlTextNode 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 24 processingInstruction 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 25 detachedProcessingInstruction 
 FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 27 detachedComment 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 28 foreignComment 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 29 detachedForeignComment 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 30 xmlComment 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 31 detachedXmlComment 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 32 docfrag 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 33 foreignDocfrag 
+PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 34 xmlDocfrag 
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 35 doctype 
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 36 foreignDoctype 
 PASS Range 27 [paras[0].firstChild, 0, paras[1].firstChild, 0], node 37 xmlDoctype 
@@ -1945,68 +1609,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 4 foreignPara1 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 5 foreignPara1.firstChild 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 6 detachedPara1 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 7 detachedPara1.firstChild 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 8 detachedPara1 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 9 detachedPara1.firstChild 
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 12 detachedDiv 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 13 detachedPara2 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 14 foreignDoc 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 15 foreignPara2 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 16 xmlDoc 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 17 xmlElement 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 18 detachedXmlElement 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 19 detachedTextNode 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 20 foreignTextNode 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 21 detachedForeignTextNode 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 22 xmlTextNode 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 23 detachedXmlTextNode 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 24 processingInstruction 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 25 detachedProcessingInstruction 
 FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 27 detachedComment 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 28 foreignComment 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 29 detachedForeignComment 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 30 xmlComment 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 31 detachedXmlComment 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 32 docfrag 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 33 foreignDocfrag 
+PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 34 xmlDocfrag 
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 35 doctype 
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 36 foreignDoctype 
 PASS Range 28 [paras[0].firstChild, 0, paras[1].firstChild, 8], node 37 xmlDoctype 
@@ -2018,68 +1654,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 4 foreignPara1 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 5 foreignPara1.firstChild 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 6 detachedPara1 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 7 detachedPara1.firstChild 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 8 detachedPara1 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 9 detachedPara1.firstChild 
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 12 detachedDiv 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 13 detachedPara2 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 14 foreignDoc 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 15 foreignPara2 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 16 xmlDoc 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 17 xmlElement 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 18 detachedXmlElement 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 19 detachedTextNode 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 20 foreignTextNode 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 21 detachedForeignTextNode 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 22 xmlTextNode 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 23 detachedXmlTextNode 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 24 processingInstruction 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 25 detachedProcessingInstruction 
 FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 29 [paras[0].firstChild, 3, paras[3], 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 27 detachedComment 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 28 foreignComment 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 29 detachedForeignComment 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 30 xmlComment 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 31 detachedXmlComment 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 32 docfrag 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 33 foreignDocfrag 
+PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 34 xmlDocfrag 
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 35 doctype 
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 36 foreignDoctype 
 PASS Range 29 [paras[0].firstChild, 3, paras[3], 1], node 37 xmlDoctype 
@@ -2091,68 +1699,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 4 foreignPara1 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 5 foreignPara1.firstChild 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 6 detachedPara1 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 7 detachedPara1.firstChild 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 8 detachedPara1 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 9 detachedPara1.firstChild 
 FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 12 detachedDiv 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 13 detachedPara2 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 14 foreignDoc 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 15 foreignPara2 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 16 xmlDoc 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 17 xmlElement 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 18 detachedXmlElement 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 19 detachedTextNode 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 20 foreignTextNode 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 21 detachedForeignTextNode 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 22 xmlTextNode 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 23 detachedXmlTextNode 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 24 processingInstruction 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 25 detachedProcessingInstruction 
 FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 30 [paras[0], 0, paras[0].firstChild, 7], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 27 detachedComment 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 28 foreignComment 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 29 detachedForeignComment 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 30 xmlComment 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 31 detachedXmlComment 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 32 docfrag 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 33 foreignDocfrag 
+PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 34 xmlDocfrag 
 PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 35 doctype 
 PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 36 foreignDoctype 
 PASS Range 30 [paras[0], 0, paras[0].firstChild, 7], node 37 xmlDoctype 
@@ -2164,40 +1744,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 31 [testDiv, 2, paras[4], 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+PASS Range 31 [testDiv, 2, paras[4], 1], node 4 foreignPara1 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 5 foreignPara1.firstChild 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 6 detachedPara1 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 7 detachedPara1.firstChild 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 8 detachedPara1 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 9 detachedPara1.firstChild 
 FAIL Range 31 [testDiv, 2, paras[4], 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 31 [testDiv, 2, paras[4], 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+PASS Range 31 [testDiv, 2, paras[4], 1], node 12 detachedDiv 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 13 detachedPara2 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 14 foreignDoc 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 15 foreignPara2 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 16 xmlDoc 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 17 xmlElement 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 18 detachedXmlElement 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 19 detachedTextNode 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 20 foreignTextNode 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 21 detachedForeignTextNode 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 22 xmlTextNode 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 23 detachedXmlTextNode 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 24 processingInstruction 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 25 detachedProcessingInstruction 
 FAIL Range 31 [testDiv, 2, paras[4], 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 31 [testDiv, 2, paras[4], 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 31 [testDiv, 2, paras[4], 1], node 27 detachedComment 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 28 foreignComment 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 29 detachedForeignComment 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 30 xmlComment 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 31 detachedXmlComment 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 32 docfrag 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 33 foreignDocfrag 
+PASS Range 31 [testDiv, 2, paras[4], 1], node 34 xmlDocfrag 
 PASS Range 31 [testDiv, 2, paras[4], 1], node 35 doctype 
 PASS Range 31 [testDiv, 2, paras[4], 1], node 36 foreignDoctype 
 PASS Range 31 [testDiv, 2, paras[4], 1], node 37 xmlDoctype 
@@ -2209,40 +1789,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 4 foreignPara1 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 5 foreignPara1.firstChild 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 6 detachedPara1 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 7 detachedPara1.firstChild 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 8 detachedPara1 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 9 detachedPara1.firstChild 
 FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 12 detachedDiv 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 13 detachedPara2 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 14 foreignDoc 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 15 foreignPara2 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 16 xmlDoc 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 17 xmlElement 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 18 detachedXmlElement 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 19 detachedTextNode 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 20 foreignTextNode 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 21 detachedForeignTextNode 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 22 xmlTextNode 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 23 detachedXmlTextNode 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 24 processingInstruction 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 25 detachedProcessingInstruction 
 FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 32 [testDiv, 1, paras[2].firstChild, 5], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 27 detachedComment 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 28 foreignComment 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 29 detachedForeignComment 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 30 xmlComment 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 31 detachedXmlComment 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 32 docfrag 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 33 foreignDocfrag 
+PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 34 xmlDocfrag 
 PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 35 doctype 
 PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 36 foreignDoctype 
 PASS Range 32 [testDiv, 1, paras[2].firstChild, 5], node 37 xmlDoctype 
@@ -2254,68 +1834,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 33 [document.documentElement, 1, document.body, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 4 foreignPara1 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 5 foreignPara1.firstChild 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 6 detachedPara1 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 7 detachedPara1.firstChild 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 8 detachedPara1 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 9 detachedPara1.firstChild 
 FAIL Range 33 [document.documentElement, 1, document.body, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 33 [document.documentElement, 1, document.body, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 12 detachedDiv 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 13 detachedPara2 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 14 foreignDoc 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 15 foreignPara2 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 16 xmlDoc 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 17 xmlElement 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 18 detachedXmlElement 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 19 detachedTextNode 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 20 foreignTextNode 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 21 detachedForeignTextNode 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 22 xmlTextNode 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 23 detachedXmlTextNode 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 24 processingInstruction 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 25 detachedProcessingInstruction 
 FAIL Range 33 [document.documentElement, 1, document.body, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 33 [document.documentElement, 1, document.body, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 27 detachedComment 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 28 foreignComment 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 29 detachedForeignComment 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 30 xmlComment 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 31 detachedXmlComment 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 32 docfrag 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 33 foreignDocfrag 
+PASS Range 33 [document.documentElement, 1, document.body, 0], node 34 xmlDocfrag 
 PASS Range 33 [document.documentElement, 1, document.body, 0], node 35 doctype 
 PASS Range 33 [document.documentElement, 1, document.body, 0], node 36 foreignDoctype 
 PASS Range 33 [document.documentElement, 1, document.body, 0], node 37 xmlDoctype 
@@ -2327,40 +1879,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 4 foreignPara1 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 5 foreignPara1.firstChild 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 6 detachedPara1 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 7 detachedPara1.firstChild 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 8 detachedPara1 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 9 detachedPara1.firstChild 
 FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 12 detachedDiv 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 13 detachedPara2 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 14 foreignDoc 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 15 foreignPara2 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 16 xmlDoc 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 17 xmlElement 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 18 detachedXmlElement 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 19 detachedTextNode 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 20 foreignTextNode 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 21 detachedForeignTextNode 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 22 xmlTextNode 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 23 detachedXmlTextNode 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 24 processingInstruction 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 25 detachedProcessingInstruction 
 FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 27 detachedComment 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 28 foreignComment 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 29 detachedForeignComment 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 30 xmlComment 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 31 detachedXmlComment 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 32 docfrag 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 33 foreignDocfrag 
+PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 34 xmlDocfrag 
 PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 35 doctype 
 PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 36 foreignDoctype 
 PASS Range 34 [foreignDoc.documentElement, 1, foreignDoc.body, 0], node 37 xmlDoctype 
@@ -2372,68 +1924,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 35 [document, 0, document, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 35 [document, 0, document, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 35 [document, 0, document, 1], node 4 foreignPara1 
+PASS Range 35 [document, 0, document, 1], node 5 foreignPara1.firstChild 
+PASS Range 35 [document, 0, document, 1], node 6 detachedPara1 
+PASS Range 35 [document, 0, document, 1], node 7 detachedPara1.firstChild 
+PASS Range 35 [document, 0, document, 1], node 8 detachedPara1 
+PASS Range 35 [document, 0, document, 1], node 9 detachedPara1.firstChild 
 FAIL Range 35 [document, 0, document, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 35 [document, 0, document, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 35 [document, 0, document, 1], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 35 [document, 0, document, 1], node 12 detachedDiv 
+PASS Range 35 [document, 0, document, 1], node 13 detachedPara2 
+PASS Range 35 [document, 0, document, 1], node 14 foreignDoc 
+PASS Range 35 [document, 0, document, 1], node 15 foreignPara2 
+PASS Range 35 [document, 0, document, 1], node 16 xmlDoc 
+PASS Range 35 [document, 0, document, 1], node 17 xmlElement 
+PASS Range 35 [document, 0, document, 1], node 18 detachedXmlElement 
+PASS Range 35 [document, 0, document, 1], node 19 detachedTextNode 
+PASS Range 35 [document, 0, document, 1], node 20 foreignTextNode 
+PASS Range 35 [document, 0, document, 1], node 21 detachedForeignTextNode 
+PASS Range 35 [document, 0, document, 1], node 22 xmlTextNode 
+PASS Range 35 [document, 0, document, 1], node 23 detachedXmlTextNode 
+PASS Range 35 [document, 0, document, 1], node 24 processingInstruction 
+PASS Range 35 [document, 0, document, 1], node 25 detachedProcessingInstruction 
 FAIL Range 35 [document, 0, document, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 35 [document, 0, document, 1], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 35 [document, 0, document, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 35 [document, 0, document, 1], node 27 detachedComment 
+PASS Range 35 [document, 0, document, 1], node 28 foreignComment 
+PASS Range 35 [document, 0, document, 1], node 29 detachedForeignComment 
+PASS Range 35 [document, 0, document, 1], node 30 xmlComment 
+PASS Range 35 [document, 0, document, 1], node 31 detachedXmlComment 
+PASS Range 35 [document, 0, document, 1], node 32 docfrag 
+PASS Range 35 [document, 0, document, 1], node 33 foreignDocfrag 
+PASS Range 35 [document, 0, document, 1], node 34 xmlDocfrag 
 PASS Range 35 [document, 0, document, 1], node 35 doctype 
 PASS Range 35 [document, 0, document, 1], node 36 foreignDoctype 
 PASS Range 35 [document, 0, document, 1], node 37 xmlDoctype 
@@ -2445,68 +1969,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 36 [document, 0, document, 2], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 36 [document, 0, document, 2], node 4 foreignPara1 
+PASS Range 36 [document, 0, document, 2], node 5 foreignPara1.firstChild 
+PASS Range 36 [document, 0, document, 2], node 6 detachedPara1 
+PASS Range 36 [document, 0, document, 2], node 7 detachedPara1.firstChild 
+PASS Range 36 [document, 0, document, 2], node 8 detachedPara1 
+PASS Range 36 [document, 0, document, 2], node 9 detachedPara1.firstChild 
 FAIL Range 36 [document, 0, document, 2], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 36 [document, 0, document, 2], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 36 [document, 0, document, 2], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 36 [document, 0, document, 2], node 12 detachedDiv 
+PASS Range 36 [document, 0, document, 2], node 13 detachedPara2 
+PASS Range 36 [document, 0, document, 2], node 14 foreignDoc 
+PASS Range 36 [document, 0, document, 2], node 15 foreignPara2 
+PASS Range 36 [document, 0, document, 2], node 16 xmlDoc 
+PASS Range 36 [document, 0, document, 2], node 17 xmlElement 
+PASS Range 36 [document, 0, document, 2], node 18 detachedXmlElement 
+PASS Range 36 [document, 0, document, 2], node 19 detachedTextNode 
+PASS Range 36 [document, 0, document, 2], node 20 foreignTextNode 
+PASS Range 36 [document, 0, document, 2], node 21 detachedForeignTextNode 
+PASS Range 36 [document, 0, document, 2], node 22 xmlTextNode 
+PASS Range 36 [document, 0, document, 2], node 23 detachedXmlTextNode 
+PASS Range 36 [document, 0, document, 2], node 24 processingInstruction 
+PASS Range 36 [document, 0, document, 2], node 25 detachedProcessingInstruction 
 FAIL Range 36 [document, 0, document, 2], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 36 [document, 0, document, 2], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 36 [document, 0, document, 2], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 36 [document, 0, document, 2], node 27 detachedComment 
+PASS Range 36 [document, 0, document, 2], node 28 foreignComment 
+PASS Range 36 [document, 0, document, 2], node 29 detachedForeignComment 
+PASS Range 36 [document, 0, document, 2], node 30 xmlComment 
+PASS Range 36 [document, 0, document, 2], node 31 detachedXmlComment 
+PASS Range 36 [document, 0, document, 2], node 32 docfrag 
+PASS Range 36 [document, 0, document, 2], node 33 foreignDocfrag 
+PASS Range 36 [document, 0, document, 2], node 34 xmlDocfrag 
 PASS Range 36 [document, 0, document, 2], node 35 doctype 
 PASS Range 36 [document, 0, document, 2], node 36 foreignDoctype 
 PASS Range 36 [document, 0, document, 2], node 37 xmlDoctype 
@@ -2518,68 +2014,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 37 [document, 1, document, 2], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 37 [document, 1, document, 2], node 4 foreignPara1 
+PASS Range 37 [document, 1, document, 2], node 5 foreignPara1.firstChild 
+PASS Range 37 [document, 1, document, 2], node 6 detachedPara1 
+PASS Range 37 [document, 1, document, 2], node 7 detachedPara1.firstChild 
+PASS Range 37 [document, 1, document, 2], node 8 detachedPara1 
+PASS Range 37 [document, 1, document, 2], node 9 detachedPara1.firstChild 
 FAIL Range 37 [document, 1, document, 2], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 37 [document, 1, document, 2], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 37 [document, 1, document, 2], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 37 [document, 1, document, 2], node 12 detachedDiv 
+PASS Range 37 [document, 1, document, 2], node 13 detachedPara2 
+PASS Range 37 [document, 1, document, 2], node 14 foreignDoc 
+PASS Range 37 [document, 1, document, 2], node 15 foreignPara2 
+PASS Range 37 [document, 1, document, 2], node 16 xmlDoc 
+PASS Range 37 [document, 1, document, 2], node 17 xmlElement 
+PASS Range 37 [document, 1, document, 2], node 18 detachedXmlElement 
+PASS Range 37 [document, 1, document, 2], node 19 detachedTextNode 
+PASS Range 37 [document, 1, document, 2], node 20 foreignTextNode 
+PASS Range 37 [document, 1, document, 2], node 21 detachedForeignTextNode 
+PASS Range 37 [document, 1, document, 2], node 22 xmlTextNode 
+PASS Range 37 [document, 1, document, 2], node 23 detachedXmlTextNode 
+PASS Range 37 [document, 1, document, 2], node 24 processingInstruction 
+PASS Range 37 [document, 1, document, 2], node 25 detachedProcessingInstruction 
 FAIL Range 37 [document, 1, document, 2], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 37 [document, 1, document, 2], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 37 [document, 1, document, 2], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 37 [document, 1, document, 2], node 27 detachedComment 
+PASS Range 37 [document, 1, document, 2], node 28 foreignComment 
+PASS Range 37 [document, 1, document, 2], node 29 detachedForeignComment 
+PASS Range 37 [document, 1, document, 2], node 30 xmlComment 
+PASS Range 37 [document, 1, document, 2], node 31 detachedXmlComment 
+PASS Range 37 [document, 1, document, 2], node 32 docfrag 
+PASS Range 37 [document, 1, document, 2], node 33 foreignDocfrag 
+PASS Range 37 [document, 1, document, 2], node 34 xmlDocfrag 
 PASS Range 37 [document, 1, document, 2], node 35 doctype 
 PASS Range 37 [document, 1, document, 2], node 36 foreignDoctype 
 PASS Range 37 [document, 1, document, 2], node 37 xmlDoctype 
@@ -2591,68 +2059,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 38 [testDiv, 0, comment, 5], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 38 [testDiv, 0, comment, 5], node 4 foreignPara1 
+PASS Range 38 [testDiv, 0, comment, 5], node 5 foreignPara1.firstChild 
+PASS Range 38 [testDiv, 0, comment, 5], node 6 detachedPara1 
+PASS Range 38 [testDiv, 0, comment, 5], node 7 detachedPara1.firstChild 
+PASS Range 38 [testDiv, 0, comment, 5], node 8 detachedPara1 
+PASS Range 38 [testDiv, 0, comment, 5], node 9 detachedPara1.firstChild 
 FAIL Range 38 [testDiv, 0, comment, 5], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 38 [testDiv, 0, comment, 5], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 38 [testDiv, 0, comment, 5], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 38 [testDiv, 0, comment, 5], node 12 detachedDiv 
+PASS Range 38 [testDiv, 0, comment, 5], node 13 detachedPara2 
+PASS Range 38 [testDiv, 0, comment, 5], node 14 foreignDoc 
+PASS Range 38 [testDiv, 0, comment, 5], node 15 foreignPara2 
+PASS Range 38 [testDiv, 0, comment, 5], node 16 xmlDoc 
+PASS Range 38 [testDiv, 0, comment, 5], node 17 xmlElement 
+PASS Range 38 [testDiv, 0, comment, 5], node 18 detachedXmlElement 
+PASS Range 38 [testDiv, 0, comment, 5], node 19 detachedTextNode 
+PASS Range 38 [testDiv, 0, comment, 5], node 20 foreignTextNode 
+PASS Range 38 [testDiv, 0, comment, 5], node 21 detachedForeignTextNode 
+PASS Range 38 [testDiv, 0, comment, 5], node 22 xmlTextNode 
+PASS Range 38 [testDiv, 0, comment, 5], node 23 detachedXmlTextNode 
+PASS Range 38 [testDiv, 0, comment, 5], node 24 processingInstruction 
+PASS Range 38 [testDiv, 0, comment, 5], node 25 detachedProcessingInstruction 
 FAIL Range 38 [testDiv, 0, comment, 5], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 38 [testDiv, 0, comment, 5], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 38 [testDiv, 0, comment, 5], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 38 [testDiv, 0, comment, 5], node 27 detachedComment 
+PASS Range 38 [testDiv, 0, comment, 5], node 28 foreignComment 
+PASS Range 38 [testDiv, 0, comment, 5], node 29 detachedForeignComment 
+PASS Range 38 [testDiv, 0, comment, 5], node 30 xmlComment 
+PASS Range 38 [testDiv, 0, comment, 5], node 31 detachedXmlComment 
+PASS Range 38 [testDiv, 0, comment, 5], node 32 docfrag 
+PASS Range 38 [testDiv, 0, comment, 5], node 33 foreignDocfrag 
+PASS Range 38 [testDiv, 0, comment, 5], node 34 xmlDocfrag 
 PASS Range 38 [testDiv, 0, comment, 5], node 35 doctype 
 PASS Range 38 [testDiv, 0, comment, 5], node 36 foreignDoctype 
 PASS Range 38 [testDiv, 0, comment, 5], node 37 xmlDoctype 
@@ -2664,40 +2104,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 4 foreignPara1 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 5 foreignPara1.firstChild 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 6 detachedPara1 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 7 detachedPara1.firstChild 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 8 detachedPara1 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 9 detachedPara1.firstChild 
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 12 detachedDiv 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 13 detachedPara2 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 14 foreignDoc 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 15 foreignPara2 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 16 xmlDoc 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 17 xmlElement 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 18 detachedXmlElement 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 19 detachedTextNode 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 20 foreignTextNode 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 21 detachedForeignTextNode 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 22 xmlTextNode 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 23 detachedXmlTextNode 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 24 processingInstruction 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 25 detachedProcessingInstruction 
 FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 39 [paras[2].firstChild, 4, comment, 2], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 27 detachedComment 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 28 foreignComment 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 29 detachedForeignComment 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 30 xmlComment 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 31 detachedXmlComment 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 32 docfrag 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 33 foreignDocfrag 
+PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 34 xmlDocfrag 
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 35 doctype 
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 36 foreignDoctype 
 PASS Range 39 [paras[2].firstChild, 4, comment, 2], node 37 xmlDoctype 
@@ -2709,40 +2149,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 40 [paras[3], 1, comment, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Efghijkl</p> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Opqrstuv</p> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
+PASS Range 40 [paras[3], 1, comment, 8], node 4 foreignPara1 
+PASS Range 40 [paras[3], 1, comment, 8], node 5 foreignPara1.firstChild 
+PASS Range 40 [paras[3], 1, comment, 8], node 6 detachedPara1 
+PASS Range 40 [paras[3], 1, comment, 8], node 7 detachedPara1.firstChild 
+PASS Range 40 [paras[3], 1, comment, 8], node 8 detachedPara1 
+PASS Range 40 [paras[3], 1, comment, 8], node 9 detachedPara1.firstChild 
 FAIL Range 40 [paras[3], 1, comment, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 40 [paras[3], 1, comment, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 40 [paras[3], 1, comment, 8], node 12 detachedDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div><p>Opqrstuv</p><p>Wxyzabcd</p></div> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Wxyzabcd</p> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 14 foreignDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <p>Mnopqrst</p> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 16 xmlDoc assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 17 xmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <igiveuponcreativenames>do re mi fa so la ti</igiveuponcr... but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <everyone-hates-hyphenated-element-names></everyone-hates... but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "do re mi fa so la ti" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 24 processingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "somePI" and data "Did you know that \":syn sync fromstart\" is very useful wh..." but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, anchorNode must be the given node expected ProcessingInstruction node with target "whippoorwill" and data "chirp chirp chirp" but got Text node "Qrstuvwx"
+PASS Range 40 [paras[3], 1, comment, 8], node 12 detachedDiv 
+PASS Range 40 [paras[3], 1, comment, 8], node 13 detachedPara2 
+PASS Range 40 [paras[3], 1, comment, 8], node 14 foreignDoc 
+PASS Range 40 [paras[3], 1, comment, 8], node 15 foreignPara2 
+PASS Range 40 [paras[3], 1, comment, 8], node 16 xmlDoc 
+PASS Range 40 [paras[3], 1, comment, 8], node 17 xmlElement 
+PASS Range 40 [paras[3], 1, comment, 8], node 18 detachedXmlElement 
+PASS Range 40 [paras[3], 1, comment, 8], node 19 detachedTextNode 
+PASS Range 40 [paras[3], 1, comment, 8], node 20 foreignTextNode 
+PASS Range 40 [paras[3], 1, comment, 8], node 21 detachedForeignTextNode 
+PASS Range 40 [paras[3], 1, comment, 8], node 22 xmlTextNode 
+PASS Range 40 [paras[3], 1, comment, 8], node 23 detachedXmlTextNode 
+PASS Range 40 [paras[3], 1, comment, 8], node 24 processingInstruction 
+PASS Range 40 [paras[3], 1, comment, 8], node 25 detachedProcessingInstruction 
 FAIL Range 40 [paras[3], 1, comment, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 27 detachedComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 28 foreignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 30 xmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 32 docfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 40 [paras[3], 1, comment, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, anchorNode must be the given node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 40 [paras[3], 1, comment, 8], node 27 detachedComment 
+PASS Range 40 [paras[3], 1, comment, 8], node 28 foreignComment 
+PASS Range 40 [paras[3], 1, comment, 8], node 29 detachedForeignComment 
+PASS Range 40 [paras[3], 1, comment, 8], node 30 xmlComment 
+PASS Range 40 [paras[3], 1, comment, 8], node 31 detachedXmlComment 
+PASS Range 40 [paras[3], 1, comment, 8], node 32 docfrag 
+PASS Range 40 [paras[3], 1, comment, 8], node 33 foreignDocfrag 
+PASS Range 40 [paras[3], 1, comment, 8], node 34 xmlDocfrag 
 PASS Range 40 [paras[3], 1, comment, 8], node 35 doctype 
 PASS Range 40 [paras[3], 1, comment, 8], node 36 foreignDoctype 
 PASS Range 40 [paras[3], 1, comment, 8], node 37 xmlDoctype 
@@ -2754,40 +2194,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 4 foreignPara1 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 5 foreignPara1.firstChild 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 6 detachedPara1 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 7 detachedPara1.firstChild 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 8 detachedPara1 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 9 detachedPara1.firstChild 
 FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 12 detachedDiv 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 13 detachedPara2 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 14 foreignDoc 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 15 foreignPara2 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 16 xmlDoc 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 17 xmlElement 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 18 detachedXmlElement 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 19 detachedTextNode 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 20 foreignTextNode 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 21 detachedForeignTextNode 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 22 xmlTextNode 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 23 detachedXmlTextNode 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 24 processingInstruction 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 25 detachedProcessingInstruction 
 FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 41 [foreignDoc, 0, foreignDoc, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 27 detachedComment 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 28 foreignComment 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 29 detachedForeignComment 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 30 xmlComment 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 31 detachedXmlComment 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 32 docfrag 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 33 foreignDocfrag 
+PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 34 xmlDocfrag 
 PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 35 doctype 
 PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 36 foreignDoctype 
 PASS Range 41 [foreignDoc, 0, foreignDoc, 0], node 37 xmlDoctype 
@@ -2799,40 +2239,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 4 foreignPara1 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 5 foreignPara1.firstChild 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 6 detachedPara1 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 7 detachedPara1.firstChild 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 8 detachedPara1 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 9 detachedPara1.firstChild 
 FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 12 detachedDiv 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 13 detachedPara2 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 14 foreignDoc 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 15 foreignPara2 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 16 xmlDoc 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 17 xmlElement 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 18 detachedXmlElement 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 19 detachedTextNode 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 20 foreignTextNode 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 21 detachedForeignTextNode 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 22 xmlTextNode 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 23 detachedXmlTextNode 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 24 processingInstruction 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 25 detachedProcessingInstruction 
 FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 42 [foreignDoc, 1, foreignComment, 2], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 27 detachedComment 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 28 foreignComment 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 29 detachedForeignComment 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 30 xmlComment 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 31 detachedXmlComment 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 32 docfrag 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 33 foreignDocfrag 
+PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 34 xmlDocfrag 
 PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 35 doctype 
 PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 36 foreignDoctype 
 PASS Range 42 [foreignDoc, 1, foreignComment, 2], node 37 xmlDoctype 
@@ -2844,40 +2284,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 4 foreignPara1 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 5 foreignPara1.firstChild 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 6 detachedPara1 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 7 detachedPara1.firstChild 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 8 detachedPara1 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 9 detachedPara1.firstChild 
 FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 12 detachedDiv 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 13 detachedPara2 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 14 foreignDoc 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 15 foreignPara2 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 16 xmlDoc 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 17 xmlElement 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 18 detachedXmlElement 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 19 detachedTextNode 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 20 foreignTextNode 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 21 detachedForeignTextNode 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 22 xmlTextNode 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 23 detachedXmlTextNode 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 24 processingInstruction 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 25 detachedProcessingInstruction 
 FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 27 detachedComment 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 28 foreignComment 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 29 detachedForeignComment 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 30 xmlComment 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 31 detachedXmlComment 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 32 docfrag 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 33 foreignDocfrag 
+PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 34 xmlDocfrag 
 PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 35 doctype 
 PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 36 foreignDoctype 
 PASS Range 43 [foreignDoc.body, 0, foreignTextNode, 36], node 37 xmlDoctype 
@@ -2889,40 +2329,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 4 foreignPara1 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 5 foreignPara1.firstChild 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 6 detachedPara1 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 7 detachedPara1.firstChild 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 8 detachedPara1 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 9 detachedPara1.firstChild 
 FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 12 detachedDiv 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 13 detachedPara2 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 14 foreignDoc 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 15 foreignPara2 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 16 xmlDoc 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 17 xmlElement 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 18 detachedXmlElement 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 19 detachedTextNode 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 20 foreignTextNode 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 21 detachedForeignTextNode 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 22 xmlTextNode 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 23 detachedXmlTextNode 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 24 processingInstruction 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 25 detachedProcessingInstruction 
 FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 44 [xmlDoc, 0, xmlDoc, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 27 detachedComment 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 28 foreignComment 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 29 detachedForeignComment 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 30 xmlComment 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 31 detachedXmlComment 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 32 docfrag 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 33 foreignDocfrag 
+PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 34 xmlDocfrag 
 PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 35 doctype 
 PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 36 foreignDoctype 
 PASS Range 44 [xmlDoc, 0, xmlDoc, 0], node 37 xmlDoctype 
@@ -2934,40 +2374,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 4 foreignPara1 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 5 foreignPara1.firstChild 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 6 detachedPara1 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 7 detachedPara1.firstChild 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 8 detachedPara1 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 9 detachedPara1.firstChild 
 FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 12 detachedDiv 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 13 detachedPara2 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 14 foreignDoc 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 15 foreignPara2 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 16 xmlDoc 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 17 xmlElement 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 18 detachedXmlElement 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 19 detachedTextNode 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 20 foreignTextNode 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 21 detachedForeignTextNode 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 22 xmlTextNode 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 23 detachedXmlTextNode 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 24 processingInstruction 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 25 detachedProcessingInstruction 
 FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 45 [xmlDoc, 1, xmlComment, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 27 detachedComment 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 28 foreignComment 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 29 detachedForeignComment 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 30 xmlComment 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 31 detachedXmlComment 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 32 docfrag 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 33 foreignDocfrag 
+PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 34 xmlDocfrag 
 PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 35 doctype 
 PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 36 foreignDoctype 
 PASS Range 45 [xmlDoc, 1, xmlComment, 0], node 37 xmlDoctype 
@@ -2979,40 +2419,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 4 foreignPara1 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 5 foreignPara1.firstChild 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 6 detachedPara1 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 7 detachedPara1.firstChild 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 8 detachedPara1 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 9 detachedPara1.firstChild 
 FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 12 detachedDiv 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 13 detachedPara2 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 14 foreignDoc 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 15 foreignPara2 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 16 xmlDoc 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 17 xmlElement 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 18 detachedXmlElement 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 19 detachedTextNode 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 20 foreignTextNode 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 21 detachedForeignTextNode 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 22 xmlTextNode 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 23 detachedXmlTextNode 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 24 processingInstruction 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 25 detachedProcessingInstruction 
 FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 27 detachedComment 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 28 foreignComment 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 29 detachedForeignComment 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 30 xmlComment 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 31 detachedXmlComment 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 32 docfrag 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 33 foreignDocfrag 
+PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 34 xmlDocfrag 
 PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 35 doctype 
 PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 36 foreignDoctype 
 PASS Range 46 [detachedTextNode, 0, detachedTextNode, 8], node 37 xmlDoctype 
@@ -3024,40 +2464,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 4 foreignPara1 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 5 foreignPara1.firstChild 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 6 detachedPara1 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 7 detachedPara1.firstChild 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 8 detachedPara1 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 9 detachedPara1.firstChild 
 FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 12 detachedDiv 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 13 detachedPara2 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 14 foreignDoc 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 15 foreignPara2 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 16 xmlDoc 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 17 xmlElement 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 18 detachedXmlElement 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 19 detachedTextNode 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 20 foreignTextNode 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 21 detachedForeignTextNode 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 22 xmlTextNode 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 23 detachedXmlTextNode 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 24 processingInstruction 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 25 detachedProcessingInstruction 
 FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 27 detachedComment 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 28 foreignComment 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 29 detachedForeignComment 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 30 xmlComment 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 31 detachedXmlComment 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 32 docfrag 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 33 foreignDocfrag 
+PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 34 xmlDocfrag 
 PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 35 doctype 
 PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 36 foreignDoctype 
 PASS Range 47 [detachedForeignTextNode, 7, detachedForeignTextNode, 7], node 37 xmlDoctype 
@@ -3069,40 +2509,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 4 foreignPara1 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 5 foreignPara1.firstChild 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 6 detachedPara1 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 7 detachedPara1.firstChild 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 8 detachedPara1 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 9 detachedPara1.firstChild 
 FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 12 detachedDiv 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 13 detachedPara2 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 14 foreignDoc 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 15 foreignPara2 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 16 xmlDoc 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 17 xmlElement 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 18 detachedXmlElement 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 19 detachedTextNode 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 20 foreignTextNode 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 21 detachedForeignTextNode 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 22 xmlTextNode 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 23 detachedXmlTextNode 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 24 processingInstruction 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 25 detachedProcessingInstruction 
 FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 27 detachedComment 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 28 foreignComment 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 29 detachedForeignComment 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 30 xmlComment 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 31 detachedXmlComment 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 32 docfrag 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 33 foreignDocfrag 
+PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 34 xmlDocfrag 
 PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 35 doctype 
 PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 36 foreignDoctype 
 PASS Range 48 [detachedForeignTextNode, 0, detachedForeignTextNode, 8], node 37 xmlDoctype 
@@ -3114,40 +2554,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 4 foreignPara1 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 5 foreignPara1.firstChild 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 6 detachedPara1 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 7 detachedPara1.firstChild 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 8 detachedPara1 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 9 detachedPara1.firstChild 
 FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 12 detachedDiv 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 13 detachedPara2 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 14 foreignDoc 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 15 foreignPara2 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 16 xmlDoc 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 17 xmlElement 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 18 detachedXmlElement 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 19 detachedTextNode 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 20 foreignTextNode 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 21 detachedForeignTextNode 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 22 xmlTextNode 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 23 detachedXmlTextNode 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 24 processingInstruction 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 25 detachedProcessingInstruction 
 FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 27 detachedComment 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 28 foreignComment 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 29 detachedForeignComment 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 30 xmlComment 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 31 detachedXmlComment 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 32 docfrag 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 33 foreignDocfrag 
+PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 34 xmlDocfrag 
 PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 35 doctype 
 PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 36 foreignDoctype 
 PASS Range 49 [detachedXmlTextNode, 7, detachedXmlTextNode, 7], node 37 xmlDoctype 
@@ -3159,40 +2599,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 4 foreignPara1 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 5 foreignPara1.firstChild 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 6 detachedPara1 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 7 detachedPara1.firstChild 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 8 detachedPara1 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 9 detachedPara1.firstChild 
 FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 12 detachedDiv 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 13 detachedPara2 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 14 foreignDoc 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 15 foreignPara2 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 16 xmlDoc 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 17 xmlElement 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 18 detachedXmlElement 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 19 detachedTextNode 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 20 foreignTextNode 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 21 detachedForeignTextNode 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 22 xmlTextNode 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 23 detachedXmlTextNode 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 24 processingInstruction 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 25 detachedProcessingInstruction 
 FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 27 detachedComment 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 28 foreignComment 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 29 detachedForeignComment 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 30 xmlComment 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 31 detachedXmlComment 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 32 docfrag 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 33 foreignDocfrag 
+PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 34 xmlDocfrag 
 PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 35 doctype 
 PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 36 foreignDoctype 
 PASS Range 50 [detachedXmlTextNode, 0, detachedXmlTextNode, 8], node 37 xmlDoctype 
@@ -3204,40 +2644,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 4 foreignPara1 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 5 foreignPara1.firstChild 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 6 detachedPara1 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 7 detachedPara1.firstChild 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 8 detachedPara1 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 9 detachedPara1.firstChild 
 FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 12 detachedDiv 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 13 detachedPara2 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 14 foreignDoc 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 15 foreignPara2 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 16 xmlDoc 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 17 xmlElement 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 18 detachedXmlElement 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 19 detachedTextNode 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 20 foreignTextNode 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 21 detachedForeignTextNode 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 22 xmlTextNode 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 23 detachedXmlTextNode 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 24 processingInstruction 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 25 detachedProcessingInstruction 
 FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 51 [detachedComment, 3, detachedComment, 4], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 27 detachedComment 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 28 foreignComment 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 29 detachedForeignComment 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 30 xmlComment 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 31 detachedXmlComment 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 32 docfrag 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 33 foreignDocfrag 
+PASS Range 51 [detachedComment, 3, detachedComment, 4], node 34 xmlDocfrag 
 PASS Range 51 [detachedComment, 3, detachedComment, 4], node 35 doctype 
 PASS Range 51 [detachedComment, 3, detachedComment, 4], node 36 foreignDoctype 
 PASS Range 51 [detachedComment, 3, detachedComment, 4], node 37 xmlDoctype 
@@ -3249,40 +2689,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 4 foreignPara1 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 5 foreignPara1.firstChild 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 6 detachedPara1 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 7 detachedPara1.firstChild 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 8 detachedPara1 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 9 detachedPara1.firstChild 
 FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 12 detachedDiv 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 13 detachedPara2 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 14 foreignDoc 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 15 foreignPara2 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 16 xmlDoc 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 17 xmlElement 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 18 detachedXmlElement 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 19 detachedTextNode 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 20 foreignTextNode 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 21 detachedForeignTextNode 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 22 xmlTextNode 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 23 detachedXmlTextNode 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 24 processingInstruction 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 25 detachedProcessingInstruction 
 FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 52 [detachedComment, 5, detachedComment, 5], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 27 detachedComment 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 28 foreignComment 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 29 detachedForeignComment 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 30 xmlComment 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 31 detachedXmlComment 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 32 docfrag 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 33 foreignDocfrag 
+PASS Range 52 [detachedComment, 5, detachedComment, 5], node 34 xmlDocfrag 
 PASS Range 52 [detachedComment, 5, detachedComment, 5], node 35 doctype 
 PASS Range 52 [detachedComment, 5, detachedComment, 5], node 36 foreignDoctype 
 PASS Range 52 [detachedComment, 5, detachedComment, 5], node 37 xmlDoctype 
@@ -3294,40 +2734,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 4 foreignPara1 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 5 foreignPara1.firstChild 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 6 detachedPara1 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 7 detachedPara1.firstChild 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 8 detachedPara1 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 9 detachedPara1.firstChild 
 FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 12 detachedDiv 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 13 detachedPara2 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 14 foreignDoc 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 15 foreignPara2 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 16 xmlDoc 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 17 xmlElement 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 18 detachedXmlElement 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 19 detachedTextNode 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 20 foreignTextNode 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 21 detachedForeignTextNode 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 22 xmlTextNode 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 23 detachedXmlTextNode 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 24 processingInstruction 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 25 detachedProcessingInstruction 
 FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 27 detachedComment 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 28 foreignComment 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 29 detachedForeignComment 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 30 xmlComment 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 31 detachedXmlComment 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 32 docfrag 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 33 foreignDocfrag 
+PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 34 xmlDocfrag 
 PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 35 doctype 
 PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 36 foreignDoctype 
 PASS Range 53 [detachedForeignComment, 0, detachedForeignComment, 1], node 37 xmlDoctype 
@@ -3339,40 +2779,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 4 foreignPara1 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 5 foreignPara1.firstChild 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 6 detachedPara1 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 7 detachedPara1.firstChild 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 8 detachedPara1 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 9 detachedPara1.firstChild 
 FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 12 detachedDiv 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 13 detachedPara2 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 14 foreignDoc 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 15 foreignPara2 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 16 xmlDoc 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 17 xmlElement 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 18 detachedXmlElement 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 19 detachedTextNode 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 20 foreignTextNode 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 21 detachedForeignTextNode 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 22 xmlTextNode 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 23 detachedXmlTextNode 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 24 processingInstruction 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 25 detachedProcessingInstruction 
 FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 27 detachedComment 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 28 foreignComment 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 29 detachedForeignComment 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 30 xmlComment 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 31 detachedXmlComment 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 32 docfrag 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 33 foreignDocfrag 
+PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 34 xmlDocfrag 
 PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 35 doctype 
 PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 36 foreignDoctype 
 PASS Range 54 [detachedForeignComment, 4, detachedForeignComment, 4], node 37 xmlDoctype 
@@ -3384,40 +2824,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 4 foreignPara1 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 5 foreignPara1.firstChild 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 6 detachedPara1 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 7 detachedPara1.firstChild 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 8 detachedPara1 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 9 detachedPara1.firstChild 
 FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 12 detachedDiv 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 13 detachedPara2 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 14 foreignDoc 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 15 foreignPara2 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 16 xmlDoc 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 17 xmlElement 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 18 detachedXmlElement 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 19 detachedTextNode 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 20 foreignTextNode 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 21 detachedForeignTextNode 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 22 xmlTextNode 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 23 detachedXmlTextNode 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 24 processingInstruction 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 25 detachedProcessingInstruction 
 FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 27 detachedComment 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 28 foreignComment 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 29 detachedForeignComment 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 30 xmlComment 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 31 detachedXmlComment 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 32 docfrag 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 33 foreignDocfrag 
+PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 34 xmlDocfrag 
 PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 35 doctype 
 PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 36 foreignDoctype 
 PASS Range 55 [detachedXmlComment, 2, detachedXmlComment, 6], node 37 xmlDoctype 
@@ -3429,40 +2869,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 56 [docfrag, 0, docfrag, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 56 [docfrag, 0, docfrag, 0], node 4 foreignPara1 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 5 foreignPara1.firstChild 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 6 detachedPara1 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 7 detachedPara1.firstChild 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 8 detachedPara1 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 9 detachedPara1.firstChild 
 FAIL Range 56 [docfrag, 0, docfrag, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 56 [docfrag, 0, docfrag, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 56 [docfrag, 0, docfrag, 0], node 12 detachedDiv 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 13 detachedPara2 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 14 foreignDoc 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 15 foreignPara2 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 16 xmlDoc 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 17 xmlElement 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 18 detachedXmlElement 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 19 detachedTextNode 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 20 foreignTextNode 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 21 detachedForeignTextNode 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 22 xmlTextNode 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 23 detachedXmlTextNode 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 24 processingInstruction 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 25 detachedProcessingInstruction 
 FAIL Range 56 [docfrag, 0, docfrag, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 56 [docfrag, 0, docfrag, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 56 [docfrag, 0, docfrag, 0], node 27 detachedComment 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 28 foreignComment 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 29 detachedForeignComment 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 30 xmlComment 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 31 detachedXmlComment 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 32 docfrag 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 33 foreignDocfrag 
+PASS Range 56 [docfrag, 0, docfrag, 0], node 34 xmlDocfrag 
 PASS Range 56 [docfrag, 0, docfrag, 0], node 35 doctype 
 PASS Range 56 [docfrag, 0, docfrag, 0], node 36 foreignDoctype 
 PASS Range 56 [docfrag, 0, docfrag, 0], node 37 xmlDoctype 
@@ -3474,40 +2914,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 4 foreignPara1 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 5 foreignPara1.firstChild 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 6 detachedPara1 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 7 detachedPara1.firstChild 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 8 detachedPara1 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 9 detachedPara1.firstChild 
 FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 12 detachedDiv 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 13 detachedPara2 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 14 foreignDoc 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 15 foreignPara2 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 16 xmlDoc 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 17 xmlElement 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 18 detachedXmlElement 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 19 detachedTextNode 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 20 foreignTextNode 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 21 detachedForeignTextNode 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 22 xmlTextNode 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 23 detachedXmlTextNode 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 24 processingInstruction 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 25 detachedProcessingInstruction 
 FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 27 detachedComment 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 28 foreignComment 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 29 detachedForeignComment 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 30 xmlComment 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 31 detachedXmlComment 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 32 docfrag 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 33 foreignDocfrag 
+PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 34 xmlDocfrag 
 PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 35 doctype 
 PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 36 foreignDoctype 
 PASS Range 57 [foreignDocfrag, 0, foreignDocfrag, 0], node 37 xmlDoctype 
@@ -3519,40 +2959,40 @@
 </p> but got Text node "Qrstuvwx"
 FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 3 paras[1].firstChild assert_equals: After selectAllChildren, anchorNode must be the given node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 4 foreignPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 5 foreignPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 6 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 7 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 8 detachedPara1 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 9 detachedPara1.firstChild assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 4 foreignPara1 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 5 foreignPara1.firstChild 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 6 detachedPara1 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 7 detachedPara1.firstChild 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 8 detachedPara1 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 9 detachedPara1.firstChild 
 FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 10 testDiv assert_equals: After selectAllChildren, anchorNode must be the given node expected Element node <div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id="b" s... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 11 document assert_equals: After selectAllChildren, anchorNode must be the given node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 12 detachedDiv assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 13 detachedPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 14 foreignDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 15 foreignPara2 assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 16 xmlDoc assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 17 xmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 18 detachedXmlElement assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 19 detachedTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 20 foreignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 21 detachedForeignTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 22 xmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 23 detachedXmlTextNode assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 24 processingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 25 detachedProcessingInstruction assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 12 detachedDiv 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 13 detachedPara2 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 14 foreignDoc 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 15 foreignPara2 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 16 xmlDoc 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 17 xmlElement 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 18 detachedXmlElement 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 19 detachedTextNode 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 20 foreignTextNode 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 21 detachedForeignTextNode 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 22 xmlTextNode 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 23 detachedXmlTextNode 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 24 processingInstruction 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 25 detachedProcessingInstruction 
 FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 26 comment assert_equals: After selectAllChildren, anchorNode must be the given node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 27 detachedComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 28 foreignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 29 detachedForeignComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 30 xmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 31 detachedXmlComment assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 32 docfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 33 foreignDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
-FAIL Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 34 xmlDocfrag assert_equals: After selectAllChildren, rangeCount must be 1 expected 1 but got 0
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 27 detachedComment 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 28 foreignComment 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 29 detachedForeignComment 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 30 xmlComment 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 31 detachedXmlComment 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 32 docfrag 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 33 foreignDocfrag 
+PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 34 xmlDocfrag 
 PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 35 doctype 
 PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 36 foreignDoctype 
 PASS Range 58 [xmlDocfrag, 0, xmlDocfrag, 0], node 37 xmlDoctype 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/selectAllChildren.html b/third_party/WebKit/LayoutTests/external/wpt/selection/selectAllChildren.html
index 904e0cb2..65a4ff3c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/selectAllChildren.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/selectAllChildren.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <title>Selection.selectAllChildren tests</title>
+<meta name="timeout" content="long">
 <div id=log></div>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
@@ -29,6 +30,16 @@
             }
 
             selection.selectAllChildren(node);
+            if (!document.contains(node)) {
+                if (originalRange) {
+                    assert_equals(getSelection().getRangeAt(0), originalRange,
+                        "selectAllChildren must do nothing");
+                } else {
+                    assert_equals(getSelection().rangeCount, 0,
+                        "selectAllChildren must do nothing");
+                }
+                return;
+            }
             // This implicitly tests that the selection is forwards, by using
             // anchorOffset/focusOffset instead of getRangeAt.
             assert_equals(selection.rangeCount, 1,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/setBaseAndExtent-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/selection/setBaseAndExtent-expected.txt
index 968982d..1aea996a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/setBaseAndExtent-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/setBaseAndExtent-expected.txt
@@ -23,18 +23,18 @@
 " but got Text node "Qrstuvwx"
 FAIL Reverse range 7 [paras[1].firstChild, 2, paras[1].firstChild, 9] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Ijklmnop
 " but got Text node "Qrstuvwx"
-FAIL Range 8 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Reverse range 8 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Reverse range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 10 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Reverse range 10 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Opqrstuv" but got Text node "Qrstuvwx"
-FAIL Range 11 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Reverse range 11 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Reverse range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Range 13 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
-FAIL Reverse range 13 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Efghijkl" but got Text node "Qrstuvwx"
+PASS Range 8 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] setBaseAndExtent() 
+PASS Reverse range 8 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0] setBaseAndExtent() 
+PASS Range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] setBaseAndExtent() 
+PASS Reverse range 9 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 1] setBaseAndExtent() 
+PASS Range 10 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8] setBaseAndExtent() 
+PASS Reverse range 10 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8] setBaseAndExtent() 
+PASS Range 11 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] setBaseAndExtent() 
+PASS Reverse range 11 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 0] setBaseAndExtent() 
+PASS Range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] setBaseAndExtent() 
+PASS Reverse range 12 [foreignPara1.firstChild, 0, foreignPara1.firstChild, 1] setBaseAndExtent() 
+PASS Range 13 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] setBaseAndExtent() 
+PASS Reverse range 13 [foreignPara1.firstChild, 2, foreignPara1.firstChild, 8] setBaseAndExtent() 
 FAIL Range 14 [document.documentElement, 0, document.documentElement, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <html><head><title>Selection.setBaseAndExtent() tests</ti... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Reverse range 14 [document.documentElement, 0, document.documentElement, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <html><head><title>Selection.setBaseAndExtent() tests</ti... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
@@ -56,12 +56,12 @@
 "
 FAIL Reverse range 18 [document.body, 0, document.body, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Qrstuvwx"
-FAIL Range 19 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Reverse range 19 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Qrstuvwx"
-FAIL Range 20 [foreignDoc.head, 1, foreignDoc.head, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Reverse range 20 [foreignDoc.head, 1, foreignDoc.head, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <head><title></title></head> but got Text node "Qrstuvwx"
-FAIL Range 21 [foreignDoc.body, 0, foreignDoc.body, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
-FAIL Reverse range 21 [foreignDoc.body, 0, foreignDoc.body, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
+PASS Range 19 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] setBaseAndExtent() 
+PASS Reverse range 19 [foreignDoc.documentElement, 0, foreignDoc.documentElement, 1] setBaseAndExtent() 
+PASS Range 20 [foreignDoc.head, 1, foreignDoc.head, 1] setBaseAndExtent() 
+PASS Reverse range 20 [foreignDoc.head, 1, foreignDoc.head, 1] setBaseAndExtent() 
+PASS Range 21 [foreignDoc.body, 0, foreignDoc.body, 0] setBaseAndExtent() 
+PASS Reverse range 21 [foreignDoc.body, 0, foreignDoc.body, 0] setBaseAndExtent() 
 FAIL Range 22 [paras[0], 0, paras[0], 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
@@ -74,14 +74,10 @@
 FAIL Reverse range 23 [paras[0], 0, paras[0], 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 24 [detachedPara1, 0, detachedPara1, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Reverse range 24 [detachedPara1, 0, detachedPara1, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Range 25 [detachedPara1, 0, detachedPara1, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Reverse range 25 [detachedPara1, 0, detachedPara1, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <p>Opqrstuv</p> but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 24 [detachedPara1, 0, detachedPara1, 0] setBaseAndExtent() 
+PASS Reverse range 24 [detachedPara1, 0, detachedPara1, 0] setBaseAndExtent() 
+PASS Range 25 [detachedPara1, 0, detachedPara1, 1] setBaseAndExtent() 
+PASS Reverse range 25 [detachedPara1, 0, detachedPara1, 1] setBaseAndExtent() 
 FAIL Range 26 [paras[0].firstChild, 0, paras[1].firstChild, 0] setBaseAndExtent() assert_equals: focusNode must equal the requested focus node expected Text node "Ijklmnop
 " but got Element node <p id="c">Qrstuvwx</p>
 FAIL Reverse range 26 [paras[0].firstChild, 0, paras[1].firstChild, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Ijklmnop
@@ -108,10 +104,8 @@
 FAIL Reverse range 32 [document.documentElement, 1, document.body, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <body><div id="test"><p id="a">Äb̈c̈d̈ëf̈g̈ḧ
 </p><p id... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
-FAIL Range 33 [foreignDoc.documentElement, 1, foreignDoc.body, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <html><head><title></title></head><body><p>Efghijkl</p><p... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
-FAIL Reverse range 33 [foreignDoc.documentElement, 1, foreignDoc.body, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
-"
+PASS Range 33 [foreignDoc.documentElement, 1, foreignDoc.body, 0] setBaseAndExtent() 
+PASS Reverse range 33 [foreignDoc.documentElement, 1, foreignDoc.body, 0] setBaseAndExtent() 
 FAIL Range 34 [document, 0, document, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
 "
 FAIL Reverse range 34 [document, 0, document, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Document node with 2 children but got Text node "Äb̈c̈d̈ëf̈g̈ḧ
@@ -130,42 +124,42 @@
 FAIL Reverse range 38 [paras[2].firstChild, 4, comment, 2] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
 FAIL Range 39 [paras[3], 1, comment, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <p id="d" style="display:none">Yzabcdef</p> but got Text node "Qrstuvwx"
 FAIL Reverse range 39 [paras[3], 1, comment, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--Alphabet soup?--> but got Text node "Qrstuvwx"
-FAIL Range 40 [foreignDoc, 0, foreignDoc, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Reverse range 40 [foreignDoc, 0, foreignDoc, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Range 41 [foreignDoc, 1, foreignComment, 2] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Document node with 3 children but got Text node "Qrstuvwx"
-FAIL Reverse range 41 [foreignDoc, 1, foreignComment, 2] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--"Commenter" and "commentator" mean different things.  I'v...--> but got Text node "Qrstuvwx"
-FAIL Range 42 [foreignDoc.body, 0, foreignTextNode, 36] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Element node <body><p>Efghijkl</p><p>Mnopqrst</p>I admit that I harbor... but got Text node "Qrstuvwx"
-FAIL Reverse range 42 [foreignDoc.body, 0, foreignTextNode, 36] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "I admit that I harbor doubts about whether we really need..." but got Text node "Qrstuvwx"
-FAIL Range 43 [xmlDoc, 0, xmlDoc, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Reverse range 43 [xmlDoc, 0, xmlDoc, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Range 44 [xmlDoc, 1, xmlComment, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Document node with 4 children but got Text node "Qrstuvwx"
-FAIL Reverse range 44 [xmlDoc, 1, xmlComment, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--I maliciously created a comment that will break incautiou...--> but got Text node "Qrstuvwx"
-FAIL Range 45 [detachedTextNode, 0, detachedTextNode, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Reverse range 45 [detachedTextNode, 0, detachedTextNode, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Uvwxyzab" but got Text node "Qrstuvwx"
-FAIL Range 46 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Reverse range 46 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 47 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Reverse range 47 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Cdefghij" but got Text node "Qrstuvwx"
-FAIL Range 48 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Reverse range 48 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 49 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Reverse range 49 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Text node "Klmnopqr" but got Text node "Qrstuvwx"
-FAIL Range 50 [detachedComment, 3, detachedComment, 4] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Reverse range 50 [detachedComment, 3, detachedComment, 4] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 51 [detachedComment, 5, detachedComment, 5] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Reverse range 51 [detachedComment, 5, detachedComment, 5] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--Stuvwxyz--> but got Text node "Qrstuvwx"
-FAIL Range 52 [detachedForeignComment, 0, detachedForeignComment, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Reverse range 52 [detachedForeignComment, 0, detachedForeignComment, 1] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 53 [detachedForeignComment, 4, detachedForeignComment, 4] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Reverse range 53 [detachedForeignComment, 4, detachedForeignComment, 4] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--אריה יהודה--> but got Text node "Qrstuvwx"
-FAIL Range 54 [detachedXmlComment, 2, detachedXmlComment, 6] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Reverse range 54 [detachedXmlComment, 2, detachedXmlComment, 6] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected Comment node <!--בן חיים אליעזר--> but got Text node "Qrstuvwx"
-FAIL Range 55 [docfrag, 0, docfrag, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Reverse range 55 [docfrag, 0, docfrag, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 56 [foreignDocfrag, 0, foreignDocfrag, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Reverse range 56 [foreignDocfrag, 0, foreignDocfrag, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Range 57 [xmlDocfrag, 0, xmlDocfrag, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested anchor node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
-FAIL Reverse range 57 [xmlDocfrag, 0, xmlDocfrag, 0] setBaseAndExtent() assert_equals: anchorNode must equal the requested focus node expected DocumentFragment node with 0 children but got Text node "Qrstuvwx"
+PASS Range 40 [foreignDoc, 0, foreignDoc, 0] setBaseAndExtent() 
+PASS Reverse range 40 [foreignDoc, 0, foreignDoc, 0] setBaseAndExtent() 
+PASS Range 41 [foreignDoc, 1, foreignComment, 2] setBaseAndExtent() 
+PASS Reverse range 41 [foreignDoc, 1, foreignComment, 2] setBaseAndExtent() 
+PASS Range 42 [foreignDoc.body, 0, foreignTextNode, 36] setBaseAndExtent() 
+PASS Reverse range 42 [foreignDoc.body, 0, foreignTextNode, 36] setBaseAndExtent() 
+PASS Range 43 [xmlDoc, 0, xmlDoc, 0] setBaseAndExtent() 
+PASS Reverse range 43 [xmlDoc, 0, xmlDoc, 0] setBaseAndExtent() 
+PASS Range 44 [xmlDoc, 1, xmlComment, 0] setBaseAndExtent() 
+PASS Reverse range 44 [xmlDoc, 1, xmlComment, 0] setBaseAndExtent() 
+PASS Range 45 [detachedTextNode, 0, detachedTextNode, 8] setBaseAndExtent() 
+PASS Reverse range 45 [detachedTextNode, 0, detachedTextNode, 8] setBaseAndExtent() 
+PASS Range 46 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] setBaseAndExtent() 
+PASS Reverse range 46 [detachedForeignTextNode, 7, detachedForeignTextNode, 7] setBaseAndExtent() 
+PASS Range 47 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] setBaseAndExtent() 
+PASS Reverse range 47 [detachedForeignTextNode, 0, detachedForeignTextNode, 8] setBaseAndExtent() 
+PASS Range 48 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] setBaseAndExtent() 
+PASS Reverse range 48 [detachedXmlTextNode, 7, detachedXmlTextNode, 7] setBaseAndExtent() 
+PASS Range 49 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] setBaseAndExtent() 
+PASS Reverse range 49 [detachedXmlTextNode, 0, detachedXmlTextNode, 8] setBaseAndExtent() 
+PASS Range 50 [detachedComment, 3, detachedComment, 4] setBaseAndExtent() 
+PASS Reverse range 50 [detachedComment, 3, detachedComment, 4] setBaseAndExtent() 
+PASS Range 51 [detachedComment, 5, detachedComment, 5] setBaseAndExtent() 
+PASS Reverse range 51 [detachedComment, 5, detachedComment, 5] setBaseAndExtent() 
+PASS Range 52 [detachedForeignComment, 0, detachedForeignComment, 1] setBaseAndExtent() 
+PASS Reverse range 52 [detachedForeignComment, 0, detachedForeignComment, 1] setBaseAndExtent() 
+PASS Range 53 [detachedForeignComment, 4, detachedForeignComment, 4] setBaseAndExtent() 
+PASS Reverse range 53 [detachedForeignComment, 4, detachedForeignComment, 4] setBaseAndExtent() 
+PASS Range 54 [detachedXmlComment, 2, detachedXmlComment, 6] setBaseAndExtent() 
+PASS Reverse range 54 [detachedXmlComment, 2, detachedXmlComment, 6] setBaseAndExtent() 
+PASS Range 55 [docfrag, 0, docfrag, 0] setBaseAndExtent() 
+PASS Reverse range 55 [docfrag, 0, docfrag, 0] setBaseAndExtent() 
+PASS Range 56 [foreignDocfrag, 0, foreignDocfrag, 0] setBaseAndExtent() 
+PASS Reverse range 56 [foreignDocfrag, 0, foreignDocfrag, 0] setBaseAndExtent() 
+PASS Range 57 [xmlDocfrag, 0, xmlDocfrag, 0] setBaseAndExtent() 
+PASS Reverse range 57 [xmlDocfrag, 0, xmlDocfrag, 0] setBaseAndExtent() 
 PASS setBaseAndExtent() with index larger than length 
 PASS setBaseAndExtent() with negative index 
 FAIL setBaseAndExtent() with null nodes assert_equals: focus node, got an TypeError exception expected "TypeError" but got "Error"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/selection/setBaseAndExtent.html b/third_party/WebKit/LayoutTests/external/wpt/selection/setBaseAndExtent.html
index 081c594..13108bb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/selection/setBaseAndExtent.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/selection/setBaseAndExtent.html
@@ -10,7 +10,12 @@
 for (var i = 0; i < testRanges.length; i++) {
     test(function() {
         var data = eval(testRanges[i]);
+        selection.removeAllRanges();
         selection.setBaseAndExtent(data[0], data[1], data[2], data[3]);
+        if (!document.contains(data[0]) || !document.contains(data[2])) {
+            assert_equals(selection.rangeCount, 0);
+            return;
+        }
         assert_equals(selection.rangeCount, 1,
                       "selection.rangeCount must equal 1");
         assert_equals(selection.anchorNode, data[0],
@@ -25,7 +30,12 @@
 
     test(function() {
         var data = eval(testRanges[i]);
+        selection.removeAllRanges();
         selection.setBaseAndExtent(data[2], data[3], data[0], data[1]);
+        if (!document.contains(data[0]) || !document.contains(data[2])) {
+            assert_equals(selection.rangeCount, 0);
+            return;
+        }
         assert_equals(selection.rangeCount, 1,
                       "selection.rangeCount must equal 1");
         assert_equals(selection.anchorNode, data[2],
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-basics.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-basics.https.html
similarity index 79%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-basics.html
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-basics.https.html
index 6bd8c5a..21e132d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-basics.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-basics.https.html
@@ -1,12 +1,14 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../resources/get-host-info.js"></script>
-<script src="resources/test-helpers.js"></script>
+<title>Service Worker: basic Foreign Fetch functionality</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
 <script src="resources/foreign-fetch-helpers.js"></script>
 <body>
 <script>
 var host_info = get_host_info();
+var resource_path = new URL('resources/', location).pathname;
 
 function worker_for_origins(origins) {
   var worker = 'foreign-fetch-worker.js?';
@@ -21,13 +23,11 @@
 }
 
 function intercepted_url(scope) {
-  return host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' +
-         scope + '/intercept/foo?basic';
+  return host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope + '/intercept/foo?basic';
 }
 
 function non_intercepted_url(scope) {
-  return host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' +
-         scope + '/foo?basic';
+  return host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope + '/foo?basic';
 }
 
 promise_test(t => {
@@ -89,7 +89,7 @@
 promise_test(t => {
     var scope = 'reply-to-message.html?onmessage';
     var remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+        host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
       .then(() => with_iframe(remote_url))
       .then(frame => new Promise(resolve => {
@@ -103,9 +103,9 @@
   }, 'Service Worker does not intercept navigations.');
 
 promise_test(t => {
-    var scope = 'fetch-access-control.php?fallback&ACAOrigin=*';
+    var scope = 'fetch-access-control.py?fallback&ACAOrigin=*';
     var remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+        host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
       .then(() => fetch(remote_url))
       .then(response => response.text())
@@ -113,9 +113,9 @@
   }, 'Service Worker that fallback to network should fallback to network.');
 
 promise_test(t => {
-    var scope = 'fetch-access-control.php?fetch&ACAOrigin=*';
+    var scope = 'fetch-access-control.py?fetch&ACAOrigin=*';
     var remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+        host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
       .then(() => fetch(remote_url))
       .then(response => response.text())
@@ -125,7 +125,7 @@
 promise_test(t => {
     var scope = 'simple.txt?fallback';
     var remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+        host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
       .then(() => fetch(remote_url, {mode: 'no-cors'}))
       .then(response => assert_equals(response.type, 'opaque'))
@@ -135,7 +135,7 @@
 promise_test(t => {
     var ff_scope = 'foreign-fetch/scope/controlled?basic';
     var remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + ff_scope;
+        host_info.HTTPS_REMOTE_ORIGIN + resource_path + ff_scope;
     var scope = 'resources/simple.html?fetch';
     var worker = 'resources/empty-worker.js';
     return install_cross_origin_worker(t, worker_for_scopes(['']), ff_scope)
@@ -155,7 +155,7 @@
 promise_test(t => {
     var ff_scope = 'foreign-fetch/scope/controlled?script';
     var remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + ff_scope;
+        host_info.HTTPS_REMOTE_ORIGIN + resource_path + ff_scope;
     var scope = 'resources/simple.html?script';
     var worker = 'resources/empty-worker.js';
     return install_cross_origin_worker(t, worker_for_scopes(['']), ff_scope)
@@ -180,7 +180,7 @@
 promise_test(t => {
     var scope = 'simple.txt?meta';
     var remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+        host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
       .then(() => fetch(remote_url, {mode: 'no-cors'}))
       .then(response => response.json())
@@ -203,36 +203,23 @@
         });
   }, 'Referrer and origin are set correctly in ForeignFetchEvent.');
 
-function fetch_from_iframe(origin, url) {
-  return with_iframe(origin +
-      '/serviceworker/resources/foreign-fetch-helper-iframe.html')
-    .then(frame => new Promise((resolve) => {
-        var channel = new MessageChannel();
-        frame.contentWindow.postMessage({url: url,
-                                         port: channel.port1},
-                                        '*', [channel.port1]);
-        channel.port2.onmessage = reply => resolve(reply.data);
-      }));
-}
-
 promise_test(t => {
     var scope = 'simple.txt?basic_insecure';
     var remote_url =
-        host_info.AUTHENTICATED_ORIGIN + '/serviceworker/resources/' + scope;
+        host_info.AUTHENTICATED_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, worker_for_scopes(['']), scope,
                                        host_info.AUTHENTICATED_ORIGIN)
-      .then(() => fetch_from_iframe(host_info.HTTPS_REMOTE_ORIGIN, remote_url))
+      .then(() => fetch_from_different_origin(host_info.HTTPS_REMOTE_ORIGIN, remote_url))
       .then(response => assert_equals(response, 'Success: Foreign Fetch'))
-      .then(() => fetch_from_iframe(host_info.UNAUTHENTICATED_ORIGIN,
+      .then(() => fetch_from_different_origin(host_info.UNAUTHENTICATED_ORIGIN,
                                     remote_url))
-      .then(response => assert_equals(response,
-                                      'Error: TypeError: Failed to fetch'));
+      .then(response => assert_true(response.startsWith('Error: TypeError')));
   }, 'Service Worker does not intercept fetches from an insecure context.');
 
 promise_test(t => {
-    var scope = 'fetch-access-control.php?basic&ACAOrigin=*&ACAMethods=SPECIAL';
+    var scope = 'fetch-access-control.py?basic&ACAOrigin=*&ACAMethods=SPECIAL';
     var remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+        host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
       .then(() => fetch(remote_url, {method: 'SPECIAL'}))
       .then(response => response.text())
@@ -246,7 +233,7 @@
 promise_test(t => {
   var scope = 'simple.txt?null';
   var remote_url =
-  host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+  host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
   return install_cross_origin_worker(t, worker_for_scopes(['']), scope)
     .then(() => promise_rejects(t, new TypeError(), fetch(remote_url)));
 }, 'Foreign fetch rejects if resolved with a null response.');
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-cors.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-cors.https.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-cors.html
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-cors.https.html
index c2cbc19..d4d728b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-cors.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-cors.https.html
@@ -1,8 +1,9 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../resources/get-host-info.js"></script>
-<script src="resources/test-helpers.js"></script>
+<title>Service Worker: Foreign Fetch CORS functionality</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
 <script src="resources/foreign-fetch-helpers.js"></script>
 <body>
 <script>
@@ -12,7 +13,7 @@
 var test_header = 'X-ServiceWorker-ServerHeader';
 
 function url_to_fetch(scope) {
-  return host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+  return host_info.HTTPS_REMOTE_ORIGIN + new URL('resources/', location).pathname + scope;
 }
 
 function worker_for_response(response) {
@@ -76,7 +77,8 @@
         return r.text();
       })
     .then(response_text => {
-        assert_true(response_text.startsWith('report('));
+        assert_true(response_text.startsWith('report('),
+            'Correct content via fetch');
         return self.caches.open(url);
       })
     .then(c => {
@@ -90,7 +92,8 @@
         return r.text();
       })
     .then(response_text => {
-        assert_true(response_text.startsWith('report('));
+        assert_true(response_text.startsWith('report('),
+            'Correct content via cache');
         return self.caches.delete(url);
       })
     .then(() => new Promise(resolve => {
@@ -102,7 +105,8 @@
         request.send();
       }))
     .then(xhr => {
-        assert_true(xhr.responseText.startsWith('report('));
+        assert_true(xhr.responseText.startsWith('report('),
+            'Correct content via xhr');
         assert_equals(xhr.getResponseHeader(test_header), header_value);
         var headers = xhr.getAllResponseHeaders().toLowerCase();
         if (header_value) {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-event.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-event.https.html
new file mode 100644
index 0000000..94eeda396
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-event.https.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<title>Service Worker: ForeignFetchEvent</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+service_worker_test('resources/foreign-fetch-event-worker.js',
+                    'ForeignFetchEvent constructor');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-workers.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-workers.https.html
similarity index 65%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-workers.html
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-workers.https.html
index 00da7f3..c2e5b65 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-workers.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/foreign-fetch-workers.https.html
@@ -1,13 +1,14 @@
 <!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../resources/get-host-info.js"></script>
-<script src="resources/test-helpers.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
 <script src="resources/foreign-fetch-helpers.js"></script>
 <body>
 <script>
 var host_info = get_host_info();
 var ff_worker = 'foreign-fetch-worker.js?{}';
+var resource_path = new URL('resources/', location).pathname;
 
 promise_test(t => {
     var ff_scope = 'simple.txt?basic_sw';
@@ -27,8 +28,7 @@
 
 promise_test(t => {
     let scope = 'simple.txt?basic_dedicated';
-    let remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+    let remote_url = host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, ff_worker, scope)
       .then(() => new Promise(resolve => {
           let worker = new Worker('resources/foreign-fetch-helper-script.js');
@@ -43,8 +43,7 @@
 
 promise_test(t => {
     let scope = 'simple.txt?basic_shared';
-    let remote_url =
-        host_info.HTTPS_REMOTE_ORIGIN + '/serviceworker/resources/' + scope;
+    let remote_url = host_info.HTTPS_REMOTE_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, ff_worker, scope)
       .then(() => new Promise(resolve => {
           let worker = new SharedWorker(
@@ -58,48 +57,32 @@
       .then(response => assert_equals(response, 'Success: Foreign Fetch'));
   }, 'Foreign fetch can intercept fetches made from a shared worker');
 
-function fetch_from_cross_origin_worker(worker_type, origin, url) {
-  return with_iframe(origin +
-      '/serviceworker/resources/foreign-fetch-helper-iframe.html')
-    .then(frame => new Promise((resolve) => {
-        let channel = new MessageChannel();
-        frame.contentWindow.postMessage({url: url,
-                                         port: channel.port1,
-                                         worker: worker_type},
-                                        '*', [channel.port1]);
-        channel.port2.onmessage = reply => resolve(reply.data);
-      }));
-}
-
 promise_test(t => {
     var scope = 'simple.txt?basic_dedicated_insecure';
-    var remote_url =
-        host_info.AUTHENTICATED_ORIGIN + '/serviceworker/resources/' + scope;
+    var remote_url = host_info.AUTHENTICATED_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, ff_worker, scope,
                                        host_info.AUTHENTICATED_ORIGIN)
-      .then(() => fetch_from_cross_origin_worker('dedicated',
-          host_info.HTTPS_REMOTE_ORIGIN, remote_url))
+      .then(() => fetch_from_different_origin(
+          host_info.HTTPS_REMOTE_ORIGIN, remote_url, 'dedicated'))
       .then(response => assert_equals(response, 'Success: Foreign Fetch'))
-      .then(() => fetch_from_cross_origin_worker('dedicated',
-          host_info.UNAUTHENTICATED_ORIGIN, remote_url))
+      .then(() => fetch_from_different_origin(
+          host_info.UNAUTHENTICATED_ORIGIN, remote_url, 'dedicated'))
       .then(response => assert_equals(response,
                                       'Error: TypeError: Failed to fetch'));
   }, 'Fetches from an insecure dedicated worker aren\'t intercepted.');
 
 promise_test(t => {
     var scope = 'simple.txt?basic_shared_insecure';
-    var remote_url =
-        host_info.AUTHENTICATED_ORIGIN + '/serviceworker/resources/' + scope;
+    var remote_url = host_info.AUTHENTICATED_ORIGIN + resource_path + scope;
     return install_cross_origin_worker(t, ff_worker, scope,
                                        host_info.AUTHENTICATED_ORIGIN)
-      .then(() => fetch_from_cross_origin_worker('shared',
-          host_info.HTTPS_REMOTE_ORIGIN, remote_url))
+      .then(() => fetch_from_different_origin(
+          host_info.HTTPS_REMOTE_ORIGIN, remote_url, 'shared'))
       .then(response => assert_equals(response, 'Success: Foreign Fetch'))
-      .then(() => fetch_from_cross_origin_worker('shared',
-          host_info.UNAUTHENTICATED_ORIGIN, remote_url))
+      .then(() => fetch_from_different_origin(
+          host_info.UNAUTHENTICATED_ORIGIN, remote_url, 'shared'))
       .then(response => assert_equals(response,
                                       'Error: TypeError: Failed to fetch'));
   }, 'Fetches from an insecure shared worker aren\'t intercepted.');
-
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-access-control.py b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-access-control.py
index 862718a..93ea0e0a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-access-control.py
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/fetch-access-control.py
@@ -16,7 +16,7 @@
             headers.append((header, request.GET[query]))
 
     if "ACEHeaders" in request.GET:
-        headers.append(("Access-Control-Expose-Headers", request.GET[query]))
+        headers.append(("Access-Control-Expose-Headers", request.GET["ACEHeaders"]))
 
     if ("Auth" in request.GET and not request.auth.username) or "AuthFail" in request.GET:
         status = 401
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-cors-worker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-cors-worker.js
similarity index 83%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-cors-worker.js
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-cors-worker.js
index 1b819ce..36c7b9d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-cors-worker.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-cors-worker.js
@@ -1,4 +1,4 @@
-importScripts('../../resources/get-host-info.js');
+importScripts('get-host-info.sub.js');
 var host_info = get_host_info();
 
 self.addEventListener('install', function(event) {
@@ -9,10 +9,10 @@
     var response = JSON.parse(decodeURIComponent(location.search.substring(1)));
     var url = new URL(event.request.url);
     var params = JSON.parse(decodeURIComponent(url.search.substring(1)));
-    var url_to_fetch = 'fetch-access-control.php?';
+    var url_to_fetch = 'fetch-access-control.py?';
     if (params.cross_origin) {
       url_to_fetch =
-          host_info.HTTPS_ORIGIN + '/serviceworker/resources/' + url_to_fetch;
+          host_info.HTTPS_ORIGIN + new URL('./', location).pathname + url_to_fetch;
     }
     if (params.with_aceheaders)
       url_to_fetch += 'ACEHeaders=X-ServiceWorker-ServerHeader&';
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-event-worker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-event-worker.js
similarity index 95%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-event-worker.js
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-event-worker.js
index a778ed1..63f996e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-event-worker.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-event-worker.js
@@ -28,4 +28,4 @@
 
 // Import testharness after install handler to make sure our install handler
 // runs first. Otherwise only one test will run.
-importScripts('../../resources/testharness.js');
+importScripts('/resources/testharness.js');
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helper-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helper-iframe.html
similarity index 89%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helper-iframe.html
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helper-iframe.html
index 9b94c12..722843a0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helper-iframe.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helper-iframe.html
@@ -13,4 +13,5 @@
       handle_message(e);
     }
   };
+if (self.opener) self.opener.postMessage('ready', '*');
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helper-script.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helper-script.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helper-script.js
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helper-script.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helper-worker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helper-worker.js
new file mode 100644
index 0000000..7a852cb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helper-worker.js
@@ -0,0 +1,8 @@
+importScripts('get-host-info.sub.js');
+const host_info = get_host_info();
+
+self.onfetch = e => {
+  const remote_url = host_info.HTTPS_REMOTE_ORIGIN +
+                     new URL('./', location).pathname + 'simple.txt?basic_sw';
+  e.respondWith(fetch(remote_url));
+};
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helpers.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helpers.js
new file mode 100644
index 0000000..e1831ed
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-helpers.js
@@ -0,0 +1,44 @@
+// Common helper functions for foreign fetch tests.
+
+// Installs a service worker on a different origin. Both |worker| and |scope|
+// are resolved relative to the /service-workers/service-worker/resources/
+// directory on a remote origin.
+function install_cross_origin_worker(
+    t, worker, scope, origin = get_host_info().HTTPS_REMOTE_ORIGIN) {
+  return with_iframe(origin + new URL('resources/install-worker-helper.html', location).pathname)
+    .then(frame => new Promise((resolve, reject) => {
+        frame.contentWindow.postMessage({worker: worker,
+                                         options: {scope: scope}},
+                                        '*');
+        window.addEventListener('message', reply => {
+            if (reply.source != frame.contentWindow) return;
+            if (reply.data == 'success') resolve();
+            else reject(reply.data);
+          });
+      }));
+}
+
+// Performs a fetch from a different origin. By default this performs a fetch
+// from a window on that origin, but if |worker_type| is 'dedicated' or 'shared'
+// the fetch is made from a worker on that origin instead.
+// This uses a window rather than an iframe because an iframe might get blocked
+// by mixed content checks.
+function fetch_from_different_origin(origin, url, worker_type) {
+  const win = open(origin + new URL('resources/foreign-fetch-helper-iframe.html', location).pathname);
+  return new Promise(resolve => {
+        self.addEventListener('message', e => {
+            if (e.source != win) return;
+            resolve();
+          });
+      })
+    .then(() => new Promise((resolve) => {
+        const channel = new MessageChannel();
+        win.postMessage({url: url,
+                         worker: worker_type},
+                        '*', [channel.port1]);
+        channel.port2.onmessage = reply => {
+          win.close();
+          resolve(reply.data);
+        };
+      }));
+}
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-worker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-worker.js
similarity index 100%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-worker.js
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/foreign-fetch-worker.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/get-host-info.sub.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/get-host-info.sub.js
index b64334d..e6edccf 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/get-host-info.sub.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/get-host-info.sub.js
@@ -1,19 +1,9 @@
 function get_host_info() {
-  var ORIGINAL_HOST = '127.0.0.1';
-  var REMOTE_HOST = 'localhost';
-  var UNAUTHENTICATED_HOST = 'example.test';
-  var HTTP_PORT = 8000;
-  var HTTPS_PORT = 8443;
-  try {
-    // In W3C test, we can get the hostname and port number in config.json
-    // using wptserve's built-in pipe.
-    // http://wptserve.readthedocs.org/en/latest/pipes.html#built-in-pipes
-    HTTP_PORT = eval('{{ports[http][0]}}');
-    HTTPS_PORT = eval('{{ports[https][0]}}');
-    ORIGINAL_HOST = eval('\'{{host}}\'');
-    REMOTE_HOST = 'www1.' + ORIGINAL_HOST;
-  } catch (e) {
-  }
+  const HTTP_PORT = '{{ports[http][0]}}';
+  const HTTPS_PORT = '{{ports[https][0]}}';
+  const ORIGINAL_HOST = '{{host}}';
+  const REMOTE_HOST = '{{domains[www1]}}';
+  const OTHER_HOST = '{{domains[www2]}}';
   return {
     HTTP_ORIGIN: 'http://' + ORIGINAL_HOST + ':' + HTTP_PORT,
     HTTPS_ORIGIN: 'https://' + ORIGINAL_HOST + ':' + HTTPS_PORT,
@@ -21,6 +11,7 @@
     HTTP_REMOTE_ORIGIN: 'http://' + REMOTE_HOST + ':' + HTTP_PORT,
     HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + ':' + HTTPS_PORT,
     HTTPS_REMOTE_ORIGIN_WITH_CREDS: 'https://foo:bar@' + REMOTE_HOST + ':' + HTTPS_PORT,
-    UNAUTHENTICATED_ORIGIN: 'http://' + UNAUTHENTICATED_HOST + ':' + HTTP_PORT
+    UNAUTHENTICATED_ORIGIN: 'http://' + OTHER_HOST + ':' + HTTP_PORT,
+    AUTHENTICATED_ORIGIN: 'https://' + OTHER_HOST + ':' + HTTPS_PORT
   };
 }
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/install-worker-helper.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/install-worker-helper.html
similarity index 79%
rename from third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/install-worker-helper.html
rename to third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/install-worker-helper.html
index 1de9baf..fcb8f6d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/install-worker-helper.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/install-worker-helper.html
@@ -1,8 +1,7 @@
 <!DOCTYPE html>
-<script src="test-helpers.js"></script>
+<script src="test-helpers.sub.js"></script>
 <script>
 window.addEventListener('message', event => {
-    var port = event.ports[0];
     navigator.serviceWorker.getRegistration(event.data.options.scope)
       .then(r => {
           if (r) return r.unregister();
@@ -16,7 +15,7 @@
               if (worker.state === 'activated') resolve();
             });
         }))
-      .then(() => port.postMessage('success'))
-      .catch((e) => port.postMessage('failure:' + e));
+      .then(() => event.source.postMessage('success', '*'))
+      .catch((e) => event.source.postMessage('failure:' + e, '*'));
   });
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/reply-to-message.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/reply-to-message.html
new file mode 100644
index 0000000..8a70e2a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/reply-to-message.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script>
+window.addEventListener('message', event => {
+    var port = event.ports[0];
+    port.postMessage(event.data);
+  });
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/service-worker-csp-script.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/service-worker-csp-script.https-expected.txt
deleted file mode 100644
index 5ea8e8a9..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/service-worker-csp-script.https-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS CSP test for script-src in ServiceWorkerGlobalScope 
-PASS importScripts test for script-src 
-FAIL Fetch test for script-src assert_unreached: unexpected rejection: assert_unreached: fetch should not fail. Reached unreachable code Reached unreachable code
-FAIL Redirected fetch test for script-src assert_unreached: unexpected rejection: assert_unreached: Redirected fetch should not fail. Reached unreachable code Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-expected.txt b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-expected.txt
deleted file mode 100644
index 83012e7..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-Tests that adding/removing a FontFace to/from FontFaceSet trigger font update.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS testElement.offsetWidth is arialElement.offsetWidth
-PASS addResult === document.fonts is true
-PASS testElement.offsetWidth is ahemElement.offsetWidth
-PASS testElement.offsetWidth is arialElement.offsetWidth
-PASS testElement.offsetWidth is ahemElement.offsetWidth
-PASS testElement.offsetWidth is arialElement.offsetWidth
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
-abcdefg 
-abcdefg 
-abcdefg
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-while-loading-expected.txt b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-while-loading-expected.txt
deleted file mode 100644
index 638e0268..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-while-loading-expected.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-Tests that FontFaceSet is correctly updated when added or removed a FontFace while loading.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS face1.status is "unloaded"
-PASS face1.status is "loading"
-PASS document.fonts.status is "loaded"
-PASS document.fonts.status is "loading"
-PASS face1.status is "loaded"
-PASS document.fonts.status is "loaded"
-PASS face2.status is "unloaded"
-PASS document.fonts.status is "loading"
-PASS document.fonts.status is "loading"
-PASS face2.status is "loading"
-PASS face2.status is "loaded"
-PASS document.fonts.status is "loaded"
-PASS face3.status is "unloaded"
-PASS document.fonts.status is "loading"
-PASS document.fonts.status is "loading"
-PASS face3.status is "loading"
-PASS document.fonts.status is "loaded"
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-while-loading.html b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-while-loading.html
index 3c63e88f..8cbf651 100644
--- a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-while-loading.html
+++ b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove-while-loading.html
@@ -1,69 +1,83 @@
 <!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
-<script>
-description('Tests that FontFaceSet is correctly updated when added or removed a FontFace while loading.');
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
 
-window.jsTestIsAsync = true;
+<script>
 
 function loadingDonePromise() {
-    return new Promise(function(resolve) {
-        function handler(e) {
-            document.fonts.removeEventListener('loadingdone', handler);
-            resolve(e);
-        };
-        document.fonts.addEventListener('loadingdone', handler);
-    });
+  return new Promise(function(resolve) {
+    function handler(e) {
+      document.fonts.removeEventListener('loadingdone', handler);
+      resolve(e);
+    };
+    document.fonts.addEventListener('loadingdone', handler);
+  });
 }
 
-Promise.resolve().then(function() {
-    face1 = new FontFace('face1', 'url(../../resources/Ahem.ttf)', {});
-    shouldBeEqualToString('face1.status', 'unloaded');
+promise_test(() => {
+  let face = new FontFace('face1', 'url(../../resources/Ahem.ttf)', {});
+  assert_equals(face.status, 'unloaded');
 
-    face1.load();
-    shouldBeEqualToString('face1.status', 'loading');
-    shouldBeEqualToString('document.fonts.status', 'loaded');
+  let faceLoaded = face.load();
+  assert_equals(face.status, 'loading');
+  assert_equals(document.fonts.status, 'loaded')
 
-    document.fonts.add(face1);
-    shouldBeEqualToString('document.fonts.status', 'loading');
-    return document.fonts.ready;
-}).then(function() {
-    shouldBeEqualToString('face1.status', 'loaded');
-    shouldBeEqualToString('document.fonts.status', 'loaded');
+  let loadingDone = loadingDonePromise();
+  document.fonts.add(face);
+  assert_equals(document.fonts.status, 'loading');
 
-    face2 = new FontFace('face2', 'url(../../resources/Ahem.ttf)', {});
-    shouldBeEqualToString('face2.status', 'unloaded');
+  return Promise.all(
+      [faceLoaded, loadingDone, document.fonts.ready]).then(() => {
+    assert_equals(document.fonts.status, 'loaded');
+    assert_equals(face.status, 'loaded');
+  });
+}, 'document.fonts.add() called while a FontFace is loading.');
 
-    document.fonts.add(face2);
-    var face2loaded = face2.load()
-    shouldBeEqualToString('document.fonts.status', 'loading');
+promise_test(() => {
+  assert_equals(document.fonts.status, 'loaded');
 
-    var loadingdone = loadingDonePromise();
-    document.fonts.delete(face2);
-    shouldBeEqualToString('document.fonts.status', 'loading');
-    shouldBeEqualToString('face2.status', 'loading');
+  let face = new FontFace('face2', 'url(../../resources/Ahem.ttf)', {});
+  assert_equals(face.status, 'unloaded');
 
-    return Promise.all([face2loaded, loadingdone]);
-}).then(function() {
-    shouldBeEqualToString('face2.status', 'loaded');
-    shouldBeEqualToString('document.fonts.status', 'loaded');
+  document.fonts.add(face);
+  let faceLoaded = face.load();
+  assert_equals(document.fonts.status, 'loading');
 
-    face3 = new FontFace('face3', 'url(../../resources/Ahem.ttf)', {});
-    shouldBeEqualToString('face3.status', 'unloaded');
+  let loadingDone = loadingDonePromise();
+  document.fonts.delete(face);
 
-    document.fonts.add(face3);
-    face3.load();
-    shouldBeEqualToString('document.fonts.status', 'loading');
+  // Deleting a font from the document should not change its or the document's
+  // loading status until the loadingdone event is fired.
+  assert_equals(document.fonts.status, 'loading');
+  assert_equals(face.status, 'loading');
 
-    document.fonts.clear();
-    shouldBeEqualToString('document.fonts.status', 'loading');
-    shouldBeEqualToString('face3.status', 'loading');
-    return document.fonts.ready;
-}).then(function() {
-    shouldBeEqualToString('document.fonts.status', 'loaded');
-    finishJSTest();
-}).catch(function (err) {
-    testFailed('Unexpected rejection: ' + err);
-    finishJSTest();
-});
+  return Promise.all(
+      [faceLoaded, loadingDone, document.fonts.ready]).then(() => {
+    assert_equals(document.fonts.status, 'loaded');
+    assert_equals(face.status, 'loaded');
+  });
+}, 'document.fonts.delete() called while a FontFace is loading.');
+
+promise_test(() => {
+  assert_equals(document.fonts.status, 'loaded');
+
+  let face = new FontFace('face3', 'url(../../resources/Ahem.ttf)', {});
+  assert_equals(face.status, 'unloaded');
+
+  document.fonts.add(face);
+  let faceLoaded = face.load();
+  assert_equals(document.fonts.status, 'loading');
+
+  let loadingDone = loadingDonePromise();
+  document.fonts.clear();
+  assert_equals(document.fonts.status, 'loading');
+  assert_equals(face.status, 'loading');
+
+  return Promise.all(
+      [faceLoaded, loadingDone, document.fonts.ready]).then(() => {
+    assert_equals(document.fonts.status, 'loaded');
+    assert_equals(face.status, 'loaded');
+  });
+}, 'document.fonts.clear() called while a FontFace is loading.');
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove.html b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove.html
index 4c9ae56..63d74f3 100644
--- a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove.html
+++ b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-add-remove.html
@@ -1,6 +1,6 @@
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+
 <style>
 @font-face {
     font-family: TestFont;
@@ -21,38 +21,36 @@
 }
 </style>
 <script>
-description('Tests that adding/removing a FontFace to/from FontFaceSet trigger font update.');
 
-window.jsTestIsAsync = true;
+promise_test(() => {
+  let ahemFace = new FontFace('TestFont', 'url(../../resources/Ahem.ttf)', {});
+  assert_equals(ahemFace.status, 'unloaded');
 
-function runTest() {
-    ahemFace = new FontFace('TestFont', 'url(../../resources/Ahem.ttf)', {});
-    ahemFace.load().then(verify);
-}
+  return ahemFace.load().then(() => {
+    let testElement = document.getElementById('test');
+    let arialElement = document.getElementById('arial');
+    let ahemElement = document.getElementById('ahem');
 
-function verify() {
-    testElement = document.getElementById('test');
-    arialElement = document.getElementById('arial');
-    ahemElement = document.getElementById('ahem');
+    assert_equals(testElement.offsetWidth, arialElement.offsetWidth);
 
-    shouldBe('testElement.offsetWidth', 'arialElement.offsetWidth');
     addResult = document.fonts.add(ahemFace);
-    shouldBeTrue('addResult === document.fonts');
-    shouldBe('testElement.offsetWidth', 'ahemElement.offsetWidth');
-    document.fonts.delete(ahemFace);
-    shouldBe('testElement.offsetWidth', 'arialElement.offsetWidth');
-    document.fonts.add(ahemFace);
-    shouldBe('testElement.offsetWidth', 'ahemElement.offsetWidth');
-    document.fonts.clear();
-    shouldBe('testElement.offsetWidth', 'arialElement.offsetWidth');
+    assert_equals(addResult, document.fonts);
+    assert_equals(testElement.offsetWidth, ahemElement.offsetWidth);
 
-    finishJSTest();
-}
+    document.fonts.delete(ahemFace);
+    assert_equals(testElement.offsetWidth, arialElement.offsetWidth);
+
+    document.fonts.add(ahemFace);
+    assert_equals(testElement.offsetWidth, ahemElement.offsetWidth);
+
+    document.fonts.clear();
+    assert_equals(testElement.offsetWidth, arialElement.offsetWidth);
+  });
+}, 'Tests that adding/removing a FontFace to/from a FontFaceSet triggers a ' +
+    'font update');
+
 </script>
-</head>
-<body onload="runTest()">
+
 <br><span id="test">abcdefg</span>
 <br><span id="arial">abcdefg</span>
 <br><span id="ahem">abcdefg</span>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-check-platform-fonts-expected.txt b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-check-platform-fonts-expected.txt
deleted file mode 100644
index 0ec9886..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-check-platform-fonts-expected.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-Tests FontFaceSet#check() returns true for platform fonts
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS document.fonts.check('10px Arial'); is true
-PASS document.fonts.check('10px Nonexistent'); is false
-PASS document.fonts.check('10px sans-serif'); is true
-PASS document.fonts.check('10px Nonexistent, monospace'); is true
-PASS document.fonts.check('10px Nonexistent1, Nonexistent2'); is false
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-check-platform-fonts.html b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-check-platform-fonts.html
index 3fd6289..5263db6 100644
--- a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-check-platform-fonts.html
+++ b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-check-platform-fonts.html
@@ -1,11 +1,14 @@
 <!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
 <script>
-description('Tests FontFaceSet#check() returns true for platform fonts');
 
-shouldBeTrue("document.fonts.check('10px Arial');");
-shouldBeFalse("document.fonts.check('10px Nonexistent');");
-shouldBeTrue("document.fonts.check('10px sans-serif');");
-shouldBeTrue("document.fonts.check('10px Nonexistent, monospace');");
-shouldBeFalse("document.fonts.check('10px Nonexistent1, Nonexistent2');");
+test(() => {
+  assert_true(document.fonts.check('10px Arial'));
+  assert_false(document.fonts.check('10px Nonexistent'));
+  assert_true(document.fonts.check('10px sans-serif'));
+  assert_true(document.fonts.check('10px Nonexistent, monospace'));
+  assert_false(document.fonts.check('10px Nonexistent1, Nonexistent2'));
+}, 'Tests FontFaceSet#check() returns true for platform fonts');
+
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-css-change-in-callback-expected.txt b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-css-change-in-callback-expected.txt
deleted file mode 100644
index 1a13e38..0000000
--- a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-css-change-in-callback-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Checks that adding CSS in callback of fonts.loadFont() does not cause a crash.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-css-change-in-callback.html b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-css-change-in-callback.html
index 28827ca..89cc925 100644
--- a/third_party/WebKit/LayoutTests/fast/css/fontfaceset-css-change-in-callback.html
+++ b/third_party/WebKit/LayoutTests/fast/css/fontfaceset-css-change-in-callback.html
@@ -1,36 +1,27 @@
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+
 <style>
 @font-face {
   font-family: 'ahem';
   src: url(../../resources/Ahem.ttf);
 }
 </style>
+
 <script>
-description('Checks that adding CSS in callback of fonts.loadFont() does not cause a crash.');
 
-window.jsTestIsAsync = true;
-
-function addCss() {
-    var cssText = "@font-face { font-family: 'Courier New'; src: local('Courier New') }";
-    var cssNode = document.createElement('style');
+promise_test(() => {
+  return document.fonts.load("12px ahem").then(() => {
+    let cssText = "@font-face { font-family: 'Courier New'; src: local('Courier New') }";
+    let cssNode = document.createElement('style');
     cssNode.type = 'text/css';
-    var head = document.getElementsByTagName('head')[0];
+    let head = document.getElementsByTagName('head')[0];
     head.appendChild(cssNode);
-    var cssTextNode = document.createTextNode(cssText);
+    let cssTextNode = document.createTextNode(cssText);
     cssNode.appendChild(cssTextNode);
-    finishJSTest();
-}
 
-if (document.fonts)
-    document.fonts.load("12px ahem").then(addCss);
-else {
-    testFailed('document.fonts does not exist');
-    finishJSTest();
-}
+  });
+}, 'Checks that adding CSS in callback of fonts.loadFont() does not ' +
+    'cause a crash.');
+
 </script>
-</head>
-<body>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/forms/shadow-tree-exposure-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/shadow-tree-exposure-expected.txt
index c0ad6f02..acf39a37 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/shadow-tree-exposure-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/shadow-tree-exposure-expected.txt
@@ -31,7 +31,7 @@
 PASS getSelection().baseOffset is 1
 PASS getSelection().extentNode is container
 PASS getSelection().extentOffset is 1
-PASS getSelection().type is 'Range'
+PASS getSelection().type is 'Caret'
 
 Add a textarea element.
 
@@ -49,7 +49,7 @@
 PASS getSelection().baseOffset is 2
 PASS getSelection().extentNode is container
 PASS getSelection().extentOffset is 2
-PASS getSelection().type is 'Range'
+PASS getSelection().type is 'Caret'
 
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/fast/forms/shadow-tree-exposure.html b/third_party/WebKit/LayoutTests/fast/forms/shadow-tree-exposure.html
index c1b1eb8d..0d47ee16 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/shadow-tree-exposure.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/shadow-tree-exposure.html
@@ -50,7 +50,7 @@
 shouldBe("getSelection().baseOffset", "1");
 shouldBe("getSelection().extentNode", "container");
 shouldBe("getSelection().extentOffset", "1");
-shouldBe("getSelection().type", "'Range'");
+shouldBe("getSelection().type", "'Caret'");
 
 debug("\nAdd a textarea element.\n");
 
@@ -75,7 +75,7 @@
 shouldBe("getSelection().baseOffset", "2");
 shouldBe("getSelection().extentNode", "container");
 shouldBe("getSelection().extentOffset", "2");
-shouldBe("getSelection().type", "'Range'");
+shouldBe("getSelection().type", "'Caret'");
 
 document.body.removeChild(container);
 
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/balance-line-underflow-1.html b/third_party/WebKit/LayoutTests/fast/multicol/balance-line-underflow-1.html
new file mode 100644
index 0000000..3be4115
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/balance-line-underflow-1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<p>There should be a blue square below.</p>
+<div id="multicol" data-expected-height="20" style="columns:2; width:20px; line-height:20px; background:blue;">
+    <div style="line-height:60px; margin-top:-40px;"><br></div>
+    <br>
+</div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/check-layout-th.js"></script>
+<script>
+    checkLayout("#multicol");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/balance-line-underflow-2.html b/third_party/WebKit/LayoutTests/fast/multicol/balance-line-underflow-2.html
new file mode 100644
index 0000000..e09a926
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/balance-line-underflow-2.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<p>There should be a blue square below.</p>
+<div id="multicol" data-expected-height="40" style="columns:4; width:40px; line-height:20px; background:blue;">
+    <div style="line-height:60px; margin-top:-20px;"><br></div>
+    <br>
+</div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/check-layout-th.js"></script>
+<script>
+    checkLayout("#multicol");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/span/underflow-after-spanner.html b/third_party/WebKit/LayoutTests/fast/multicol/span/underflow-after-spanner.html
new file mode 100644
index 0000000..8131a97
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/span/underflow-after-spanner.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<p>There should be a blue square below.</p>
+<div id="multicol" data-expected-height="72" style="position:relative; columns:5; column-gap:10px; width:240px; line-height:20px;">
+    <div style="height:160px;">
+        <div style="height:161px;"></div>
+        <!-- The spanner starts after 161px of column content. -->
+        <div data-offset-y="32" style="column-span:all; width:40px; height:20px; background:blue;"></div>
+        <!-- The second column row starts here, after 161px of column
+             content (the spanner doesn't count as column content). -->
+    </div>
+    <!-- The following block starts after 160px of column content. It's
+         logically after the spanner, but since offset 160px belongs to the
+         first column row, we'll first attempt to place it there. In this case
+         it's not going to fit there, since there's only 1px of space left, and
+         we have a 20px tall line to fit, so it should be pushed to the next
+         row. -->
+    <div data-offset-y="52" data-expected-height="20" style="background:blue;"><br></div>
+</div>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/check-layout-th.js"></script>
+<script>
+    checkLayout("#multicol");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-max-height-expected.txt b/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-max-height-expected.txt
new file mode 100644
index 0000000..424504e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-max-height-expected.txt
@@ -0,0 +1,4 @@
+Tests that a replaced child with percentage max-height should keep the aspect ratio when the size of its container changes.
+
+ 
+PASS
diff --git a/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-max-height.html b/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-max-height.html
new file mode 100644
index 0000000..5eeb47ca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/replaced/aspect-ratio-of-replaced-child-with-max-height.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<style>
+#container {
+  background-color: lime;
+}
+
+img, canvas {
+  max-height: 100%;
+}
+</style>
+
+<p>
+Tests that a replaced child with percentage max-height should keep the aspect
+ratio when the size of its container changes.
+</p>
+
+<div id="container">
+  <img src="resources/square-blue-100x100.png" data-expected-width="50"
+      data-expected-height="50">
+  <canvas width="400" height="400" data-expected-width="50"
+      data-expected-height="50"></canvas>
+</div>
+
+<script src="../../resources/check-layout.js"></script>
+
+<script>
+ function runTest() {
+   document.body.offsetTop;
+   var container = document.getElementById('container');
+   container.style.height = "50px";
+   document.body.offsetTop;
+   checkLayout("#container");
+ }
+window.onload = runTest;
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/text-autosizing/first-line-scale-factor-expected.html b/third_party/WebKit/LayoutTests/fast/text-autosizing/first-line-scale-factor-expected.html
index 6a9e3b0..e419276 100644
--- a/third_party/WebKit/LayoutTests/fast/text-autosizing/first-line-scale-factor-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/text-autosizing/first-line-scale-factor-expected.html
@@ -4,7 +4,7 @@
 <meta name="viewport" content="width=800">
 <style>
     html { font-size: 16px; }
-    body { width: 800px; margin: 0; overflow-y: hidden; }
+    body { width: 800px; margin: 0; overflow: hidden; }
 </style>
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/fast/workers/resources/shared-worker-usecounter-window.html b/third_party/WebKit/LayoutTests/fast/workers/resources/shared-worker-usecounter-window.html
index 399894a..ddff00c 100644
--- a/third_party/WebKit/LayoutTests/fast/workers/resources/shared-worker-usecounter-window.html
+++ b/third_party/WebKit/LayoutTests/fast/workers/resources/shared-worker-usecounter-window.html
@@ -2,10 +2,7 @@
 <title>Shared Worker: UseCounter</title>
 <script>
 self.connectToWorker = () => {
-  return new Promise(resolve => {
-    var worker = new SharedWorker('shared-worker-usecounter.js');
-    worker.port.onmessage = resolve;
-  });
+  var worker = new SharedWorker('shared-worker-usecounter.js');
 };
 window.opener.postMessage('LOADED', '*');
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/workers/resources/shared-worker-usecounter.js b/third_party/WebKit/LayoutTests/fast/workers/resources/shared-worker-usecounter.js
index 80445e5..3c01190 100644
--- a/third_party/WebKit/LayoutTests/fast/workers/resources/shared-worker-usecounter.js
+++ b/third_party/WebKit/LayoutTests/fast/workers/resources/shared-worker-usecounter.js
@@ -5,7 +5,6 @@
       internals.countFeature(e.data.feature);
     else if (e.data.type == 'COUNT_DEPRECATION')
       internals.countDeprecation(e.data.feature);
-    port.postMessage('COUNTED');
   };
   port.postMessage('CONNECTED');
 }
diff --git a/third_party/WebKit/LayoutTests/fast/workers/shared-worker-usecounter.html b/third_party/WebKit/LayoutTests/fast/workers/shared-worker-usecounter.html
index ef5fecb..51cf03c2 100644
--- a/third_party/WebKit/LayoutTests/fast/workers/shared-worker-usecounter.html
+++ b/third_party/WebKit/LayoutTests/fast/workers/shared-worker-usecounter.html
@@ -13,6 +13,10 @@
   return win.internals.isUseCounted(win.document, feature);
 }
 
+function observeUseCounter(win, feature) {
+  return win.internals.observeUseCounter(win.document, feature);
+}
+
 function openWindow(url) {
   return new Promise(resolve => {
       let win = window.open(url, '_blank');
@@ -54,14 +58,13 @@
         assert_false(isUseCounted(win2, kFeature));
 
         // Request to count a feature.
-        let promise =
-            new Promise(resolve => worker.port.onmessage = resolve);
         worker.port.postMessage({type: 'COUNT_FEATURE', feature: kFeature});
-        return promise;
+        return Promise.all([
+            observeUseCounter(win1, kFeature),
+            observeUseCounter(win2, kFeature)
+        ]);
       })
-    .then(e => {
-        assert_equals(e.data, 'COUNTED');
-
+    .then(() => {
         // API use on the SharedWorkerGlobalScope is recorded in UseCounters on
         // all connected documents.
         assert_true(isUseCounted(win1, kFeature));
@@ -71,15 +74,14 @@
         assert_false(isUseCounted(win2, kDeprecatedFeature));
 
         // Request to count a deprecated feature.
-        let promise =
-            new Promise(resolve => worker.port.onmessage = resolve);
         worker.port.postMessage(
             {type: 'COUNT_DEPRECATION', feature: kDeprecatedFeature});
-        return promise;
+        return Promise.all([
+            observeUseCounter(win1, kDeprecatedFeature),
+            observeUseCounter(win2, kDeprecatedFeature)
+        ]);
       })
-    .then(e => {
-        assert_equals(e.data, 'COUNTED');
-
+    .then(() => {
         // Deprecated API use on the SharedWorkerGlobalScope is recorded in
         // UseCounters on all connected documents.
         assert_true(isUseCounted(win1, kDeprecatedFeature));
@@ -93,7 +95,11 @@
         // not be counted yet.
         assert_false(isUseCounted(win3, kFeature));
         assert_false(isUseCounted(win3, kDeprecatedFeature));
-        return win3.connectToWorker();
+        win3.connectToWorker();
+        return Promise.all([
+            observeUseCounter(win3, kFeature),
+            observeUseCounter(win3, kDeprecatedFeature)
+        ]);
       })
     .then(() => {
         // A counter of the newly connected document should be synced with
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/resolve-relative-url-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/resolve-relative-url-expected.txt
new file mode 100644
index 0000000..af9d24d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/resolve-relative-url-expected.txt
@@ -0,0 +1,50 @@
+http://example.com/map.json === http://example.com/map.json
+http://example.com/map.json === http://example.com/map.json
+http://example.com/maps/map.json === http://example.com/maps/map.json
+Tests from http://tools.ietf.org/html/rfc3986#section-5.4 using baseURL="http://a/b/c/d;p?q"
+http://h resolves to http://h===http://h passes: true
+g resolves to http://a/b/c/g===http://a/b/c/g passes: true
+./g resolves to http://a/b/c/g===http://a/b/c/g passes: true
+g/ resolves to http://a/b/c/g/===http://a/b/c/g/ passes: true
+/g resolves to http://a/g===http://a/g passes: true
+//g resolves to http://g===http://g passes: true
+?y resolves to http://a/b/c/d;p?y===http://a/b/c/d;p?y passes: true
+g?y resolves to http://a/b/c/g?y===http://a/b/c/g?y passes: true
+#s resolves to http://a/b/c/d;p?q#s===http://a/b/c/d;p?q#s passes: true
+g#s resolves to http://a/b/c/g#s===http://a/b/c/g#s passes: true
+g?y#s resolves to http://a/b/c/g?y#s===http://a/b/c/g?y#s passes: true
+;x resolves to http://a/b/c/;x===http://a/b/c/;x passes: true
+g;x resolves to http://a/b/c/g;x===http://a/b/c/g;x passes: true
+g;x?y#s resolves to http://a/b/c/g;x?y#s===http://a/b/c/g;x?y#s passes: true
+ resolves to http://a/b/c/d;p?q===http://a/b/c/d;p?q passes: true
+. resolves to http://a/b/c/===http://a/b/c/ passes: true
+./ resolves to http://a/b/c/===http://a/b/c/ passes: true
+.. resolves to http://a/b/===http://a/b/ passes: true
+../ resolves to http://a/b/===http://a/b/ passes: true
+../g resolves to http://a/b/g===http://a/b/g passes: true
+../.. resolves to http://a/===http://a/ passes: true
+../../ resolves to http://a/===http://a/ passes: true
+../../g resolves to http://a/g===http://a/g passes: true
+../../../g resolves to http://a/g===http://a/g passes: true
+../../../../g resolves to http://a/g===http://a/g passes: true
+/./g resolves to http://a/g===http://a/g passes: true
+/../g resolves to http://a/g===http://a/g passes: true
+g. resolves to http://a/b/c/g.===http://a/b/c/g. passes: true
+.g resolves to http://a/b/c/.g===http://a/b/c/.g passes: true
+g.. resolves to http://a/b/c/g..===http://a/b/c/g.. passes: true
+..g resolves to http://a/b/c/..g===http://a/b/c/..g passes: true
+./../g resolves to http://a/b/g===http://a/b/g passes: true
+./g/. resolves to http://a/b/c/g/===http://a/b/c/g/ passes: true
+g/./h resolves to http://a/b/c/g/h===http://a/b/c/g/h passes: true
+g/../h resolves to http://a/b/c/h===http://a/b/c/h passes: true
+g;x=1/./y resolves to http://a/b/c/g;x=1/y===http://a/b/c/g;x=1/y passes: true
+g;x=1/../y resolves to http://a/b/c/y===http://a/b/c/y passes: true
+g?y/./x resolves to http://a/b/c/g?y/./x===http://a/b/c/g?y/./x passes: true
+g?y/../x resolves to http://a/b/c/g?y/../x===http://a/b/c/g?y/../x passes: true
+g#s/./x resolves to http://a/b/c/g#s/./x===http://a/b/c/g#s/./x passes: true
+g#s/../x resolves to http://a/b/c/g#s/../x===http://a/b/c/g#s/../x passes: true
+Custom completeURL tests
+//secure.com/moo resolves to http://secure.com/moo===http://secure.com/moo passes: true
+cat.jpeg resolves to http://a/b/c/cat.jpeg===http://a/b/c/cat.jpeg passes: true
+ resolves to http://example.com/path.css?query===http://example.com/path.css?query passes: true
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector-unit/resolve-relative-url.js b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/resolve-relative-url.js
new file mode 100644
index 0000000..cbde5725
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector-unit/resolve-relative-url.js
@@ -0,0 +1,61 @@
+TestRunner.addResult("http://example.com/map.json === " + Common.ParsedURL.completeURL("http://example.com/script.js", "http://example.com/map.json"));
+TestRunner.addResult("http://example.com/map.json === " + Common.ParsedURL.completeURL("http://example.com/script.js", "/map.json"));
+TestRunner.addResult("http://example.com/maps/map.json === " + Common.ParsedURL.completeURL("http://example.com/scripts/script.js", "../maps/map.json"));
+
+function testCompleteURL(base, lhs, rhs)
+{
+    var actual =  Common.ParsedURL.completeURL(base, lhs);
+    TestRunner.addResult(lhs + " resolves to " + actual + "===" + rhs + " passes: " + (actual === rhs));
+}
+
+var rfc3986_5_4_baseURL =  "http://a/b/c/d;p?q";
+TestRunner.addResult("Tests from http://tools.ietf.org/html/rfc3986#section-5.4 using baseURL=\"" + rfc3986_5_4_baseURL + "\"");
+var rfc3986_5_4 = testCompleteURL.bind(null, rfc3986_5_4_baseURL);
+rfc3986_5_4("http://h", "http://h");  // modified from RFC3986
+rfc3986_5_4("g", "http://a/b/c/g");
+rfc3986_5_4("./g", "http://a/b/c/g");
+rfc3986_5_4("g/", "http://a/b/c/g/");
+rfc3986_5_4("/g", "http://a/g");
+rfc3986_5_4("//g", "http://g");
+rfc3986_5_4("?y", "http://a/b/c/d;p?y");
+rfc3986_5_4("g?y", "http://a/b/c/g?y");
+rfc3986_5_4("#s", "http://a/b/c/d;p?q#s");
+rfc3986_5_4("g#s", "http://a/b/c/g#s");
+rfc3986_5_4("g?y#s", "http://a/b/c/g?y#s");
+rfc3986_5_4(";x", "http://a/b/c/;x");
+rfc3986_5_4("g;x", "http://a/b/c/g;x");
+rfc3986_5_4("g;x?y#s", "http://a/b/c/g;x?y#s");
+rfc3986_5_4("", "http://a/b/c/d;p?q");
+rfc3986_5_4(".", "http://a/b/c/");
+rfc3986_5_4("./", "http://a/b/c/");
+rfc3986_5_4("..", "http://a/b/");
+rfc3986_5_4("../", "http://a/b/");
+rfc3986_5_4("../g", "http://a/b/g");
+rfc3986_5_4("../..", "http://a/");
+rfc3986_5_4("../../", "http://a/");
+rfc3986_5_4("../../g", "http://a/g");
+rfc3986_5_4("../../../g", "http://a/g");
+rfc3986_5_4("../../../../g", "http://a/g");
+rfc3986_5_4("/./g", "http://a/g");
+rfc3986_5_4("/../g", "http://a/g");
+rfc3986_5_4("g." , "http://a/b/c/g.");
+rfc3986_5_4(".g" , "http://a/b/c/.g");
+rfc3986_5_4("g..", "http://a/b/c/g..");
+rfc3986_5_4("..g", "http://a/b/c/..g");
+rfc3986_5_4("./../g", "http://a/b/g");
+rfc3986_5_4("./g/.", "http://a/b/c/g/");
+rfc3986_5_4("g/./h", "http://a/b/c/g/h");
+rfc3986_5_4("g/../h", "http://a/b/c/h");
+rfc3986_5_4("g;x=1/./y", "http://a/b/c/g;x=1/y");
+rfc3986_5_4("g;x=1/../y", "http://a/b/c/y");
+rfc3986_5_4("g?y/./x", "http://a/b/c/g?y/./x");
+rfc3986_5_4("g?y/../x", "http://a/b/c/g?y/../x");
+rfc3986_5_4("g#s/./x", "http://a/b/c/g#s/./x");
+rfc3986_5_4("g#s/../x", "http://a/b/c/g#s/../x");
+
+TestRunner.addResult("Custom completeURL tests");
+testCompleteURL("http://a/b/c/d;p?q", "//secure.com/moo", "http://secure.com/moo");
+testCompleteURL("http://a/b/c/d;p?q", "cat.jpeg", "http://a/b/c/cat.jpeg");
+testCompleteURL("http://example.com/path.css?query#fragment","", "http://example.com/path.css?query");
+
+TestRunner.completeTest();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping-expected.txt
index 987ac518..c36f13b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping-expected.txt
@@ -1,118 +1,6 @@
 Tests SourceMap and CompilerScriptMapping.
 
 
-Running: testSimpleMap
-example.js === example.js
-0 === 0
-9 === 9
-example.js === example.js
-0 === 0
-13 === 13
-example.js === example.js
-0 === 0
-25 === 25
-example.js === example.js
-2 === 2
-4 === 4
-example.js === example.js
-2 === 2
-11 === 11
-example.js === example.js
-2 === 2
-24 === 24
-undefined === undefined
-undefined === undefined
-undefined === undefined
-0 === 0
-0 === 0
-0 === 0
-17 === 17
-0 === 0
-18 === 18
-source line 4 has no mappings.
-0 === 0
-29 === 29
-
-Running: testNoMappingEntry
-example.js === example.js
-0 === 0
-0 === 0
-example.js === example.js
-0 === 0
-2 === 2
-
-Running: testEmptyLine
-example.js === example.js
-0 === 0
-0 === 0
-3 === 3
-1 === 1
-
-Running: testSections
-source1.js === source1.js
-0 === 0
-0 === 0
-source1.js === source1.js
-2 === 2
-1 === 1
-source2.js === source2.js
-0 === 0
-0 === 0
-source2.js === source2.js
-2 === 2
-1 === 1
-
-Running: testResolveSourceMapURL
-http://example.com/map.json === http://example.com/map.json
-http://example.com/map.json === http://example.com/map.json
-http://example.com/maps/map.json === http://example.com/maps/map.json
-Tests from http://tools.ietf.org/html/rfc3986#section-5.4 using baseURL="http://a/b/c/d;p?q"
-http://h resolves to http://h===http://h passes: true
-g resolves to http://a/b/c/g===http://a/b/c/g passes: true
-./g resolves to http://a/b/c/g===http://a/b/c/g passes: true
-g/ resolves to http://a/b/c/g/===http://a/b/c/g/ passes: true
-/g resolves to http://a/g===http://a/g passes: true
-//g resolves to http://g===http://g passes: true
-?y resolves to http://a/b/c/d;p?y===http://a/b/c/d;p?y passes: true
-g?y resolves to http://a/b/c/g?y===http://a/b/c/g?y passes: true
-#s resolves to http://a/b/c/d;p?q#s===http://a/b/c/d;p?q#s passes: true
-g#s resolves to http://a/b/c/g#s===http://a/b/c/g#s passes: true
-g?y#s resolves to http://a/b/c/g?y#s===http://a/b/c/g?y#s passes: true
-;x resolves to http://a/b/c/;x===http://a/b/c/;x passes: true
-g;x resolves to http://a/b/c/g;x===http://a/b/c/g;x passes: true
-g;x?y#s resolves to http://a/b/c/g;x?y#s===http://a/b/c/g;x?y#s passes: true
- resolves to http://a/b/c/d;p?q===http://a/b/c/d;p?q passes: true
-. resolves to http://a/b/c/===http://a/b/c/ passes: true
-./ resolves to http://a/b/c/===http://a/b/c/ passes: true
-.. resolves to http://a/b/===http://a/b/ passes: true
-../ resolves to http://a/b/===http://a/b/ passes: true
-../g resolves to http://a/b/g===http://a/b/g passes: true
-../.. resolves to http://a/===http://a/ passes: true
-../../ resolves to http://a/===http://a/ passes: true
-../../g resolves to http://a/g===http://a/g passes: true
-../../../g resolves to http://a/g===http://a/g passes: true
-../../../../g resolves to http://a/g===http://a/g passes: true
-/./g resolves to http://a/g===http://a/g passes: true
-/../g resolves to http://a/g===http://a/g passes: true
-g. resolves to http://a/b/c/g.===http://a/b/c/g. passes: true
-.g resolves to http://a/b/c/.g===http://a/b/c/.g passes: true
-g.. resolves to http://a/b/c/g..===http://a/b/c/g.. passes: true
-..g resolves to http://a/b/c/..g===http://a/b/c/..g passes: true
-./../g resolves to http://a/b/g===http://a/b/g passes: true
-./g/. resolves to http://a/b/c/g/===http://a/b/c/g/ passes: true
-g/./h resolves to http://a/b/c/g/h===http://a/b/c/g/h passes: true
-g/../h resolves to http://a/b/c/h===http://a/b/c/h passes: true
-g;x=1/./y resolves to http://a/b/c/g;x=1/y===http://a/b/c/g;x=1/y passes: true
-g;x=1/../y resolves to http://a/b/c/y===http://a/b/c/y passes: true
-g?y/./x resolves to http://a/b/c/g?y/./x===http://a/b/c/g?y/./x passes: true
-g?y/../x resolves to http://a/b/c/g?y/../x===http://a/b/c/g?y/../x passes: true
-g#s/./x resolves to http://a/b/c/g#s/./x===http://a/b/c/g#s/./x passes: true
-g#s/../x resolves to http://a/b/c/g#s/../x===http://a/b/c/g#s/../x passes: true
-Custom completeURL tests
-//secure.com/moo resolves to http://secure.com/moo===http://secure.com/moo passes: true
-cat.jpeg resolves to http://a/b/c/cat.jpeg===http://a/b/c/cat.jpeg passes: true
- resolves to http://example.com/path.css?query===http://example.com/path.css?query passes: true
-
 Running: testCompilerScriptMapping
 Adding compiled.js
 compiled.js UISourceCode arrived
@@ -138,28 +26,3 @@
 source-map.json_ UISourceCode arrived
 debugger:///VM
 
-Running: testSourceRoot
-/example.js === /example.js
-0 === 0
-9 === 9
-0 === 0
-0 === 0
-
-Running: testNameClash
-example.js === example.js [sm]
-0 === 0
-9 === 9
-source line 0 has no mappings.
-
-Running: testNameIndexes
-1:0 > [no name assigned]
-3:0 > [no name assigned]
-3:18 > [no name assigned]
-3:4 > 'name1'
-4:0 > [no name assigned]
-4:0 > [no name assigned]
-4:4 > 'generated31465'
-4:27 > [no name assigned]
-5:0 > [no name assigned]
-5:0 > [no name assigned]
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
index 9b3b58f8..849ebfc7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/compiler-script-mapping.html
@@ -14,25 +14,6 @@
 
 function test()
 {
-    function checkMapping(compiledLineNumber, compiledColumnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, mapping)
-    {
-        var entry = mapping.findEntry(compiledLineNumber, compiledColumnNumber);
-        InspectorTest.addResult(sourceURL + " === " + entry.sourceURL);
-        InspectorTest.addResult(sourceLineNumber + " === " + entry.sourceLineNumber);
-        InspectorTest.addResult(sourceColumnNumber + " === " + entry.sourceColumnNumber);
-    }
-
-    function checkReverseMapping(compiledLineNumber, compiledColumnNumber, sourceURL, sourceLineNumber, mapping)
-    {
-        var entry = mapping.firstSourceLineMapping(sourceURL, sourceLineNumber);
-        if (!entry) {
-            InspectorTest.addResult("source line " + sourceLineNumber + " has no mappings.");
-            return;
-        }
-        InspectorTest.addResult(compiledLineNumber + " === " + entry.lineNumber);
-        InspectorTest.addResult(compiledColumnNumber + " === " + entry.columnNumber);
-    }
-
     function uiLocation(script, line, column)
     {
         var location = script.debuggerModel.createRawLocation(script, line, column);
@@ -40,164 +21,6 @@
     }
 
     InspectorTest.runTestSuite([
-        function testSimpleMap(next)
-        {
-            /*
-                example.js:
-                0         1         2         3
-                012345678901234567890123456789012345
-                function add(variable_x, variable_y)
-                {
-                    return variable_x + variable_y;
-                }
-
-                var global = "foo";
-                ----------------------------------------
-                example-compiled.js:
-                0         1         2         3
-                012345678901234567890123456789012345
-                function add(a,b){return a+b}var global="foo";
-                foo
-            */
-            var mappingPayload = {
-                "mappings":"AAASA,QAAAA,IAAG,CAACC,CAAD,CAAaC,CAAb,CACZ,CACI,MAAOD,EAAP,CAAoBC,CADxB,CAIA,IAAIC,OAAS;A",
-                "sources":["example.js"]
-            };
-            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
-
-            checkMapping(0, 9, "example.js", 0, 9, mapping);
-            checkMapping(0, 13, "example.js", 0, 13, mapping);
-            checkMapping(0, 15, "example.js", 0, 25, mapping);
-            checkMapping(0, 18, "example.js", 2, 4, mapping);
-            checkMapping(0, 25, "example.js", 2, 11, mapping);
-            checkMapping(0, 27, "example.js", 2, 24, mapping);
-            checkMapping(1, 0, undefined, undefined, undefined, mapping);
-
-            checkReverseMapping(0, 0, "example.js", 0, mapping);
-            checkReverseMapping(0, 17, "example.js", 1, mapping);
-            checkReverseMapping(0, 18, "example.js", 2, mapping);
-            checkReverseMapping(0, 29, "example.js", 4, mapping);
-            checkReverseMapping(0, 29, "example.js", 5, mapping);
-
-            next();
-        },
-
-        function testNoMappingEntry(next)
-        {
-            var mappingPayload = {
-                "mappings":"AAAA,C,CAAE;",
-                "sources":["example.js"]
-            };
-            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
-            checkMapping(0, 0, "example.js", 0, 0, mapping);
-            var entry = mapping.findEntry(0, 1);
-            InspectorTest.assertTrue(!entry.sourceURL);
-            checkMapping(0, 2, "example.js", 0, 2, mapping);
-            next();
-        },
-
-        function testEmptyLine(next)
-        {
-            var mappingPayload = {
-                "mappings":"AAAA;;;CACA",
-                "sources":["example.js"]
-            };
-            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
-            checkMapping(0, 0, "example.js", 0, 0, mapping);
-            checkReverseMapping(3, 1, "example.js", 1, mapping);
-            next();
-        },
-
-        function testSections(next)
-        {
-            var mappingPayload = {
-                "sections": [{
-                    "offset": { "line": 0, "column": 0 },
-                    "map": {
-                        "mappings":"AAAA,CAEC",
-                        "sources":["source1.js", "source2.js"]
-                    }
-                }, {
-                    "offset": { "line": 2, "column": 10 },
-                    "map": {
-                        "mappings":"AAAA,CAEC",
-                        "sources":["source2.js"]
-                    }
-                }
-            ]};
-            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
-            InspectorTest.assertEquals(2, mapping.sourceURLs().length);
-            checkMapping(0, 0, "source1.js", 0, 0, mapping);
-            checkMapping(0, 1, "source1.js", 2, 1, mapping);
-            checkMapping(2, 10, "source2.js", 0, 0, mapping);
-            checkMapping(2, 11, "source2.js", 2, 1, mapping);
-            next();
-        },
-
-        function testResolveSourceMapURL(next)
-        {
-            var func = Common.ParsedURL.completeURL;
-            InspectorTest.addResult("http://example.com/map.json === " + func("http://example.com/script.js", "http://example.com/map.json"));
-            InspectorTest.addResult("http://example.com/map.json === " + func("http://example.com/script.js", "/map.json"));
-            InspectorTest.addResult("http://example.com/maps/map.json === " + func("http://example.com/scripts/script.js", "../maps/map.json"));
-            function testCompleteURL(base, lhs, rhs)
-            {
-                var actual =  Common.ParsedURL.completeURL(base, lhs);
-                InspectorTest.addResult(lhs + " resolves to " + actual + "===" + rhs + " passes: " + (actual === rhs));
-            }
-
-            var rfc3986_5_4_baseURL =  "http://a/b/c/d;p?q";
-            InspectorTest.addResult("Tests from http://tools.ietf.org/html/rfc3986#section-5.4 using baseURL=\"" + rfc3986_5_4_baseURL + "\"");
-            var rfc3986_5_4 = testCompleteURL.bind(null, rfc3986_5_4_baseURL);
-            rfc3986_5_4("http://h", "http://h");  // modified from RFC3986
-            rfc3986_5_4("g", "http://a/b/c/g");
-            rfc3986_5_4("./g", "http://a/b/c/g");
-            rfc3986_5_4("g/", "http://a/b/c/g/");
-            rfc3986_5_4("/g", "http://a/g");
-            rfc3986_5_4("//g", "http://g");
-            rfc3986_5_4("?y", "http://a/b/c/d;p?y");
-            rfc3986_5_4("g?y", "http://a/b/c/g?y");
-            rfc3986_5_4("#s", "http://a/b/c/d;p?q#s");
-            rfc3986_5_4("g#s", "http://a/b/c/g#s");
-            rfc3986_5_4("g?y#s", "http://a/b/c/g?y#s");
-            rfc3986_5_4(";x", "http://a/b/c/;x");
-            rfc3986_5_4("g;x", "http://a/b/c/g;x");
-            rfc3986_5_4("g;x?y#s", "http://a/b/c/g;x?y#s");
-            rfc3986_5_4("", "http://a/b/c/d;p?q");
-            rfc3986_5_4(".", "http://a/b/c/");
-            rfc3986_5_4("./", "http://a/b/c/");
-            rfc3986_5_4("..", "http://a/b/");
-            rfc3986_5_4("../", "http://a/b/");
-            rfc3986_5_4("../g", "http://a/b/g");
-            rfc3986_5_4("../..", "http://a/");
-            rfc3986_5_4("../../", "http://a/");
-            rfc3986_5_4("../../g", "http://a/g");
-            rfc3986_5_4("../../../g", "http://a/g");
-            rfc3986_5_4("../../../../g", "http://a/g");
-            rfc3986_5_4("/./g", "http://a/g");
-            rfc3986_5_4("/../g", "http://a/g");
-            rfc3986_5_4("g." , "http://a/b/c/g.");
-            rfc3986_5_4(".g" , "http://a/b/c/.g");
-            rfc3986_5_4("g..", "http://a/b/c/g..");
-            rfc3986_5_4("..g", "http://a/b/c/..g");
-            rfc3986_5_4("./../g", "http://a/b/g");
-            rfc3986_5_4("./g/.", "http://a/b/c/g/");
-            rfc3986_5_4("g/./h", "http://a/b/c/g/h");
-            rfc3986_5_4("g/../h", "http://a/b/c/h");
-            rfc3986_5_4("g;x=1/./y", "http://a/b/c/g;x=1/y");
-            rfc3986_5_4("g;x=1/../y", "http://a/b/c/y");
-            rfc3986_5_4("g?y/./x", "http://a/b/c/g?y/./x");
-            rfc3986_5_4("g?y/../x", "http://a/b/c/g?y/../x");
-            rfc3986_5_4("g#s/./x", "http://a/b/c/g#s/./x");
-            rfc3986_5_4("g#s/../x", "http://a/b/c/g#s/../x");
-
-            InspectorTest.addResult("Custom completeURL tests");
-            testCompleteURL("http://a/b/c/d;p?q", "//secure.com/moo", "http://secure.com/moo");
-            testCompleteURL("http://a/b/c/d;p?q", "cat.jpeg", "http://a/b/c/cat.jpeg");
-            testCompleteURL("http://example.com/path.css?query#fragment","", "http://example.com/path.css?query");
-            next();
-        },
-
         function testCompilerScriptMapping(next)
         {
             var script;
@@ -340,92 +163,6 @@
                 console.error = consoleError;
                 next();
             }
-        },
-
-        function testSourceRoot(next)
-        {
-            /*
-                example.js:
-                0         1         2         3
-                012345678901234567890123456789012345
-                function add(variable_x, variable_y)
-                {
-                    return variable_x + variable_y;
-                }
-
-                var global = "foo";
-                ----------------------------------------
-                example-compiled.js:
-                0         1         2         3
-                012345678901234567890123456789012345
-                function add(a,b){return a+b}var global="foo";
-            */
-            var mappingPayload = {
-                "mappings":"AAASA,QAAAA,IAAG,CAACC,CAAD,CAAaC,CAAb,CACZ,CACI,MAAOD,EAAP,CAAoBC,CADxB,CAIA,IAAIC,OAAS;",
-                "sources":["example.js"],
-                "sourceRoot":"/"
-            };
-            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
-            checkMapping(0, 9, "/example.js", 0, 9, mapping);
-            checkReverseMapping(0, 0, "/example.js", 0, mapping);
-            next();
-        },
-
-        function testNameClash(next)
-        {
-            var mappingPayload = {
-                "mappings":"AAASA,QAAAA,IAAG,CAACC,CAAD,CAAaC,CAAb,CACZ,CACI,MAAOD,EAAP,CAAoBC,CADxB,CAIA,IAAIC,OAAS;",
-                "sources":["example.js"],
-                "sourcesContent":["var i = 0;"]
-            };
-            var mapping = new SDK.TextSourceMap("example.js", "source-map.json",mappingPayload);
-            checkMapping(0, 9, "example.js", 0, 9, mapping);
-            checkReverseMapping(0, 0, "example.js", 0, mapping);
-            next();
-        },
-
-        function testNameIndexes(next)
-        {
-            /*
-               ------------------------------------------------------------------------------------
-               chrome_issue_611738.clj:
-               (ns devtools-sample.chrome-issue-611738)
-
-               (defmacro m []
-                 `(let [generated# "value2"]))
-               ------------------------------------------------------------------------------------
-               chrome_issue_611738.cljs:
-               (ns devtools-sample.chrome-issue-611738
-               (:require-macros [devtools-sample.chrome-issue-611738 :refer [m]]))
-
-               (let [name1 "value1"]
-                 (m))
-               ------------------------------------------------------------------------------------
-               chrome_issue_611738.js:
-               // Compiled by ClojureScript 1.9.89 {}
-               goog.provide('devtools_sample.chrome_issue_611738');
-               goog.require('cljs.core');
-               var name1_31466 = "value1";
-               var generated31465_31467 = "value2";
-
-               //# sourceMappingURL=chrome_issue_611738.js.map
-               ------------------------------------------------------------------------------------
-               chrome_issue_611738.js.map:
-               {"version":3,"file":"\/Users\/darwin\/code\/cljs-devtools-sample\/resources\/public\/_compiled\/demo\/devtools_sample\/chrome_issue_611738.js","sources":["chrome_issue_611738.cljs"],"lineCount":7,"mappings":";AAAA;;AAGA,kBAAA,dAAMA;AAAN,AACE,IAAAC,uBAAA;AAAA,AAAA","names":["name1","generated31465"]}
-               ------------------------------------------------------------------------------------
-             */
-
-            var mappingPayload = {
-                "sources": ["chrome_issue_611738.cljs"],
-                "mappings": ";AAAA;;AAGA,kBAAA,dAAMA;AAAN,AACE,IAAAC,uBAAA;AAAA,AAAA",
-                "names": ["name1", "generated31465"]
-            };
-            var mapping = new SDK.TextSourceMap("chrome_issue_611738.js", "chrome_issue_611738.js.map", mappingPayload);
-            mapping.mappings().forEach(function(entry) {
-                const name = entry.name ? "'" + entry.name + "'" : "[no name assigned]";
-                InspectorTest.addResult(entry.lineNumber + ":" + entry.columnNumber + " > " + name);
-            });
-            next();
         }
     ]);
 };
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker-expected.txt
index cb9f3837..3eb2b38 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker-expected.txt
@@ -9,7 +9,7 @@
 Dumping listeners
 
 ======== load ========
-== normal
+== Raw
 [expanded] WindowRemoveevent-listeners-framework-with-service-worker.html:59
     useCapture: false
     passive: false
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
index b1cbc88..1a32e8c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -345,7 +345,7 @@
             InspectorTest.addResult("======== " + eventType + " ========");
             var listenerItems = listenerTypes[i].children();
             for (var j = 0; j < listenerItems.length; ++j) {
-                InspectorTest.addResult("== " + listenerItems[j].eventListener().listenerType());
+                InspectorTest.addResult("== " + listenerItems[j].eventListener().origin());
                 InspectorTest.dumpObjectPropertyTreeElement(listenerItems[j]);
             }
         }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-blocked-reason.html b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-blocked-reason.html
index 56541d8..53e58845 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-blocked-reason.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network/network-blocked-reason.html
@@ -22,7 +22,7 @@
 {
     var requestName;
     var nextStep;
-    var blockedSetting = Common.settingForTest("blockedURLs");
+    var blockedSetting = Common.settingForTest("networkBlockedURLs");
 
     function onRequest(event)
     {
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/text-source-map-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/text-source-map-expected.txt
new file mode 100644
index 0000000..9e7dc41
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/text-source-map-expected.txt
@@ -0,0 +1,89 @@
+Verify TextSourceMap implementation
+
+
+Running: testSimpleMap
+example.js === example.js
+0 === 0
+9 === 9
+example.js === example.js
+0 === 0
+13 === 13
+example.js === example.js
+0 === 0
+25 === 25
+example.js === example.js
+2 === 2
+4 === 4
+example.js === example.js
+2 === 2
+11 === 11
+example.js === example.js
+2 === 2
+24 === 24
+undefined === undefined
+undefined === undefined
+undefined === undefined
+0 === 0
+0 === 0
+0 === 0
+17 === 17
+0 === 0
+18 === 18
+source line 4 has no mappings.
+0 === 0
+29 === 29
+
+Running: testNoMappingEntry
+example.js === example.js
+0 === 0
+0 === 0
+example.js === example.js
+0 === 0
+2 === 2
+
+Running: testEmptyLine
+example.js === example.js
+0 === 0
+0 === 0
+3 === 3
+1 === 1
+
+Running: testSections
+source1.js === source1.js
+0 === 0
+0 === 0
+source1.js === source1.js
+2 === 2
+1 === 1
+source2.js === source2.js
+0 === 0
+0 === 0
+source2.js === source2.js
+2 === 2
+1 === 1
+
+Running: testSourceRoot
+/example.js === /example.js
+0 === 0
+9 === 9
+0 === 0
+0 === 0
+
+Running: testNameClash
+example.js === example.js [sm]
+0 === 0
+9 === 9
+source line 0 has no mappings.
+
+Running: testNameIndexes
+1:0 > [no name assigned]
+3:0 > [no name assigned]
+3:18 > [no name assigned]
+3:4 > 'name1'
+4:0 > [no name assigned]
+4:0 > [no name assigned]
+4:4 > 'generated31465'
+4:27 > [no name assigned]
+5:0 > [no name assigned]
+5:0 > [no name assigned]
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/text-source-map.html b/third_party/WebKit/LayoutTests/http/tests/inspector/text-source-map.html
new file mode 100644
index 0000000..2e5f1f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/text-source-map.html
@@ -0,0 +1,219 @@
+<html>
+<head>
+<script src="inspector-test.js"></script>
+<script src="debugger-test.js"></script>
+
+<script>
+
+function test()
+{
+    function checkMapping(compiledLineNumber, compiledColumnNumber, sourceURL, sourceLineNumber, sourceColumnNumber, mapping)
+    {
+        var entry = mapping.findEntry(compiledLineNumber, compiledColumnNumber);
+        InspectorTest.addResult(sourceURL + " === " + entry.sourceURL);
+        InspectorTest.addResult(sourceLineNumber + " === " + entry.sourceLineNumber);
+        InspectorTest.addResult(sourceColumnNumber + " === " + entry.sourceColumnNumber);
+    }
+
+    function checkReverseMapping(compiledLineNumber, compiledColumnNumber, sourceURL, sourceLineNumber, mapping)
+    {
+        var entry = mapping.firstSourceLineMapping(sourceURL, sourceLineNumber);
+        if (!entry) {
+            InspectorTest.addResult("source line " + sourceLineNumber + " has no mappings.");
+            return;
+        }
+        InspectorTest.addResult(compiledLineNumber + " === " + entry.lineNumber);
+        InspectorTest.addResult(compiledColumnNumber + " === " + entry.columnNumber);
+    }
+
+    InspectorTest.runTestSuite([
+        function testSimpleMap(next)
+        {
+            /*
+                example.js:
+                0         1         2         3
+                012345678901234567890123456789012345
+                function add(variable_x, variable_y)
+                {
+                    return variable_x + variable_y;
+                }
+
+                var global = "foo";
+                ----------------------------------------
+                example-compiled.js:
+                0         1         2         3
+                012345678901234567890123456789012345
+                function add(a,b){return a+b}var global="foo";
+                foo
+            */
+            var mappingPayload = {
+                "mappings":"AAASA,QAAAA,IAAG,CAACC,CAAD,CAAaC,CAAb,CACZ,CACI,MAAOD,EAAP,CAAoBC,CADxB,CAIA,IAAIC,OAAS;A",
+                "sources":["example.js"]
+            };
+            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
+
+            checkMapping(0, 9, "example.js", 0, 9, mapping);
+            checkMapping(0, 13, "example.js", 0, 13, mapping);
+            checkMapping(0, 15, "example.js", 0, 25, mapping);
+            checkMapping(0, 18, "example.js", 2, 4, mapping);
+            checkMapping(0, 25, "example.js", 2, 11, mapping);
+            checkMapping(0, 27, "example.js", 2, 24, mapping);
+            checkMapping(1, 0, undefined, undefined, undefined, mapping);
+
+            checkReverseMapping(0, 0, "example.js", 0, mapping);
+            checkReverseMapping(0, 17, "example.js", 1, mapping);
+            checkReverseMapping(0, 18, "example.js", 2, mapping);
+            checkReverseMapping(0, 29, "example.js", 4, mapping);
+            checkReverseMapping(0, 29, "example.js", 5, mapping);
+
+            next();
+        },
+
+        function testNoMappingEntry(next)
+        {
+            var mappingPayload = {
+                "mappings":"AAAA,C,CAAE;",
+                "sources":["example.js"]
+            };
+            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
+            checkMapping(0, 0, "example.js", 0, 0, mapping);
+            var entry = mapping.findEntry(0, 1);
+            InspectorTest.assertTrue(!entry.sourceURL);
+            checkMapping(0, 2, "example.js", 0, 2, mapping);
+            next();
+        },
+
+        function testEmptyLine(next)
+        {
+            var mappingPayload = {
+                "mappings":"AAAA;;;CACA",
+                "sources":["example.js"]
+            };
+            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
+            checkMapping(0, 0, "example.js", 0, 0, mapping);
+            checkReverseMapping(3, 1, "example.js", 1, mapping);
+            next();
+        },
+
+        function testSections(next)
+        {
+            var mappingPayload = {
+                "sections": [{
+                    "offset": { "line": 0, "column": 0 },
+                    "map": {
+                        "mappings":"AAAA,CAEC",
+                        "sources":["source1.js", "source2.js"]
+                    }
+                }, {
+                    "offset": { "line": 2, "column": 10 },
+                    "map": {
+                        "mappings":"AAAA,CAEC",
+                        "sources":["source2.js"]
+                    }
+                }
+            ]};
+            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
+            InspectorTest.assertEquals(2, mapping.sourceURLs().length);
+            checkMapping(0, 0, "source1.js", 0, 0, mapping);
+            checkMapping(0, 1, "source1.js", 2, 1, mapping);
+            checkMapping(2, 10, "source2.js", 0, 0, mapping);
+            checkMapping(2, 11, "source2.js", 2, 1, mapping);
+            next();
+        },
+
+        function testSourceRoot(next)
+        {
+            /*
+                example.js:
+                0         1         2         3
+                012345678901234567890123456789012345
+                function add(variable_x, variable_y)
+                {
+                    return variable_x + variable_y;
+                }
+
+                var global = "foo";
+                ----------------------------------------
+                example-compiled.js:
+                0         1         2         3
+                012345678901234567890123456789012345
+                function add(a,b){return a+b}var global="foo";
+            */
+            var mappingPayload = {
+                "mappings":"AAASA,QAAAA,IAAG,CAACC,CAAD,CAAaC,CAAb,CACZ,CACI,MAAOD,EAAP,CAAoBC,CADxB,CAIA,IAAIC,OAAS;",
+                "sources":["example.js"],
+                "sourceRoot":"/"
+            };
+            var mapping = new SDK.TextSourceMap("compiled.js", "source-map.json", mappingPayload);
+            checkMapping(0, 9, "/example.js", 0, 9, mapping);
+            checkReverseMapping(0, 0, "/example.js", 0, mapping);
+            next();
+        },
+
+        function testNameClash(next)
+        {
+            var mappingPayload = {
+                "mappings":"AAASA,QAAAA,IAAG,CAACC,CAAD,CAAaC,CAAb,CACZ,CACI,MAAOD,EAAP,CAAoBC,CADxB,CAIA,IAAIC,OAAS;",
+                "sources":["example.js"],
+                "sourcesContent":["var i = 0;"]
+            };
+            var mapping = new SDK.TextSourceMap("example.js", "source-map.json",mappingPayload);
+            checkMapping(0, 9, "example.js", 0, 9, mapping);
+            checkReverseMapping(0, 0, "example.js", 0, mapping);
+            next();
+        },
+
+        function testNameIndexes(next)
+        {
+            /*
+               ------------------------------------------------------------------------------------
+               chrome_issue_611738.clj:
+               (ns devtools-sample.chrome-issue-611738)
+
+               (defmacro m []
+                 `(let [generated# "value2"]))
+               ------------------------------------------------------------------------------------
+               chrome_issue_611738.cljs:
+               (ns devtools-sample.chrome-issue-611738
+               (:require-macros [devtools-sample.chrome-issue-611738 :refer [m]]))
+
+               (let [name1 "value1"]
+                 (m))
+               ------------------------------------------------------------------------------------
+               chrome_issue_611738.js:
+               // Compiled by ClojureScript 1.9.89 {}
+               goog.provide('devtools_sample.chrome_issue_611738');
+               goog.require('cljs.core');
+               var name1_31466 = "value1";
+               var generated31465_31467 = "value2";
+
+               //# sourceMappingURL=chrome_issue_611738.js.map
+               ------------------------------------------------------------------------------------
+               chrome_issue_611738.js.map:
+               {"version":3,"file":"\/Users\/darwin\/code\/cljs-devtools-sample\/resources\/public\/_compiled\/demo\/devtools_sample\/chrome_issue_611738.js","sources":["chrome_issue_611738.cljs"],"lineCount":7,"mappings":";AAAA;;AAGA,kBAAA,dAAMA;AAAN,AACE,IAAAC,uBAAA;AAAA,AAAA","names":["name1","generated31465"]}
+               ------------------------------------------------------------------------------------
+             */
+
+            var mappingPayload = {
+                "sources": ["chrome_issue_611738.cljs"],
+                "mappings": ";AAAA;;AAGA,kBAAA,dAAMA;AAAN,AACE,IAAAC,uBAAA;AAAA,AAAA",
+                "names": ["name1", "generated31465"]
+            };
+            var mapping = new SDK.TextSourceMap("chrome_issue_611738.js", "chrome_issue_611738.js.map", mappingPayload);
+            mapping.mappings().forEach(function(entry) {
+                const name = entry.name ? "'" + entry.name + "'" : "[no name assigned]";
+                InspectorTest.addResult(entry.lineNumber + ":" + entry.columnNumber + " > " + name);
+            });
+            next();
+        }
+    ]);
+};
+
+</script>
+
+</head>
+
+<body onload="runTest()">
+<p>Verify TextSourceMap implementation</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
index 9ef1231..75c0022 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
@@ -99,7 +99,7 @@
 
     function onPageActionsDone()
     {
-        InspectorTest.addSniffer(UI.panels.timeline, "loadingComplete", callback)
+        InspectorTest.runWhenTimelineIsReady(callback);
         timelineController.stopRecording();
     }
 }
@@ -136,6 +136,11 @@
     return new Timeline.TimelineController(SDK.targetManager.mainTarget(), performanceModel, UI.panels.timeline);
 }
 
+InspectorTest.runWhenTimelineIsReady = function(callback)
+{
+    InspectorTest.addSniffer(UI.panels.timeline, "loadingComplete", () => callback());
+}
+
 InspectorTest.startTimeline = function(callback)
 {
     var panel = UI.panels.timeline;
@@ -145,13 +150,8 @@
 
 InspectorTest.stopTimeline = function(callback)
 {
-    var panel = UI.panels.timeline;
-    function didStop()
-    {
-        InspectorTest.deprecatedRunAfterPendingDispatches(callback);
-    }
-    InspectorTest.addSniffer(panel, "loadingComplete", didStop);
-    panel._toggleRecording();
+    InspectorTest.runWhenTimelineIsReady(callback);
+    UI.panels.timeline._toggleRecording();
 };
 
 InspectorTest.evaluateWithTimeline = function(actions, doneCallback)
@@ -420,7 +420,9 @@
     }
 
     InspectorTest.override(Timeline.TimelineLoader, "_createFileReader", createFileReader);
+    var promise = new Promise(fulfill => InspectorTest.runWhenTimelineIsReady(fulfill));
     timeline._loadFromFile({});
+    return promise;
 }
 
 };
diff --git a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt b/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt
deleted file mode 100644
index 8ffee0ef..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CONSOLE MESSAGE: line 15: Interfaces in document
-interface PerformanceLongTaskTiming
-    getter attribution
-    method constructor
-This is a testharness.js-based test.
-PASS LongTaskObserver related interfaces in Origin-Trial enabled document. 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt b/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt
deleted file mode 100644
index 85a4c33..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-CONSOLE MESSAGE: line 15: Interfaces before adding trial token
-interface PerformanceLongTaskTiming
-    getter attribution
-    method constructor
-CONSOLE MESSAGE: line 23: Interfaces after adding trial token
-interface PerformanceLongTaskTiming
-    getter attribution
-    method constructor
-This is a testharness.js-based test.
-PASS LongTaskObserver related interfaces before adding trial token via script. 
-PASS LongTaskObserver related interfaces after adding trial token via script. 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added.html b/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added.html
deleted file mode 100644
index 3a915ae2..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>LongTaskObserver - origin trial is enabled by script-added meta tag</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/origin-trials-helper.js"></script>
-<script>
-// Generate token with the command:
-// generate_token.py  http://127.0.0.1:8000 LongTaskObserver --expire-timestamp=2000000000
-var token = "AjpM/J+Oaon2wm/Ige8C0M00AhbG4U3Q1nAAmsNxmDTB/FTgFHfMYk2aVJozhE7m0dlJhozhaPh7C+GM6KD+QgYAAABYeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiTG9uZ1Rhc2tPYnNlcnZlciIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==";
-
-test(t => {
-  var interfaces =
-      OriginTrialsHelper.get_interface_names(window, ['PerformanceLongTaskTiming']);
-  console.log('Interfaces before adding trial token\n' + interfaces);
-}, "LongTaskObserver related interfaces before adding trial token via script.");
-
-OriginTrialsHelper.add_token(token);
-
-test(t => {
-  var interfaces =
-      OriginTrialsHelper.get_interface_names(window, ['PerformanceLongTaskTiming']);
-  console.log('Interfaces after adding trial token\n' + interfaces);
-}, "LongTaskObserver related interfaces after adding trial token via script.");
-</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces.html b/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces.html
deleted file mode 100644
index 1711078de..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<!-- Generate token with the command:
-generate_token.py  http://127.0.0.1:8000 LongTaskObserver --expire-timestamp=2000000000
--->
-<meta http-equiv="origin-trial" content="AjpM/J+Oaon2wm/Ige8C0M00AhbG4U3Q1nAAmsNxmDTB/FTgFHfMYk2aVJozhE7m0dlJhozhaPh7C+GM6KD+QgYAAABYeyJvcmlnaW4iOiAiaHR0cDovLzEyNy4wLjAuMTo4MDAwIiwgImZlYXR1cmUiOiAiTG9uZ1Rhc2tPYnNlcnZlciIsICJleHBpcnkiOiAyMDAwMDAwMDAwfQ==" />
-<title>LongTaskObserver - interfaces exposed by origin trial</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/origin-trials-helper.js"></script>
-<script>
-test(t => {
-  var interfaces =
-      OriginTrialsHelper.get_interface_names(window, ['PerformanceLongTaskTiming']);
-  console.log('Interfaces in document\n' + interfaces);
-}, "LongTaskObserver related interfaces in Origin-Trial enabled document.");
-</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter-window.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter-window.html
new file mode 100644
index 0000000..9238aa9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter-window.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<title>Service Worker: UseCounter</title>
+<script>
+window.opener.postMessage('LOADED', '*');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter-worker.js
new file mode 100644
index 0000000..44a3400
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/resources/usecounter-worker.js
@@ -0,0 +1,30 @@
+// This should be accessed only in the install event or the message event. When
+// this is false, it implies that this service worker is restarted after the
+// install event.
+let did_run_install_event = false;
+
+self.addEventListener('install', e => {
+  var scope = new URL(self.registration.scope);
+  if (scope.searchParams.get('type') == 'features-during-install') {
+    internals.countFeature(scope.searchParams.get('feature'));
+    internals.countDeprecation(scope.searchParams.get('deprecated'));
+  } else if (scope.searchParams.get('type') == 'skip-waiting') {
+    e.waitUntil(self.skipWaiting());
+  }
+  did_run_install_event = true;
+});
+
+onmessage = e => {
+  if (e.data.type == 'COUNT_FEATURE') {
+    internals.countFeature(e.data.feature);
+  } else if (e.data.type == 'COUNT_DEPRECATION') {
+    internals.countDeprecation(e.data.feature);
+  } else if (e.data.type == 'CLAIM') {
+    let promise = self.clients.claim()
+        .then(() => e.source.postMessage(
+            {type: 'CLAIMED', restarted: !did_run_install_event}));
+    e.waitUntil(promise);
+  } else if (e.data.type == 'PING') {
+    e.source.postMessage({type: 'PONG'});
+  }
+};
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter.html
new file mode 100644
index 0000000..9b0f94f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/usecounter.html
@@ -0,0 +1,325 @@
+<!DOCTYPE html>
+<title>Service Worker: UseCounter</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../resources/test-helpers.js"></script>
+<script>
+
+const kFeature = 675;  // From UseCounter.h
+const kDeprecatedFeature = 538;  // From Deprecation.h
+
+function isUseCounted(win, feature) {
+  return win.internals.isUseCounted(win.document, feature);
+}
+
+function observeUseCounter(win, feature) {
+  return win.internals.observeUseCounter(win.document, feature);
+}
+
+// Use a window instead of an iframe because UseCounter is shared among frames
+// in a document and these tests cannot be conducted in such an environment.
+// A window has its own UseCounter.
+function openWindow(url) {
+  return new Promise(resolve => {
+      let win = window.open(url, '_blank');
+      add_completion_callback(() => win.close());
+      window.onmessage = e => {
+        assert_equals(e.data, 'LOADED');
+        resolve(win);
+      };
+    });
+}
+
+promise_test(t => {
+    const kUrl = 'resources/usecounter-worker.js';
+    const kScope = 'resources/usecounter-window.html?basic';
+    let worker;
+    let win1;
+    let win2;
+
+    return service_worker_unregister_and_register(t, kUrl, kScope)
+      .then(registration => {
+          add_completion_callback(function() { registration.unregister(); });
+          worker = registration.installing;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(() => { return openWindow(kScope); })
+      .then(win => {
+          win1 = win;
+          return openWindow(kScope);
+        })
+      .then(win => {
+          win2 = win;
+
+          assert_false(isUseCounted(win1, kFeature));
+          assert_false(isUseCounted(win2, kFeature));
+
+          // Request to count a feature.
+          worker.postMessage({type: 'COUNT_FEATURE', feature: kFeature});
+          return Promise.all([
+              observeUseCounter(win1, kFeature),
+              observeUseCounter(win2, kFeature)
+          ]);
+        })
+      .then(() => {
+          // API use on ServiceWorkerGlobalScope should be recorded in all
+          // controlled windows.
+          assert_true(isUseCounted(win1, kFeature));
+          assert_true(isUseCounted(win2, kFeature));
+
+          assert_false(isUseCounted(win1, kDeprecatedFeature));
+          assert_false(isUseCounted(win2, kDeprecatedFeature));
+
+          // Request to count a deprecated feature.
+          worker.postMessage(
+              {type: 'COUNT_DEPRECATION', feature: kDeprecatedFeature});
+          return Promise.all([
+              observeUseCounter(win1, kDeprecatedFeature),
+              observeUseCounter(win2, kDeprecatedFeature)
+          ]);
+        })
+      .then(() => {
+          // Deprecated API use on ServiceWorkerGlobalScope should be recorded
+          // in all controlled windows.
+          assert_true(isUseCounted(win1, kDeprecatedFeature));
+          assert_true(isUseCounted(win2, kDeprecatedFeature));
+
+          return openWindow(kScope);
+        })
+      .then(win => {
+          assert_true(isUseCounted(win, kFeature));
+          assert_true(isUseCounted(win, kDeprecatedFeature));
+        });
+  }, 'UseCounter on ServiceWorkerGlobalScope');
+
+promise_test(t => {
+    const kUrl = 'resources/usecounter-worker.js';
+    const kScope = 'resources/usecounter-window.html?claim';
+    let worker;
+    let win1;
+    let win2;
+
+    return openWindow(kScope)
+     .then(win => {
+          win1 = win;
+          return openWindow(kScope);
+        })
+      .then(win => {
+          win2 = win;
+          return service_worker_unregister_and_register(t, kUrl, kScope)
+        })
+      .then(registration => {
+          add_completion_callback(function() { registration.unregister(); });
+          worker = registration.installing;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(() => {
+          // Request to count a feature.
+          worker.postMessage({type: 'COUNT_FEATURE', feature: kFeature});
+          return new Promise(resolve => {
+              navigator.serviceWorker.onmessage = resolve;
+              // There is no way to verify that API use is never counted. As a
+              // workaround, wait for only one round-trip.
+              worker.postMessage({type: 'PING'});
+            });
+        })
+      .then(e => {
+          assert_equals(e.data.type, 'PONG');
+
+          // API use on ServiceWorkerGlobalScope should not be recorded in
+          // windows because they are not controlled yet.
+          assert_false(isUseCounted(win1, kFeature));
+          assert_false(isUseCounted(win2, kFeature));
+
+          // Request to count a deprecated feature.
+          worker.postMessage(
+              {type: 'COUNT_DEPRECATION', feature: kDeprecatedFeature});
+          return new Promise(resolve => {
+              navigator.serviceWorker.onmessage = resolve;
+              // There is no way to verify that API use is never counted. As a
+              // workaround, wait for only one round-trip.
+              worker.postMessage({type: 'PING'});
+            });
+        })
+      .then(e => {
+          assert_equals(e.data.type, 'PONG');
+
+          // Deprecated API use on ServiceWorkerGlobalScope should not be
+          // recorded in windows because they are not controlled yet.
+          assert_false(isUseCounted(win1, kDeprecatedFeature));
+          assert_false(isUseCounted(win2, kDeprecatedFeature));
+
+          assert_equals(win1.navigator.serviceWorker.controller, null);
+          assert_equals(win2.navigator.serviceWorker.controller, null);
+
+          // Request to claim.
+          return new Promise(resolve => {
+              navigator.serviceWorker.onmessage = resolve;
+              worker.postMessage({type: 'CLAIM'});
+            });
+        })
+      .then(e => {
+          assert_equals(e.data.type, 'CLAIMED');
+          assert_false(e.data.restarted);
+          assert_not_equals(win1.navigator.serviceWorker.controller, null);
+          assert_not_equals(win2.navigator.serviceWorker.controller, null);
+
+          // The windows are now controlled by the service worker. Their
+          // UseCounter should be synchronized with worker's counter.
+          assert_true(isUseCounted(win1, kFeature));
+          assert_true(isUseCounted(win2, kFeature));
+          assert_true(isUseCounted(win1, kDeprecatedFeature));
+          assert_true(isUseCounted(win2, kDeprecatedFeature));
+        });
+  }, 'UseCounter on ServiceWorkerGlobalScope - A use counter owned by newly ' +
+     'controlled window should be synchronized with worker\'s counter');
+
+// Test that features used during service worker installation are persisted.
+// This test could be non-deterministic because there is no handy way to
+// sweep out on-memory representation of ServiceWorker in the browser process
+// and make sure to restore it from the storage.
+promise_test(t => {
+    const kUrl = 'resources/usecounter-worker.js';
+    const kScope = 'resources/usecounter-window.html' +
+                   '?type=features-during-install' +
+                   '&feature=' + kFeature +
+                   '&deprecated=' + kDeprecatedFeature;
+    let worker;
+    let win1;
+    let win2;
+
+    return openWindow(kScope)
+     .then(win => {
+          win1 = win;
+          return openWindow(kScope);
+        })
+      .then(win => {
+          win2 = win;
+          // A service worker will call some APIs during the install event.
+          return service_worker_unregister_and_register(t, kUrl, kScope)
+        })
+      .then(registration => {
+          add_completion_callback(function() { registration.unregister(); });
+          worker = registration.installing;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(e => {
+          assert_equals(win1.navigator.serviceWorker.controller, null);
+          assert_equals(win2.navigator.serviceWorker.controller, null);
+
+          // API use on ServiceWorkerGlobalScope should not be recorded in
+          // windows because they are not controlled yet.
+          assert_false(isUseCounted(win1, kFeature));
+          assert_false(isUseCounted(win2, kFeature));
+          assert_false(isUseCounted(win1, kDeprecatedFeature));
+          assert_false(isUseCounted(win2, kDeprecatedFeature));
+
+          // Terminate the service worker.
+          internals.terminateServiceWorker(worker);
+
+          // Request to claim. This will restart the service worker.
+          return new Promise(resolve => {
+              navigator.serviceWorker.onmessage = resolve;
+              worker.postMessage({type: 'CLAIM'});
+            });
+        })
+      .then(e => {
+          assert_equals(e.data.type, 'CLAIMED');
+          assert_true(e.data.restarted);
+          assert_not_equals(win1.navigator.serviceWorker.controller, null);
+          assert_not_equals(win2.navigator.serviceWorker.controller, null);
+
+          // The windows are now controlled by the service worker. Their
+          // UseCounter should be synchronized with worker's counter retrieved
+          // from the storage.
+          assert_true(isUseCounted(win1, kFeature));
+          assert_true(isUseCounted(win2, kFeature));
+          assert_true(isUseCounted(win1, kDeprecatedFeature));
+          assert_true(isUseCounted(win2, kDeprecatedFeature));
+        });
+  }, 'UseCounter on ServiceWorkerGlobalScope - counts during the install ' +
+     'event should be persisted');
+
+// TODO(nhiroki): Test that features used after service worker installation are
+// not persisted. This could be impossible because there is no handy way to
+// sweep out on-memory representation of ServiceWorker in the browser process
+// and make sure to restore it from the storage.
+
+promise_test(t => {
+    const kUrl = 'resources/usecounter-worker.js';
+    const kScope = 'resources/usecounter-window.html?type=skip-waiting';
+    let worker1;
+    let worker2;
+    let win1;
+    let win2;
+
+    return service_worker_unregister_and_register(t, kUrl, kScope)
+      .then(registration => {
+          add_completion_callback(function() { registration.unregister(); });
+          worker1 = registration.installing;
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(() => { return openWindow(kScope); })
+      .then(win => {
+          win1 = win;
+          assert_false(isUseCounted(win1, kFeature));
+
+          // Request to count a feature.
+          worker1.postMessage({type: 'COUNT_FEATURE', feature: kFeature});
+          return observeUseCounter(win1, kFeature);
+        })
+      .then(e => {
+          // API use on ServiceWorkerGlobalScope should be recorded in a
+          // controlled window.
+          assert_true(isUseCounted(win1, kFeature));
+
+          // Update a controller using skipWaiting().
+          return navigator.serviceWorker.register(
+              kUrl + '?skip-waiting', {scope: kScope});
+        })
+      .then(registration => {
+          add_completion_callback(function() { registration.unregister(); });
+          worker2 = registration.installing;
+          // Wait until the new worker gets activated.
+          return wait_for_state(t, worker2, 'activated');
+        })
+      .then(() => { return openWindow(kScope); })
+      .then(win => {
+          // This window wasn't controlled by the previous worker.
+          win2 = win;
+          assert_not_equals(win2.navigator.serviceWorker.controller, undefined);
+
+          // An updated worker does not take over the previous counter, so API
+          // use on the previous worker should not be recorded in the newly
+          // controlled window.
+          assert_true(isUseCounted(win1, kFeature));
+          assert_false(isUseCounted(win2, kFeature));
+
+          assert_false(isUseCounted(win1, kDeprecatedFeature));
+          assert_false(isUseCounted(win2, kDeprecatedFeature));
+
+          // Request to count a deprecated feature.
+          worker2.postMessage(
+              {type: 'COUNT_DEPRECATION', feature: kDeprecatedFeature});
+          return Promise.all([
+              observeUseCounter(win1, kDeprecatedFeature),
+              observeUseCounter(win2, kDeprecatedFeature)
+          ]);
+        })
+      .then(e => {
+          // Deprecated API use on the updated worker should be recorded in
+          // all controlled windows.
+          assert_true(isUseCounted(win1, kFeature));
+          assert_false(isUseCounted(win2, kFeature));
+          assert_true(isUseCounted(win1, kDeprecatedFeature));
+          assert_true(isUseCounted(win2, kDeprecatedFeature));
+        });
+  }, 'UseCounter on ServiceWorkerGlobalScope - an updated worker should not ' +
+     'take over a previous counter');
+
+// TODO(nhiroki): Test a case where ServiceWorker controls SharedWorker that is
+// connected from multiple windows. In such a case, API use on ServiceWorker
+// should be propagated to all connecting windows via SharedWorker.
+
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-event.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-event.html
deleted file mode 100644
index 147de903..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/foreign-fetch-event.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="resources/test-helpers.js"></script>
-<script>
-service_worker_test('resources/foreign-fetch-event-worker.js',
-                    'ForeignFetchEvent constructor');
-</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helper-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helper-worker.js
deleted file mode 100644
index 9b9a293..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helper-worker.js
+++ /dev/null
@@ -1,8 +0,0 @@
-importScripts('../../resources/get-host-info.js');
-var host_info = get_host_info();
-
-self.onfetch = e => {
-  var remote_url = host_info.HTTPS_REMOTE_ORIGIN +
-                   '/serviceworker/resources/simple.txt?basic_sw';
-  e.respondWith(fetch(remote_url));
-};
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helpers.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helpers.js
deleted file mode 100644
index eae9f4e..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/foreign-fetch-helpers.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// Common helper functions for foreign fetch tests.
-
-// Installs a service worker on a different origin. Both |worker| and |scope|
-// are resolved relative to the /serviceworker/resources/ directory on a
-// remote origin.
-function install_cross_origin_worker(
-    t, worker, scope, origin = get_host_info().HTTPS_REMOTE_ORIGIN) {
-  return with_iframe(origin +
-                     '/serviceworker/resources/install-worker-helper.html')
-    .then(frame => new Promise((resolve, reject) => {
-        var channel = new MessageChannel();
-        frame.contentWindow.postMessage({worker: worker,
-                                         options: {scope: scope},
-                                         port: channel.port1},
-                                        '*', [channel.port1]);
-        channel.port2.onmessage = reply => {
-            if (reply.data == 'success') resolve();
-            else reject(reply.data);
-          };
-      }));
-}
diff --git a/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners-expected.txt
index c2f5743..32c2487 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners-expected.txt
@@ -8,7 +8,6 @@
 [page]         listener: function listener1() { }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "keydown"
 [page]         useCapture: false
 [page]     }
@@ -16,7 +15,6 @@
 [page]         listener: function listener2() { }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "keydown"
 [page]         useCapture: true
 [page]     }
@@ -26,7 +24,6 @@
 [page]         listener: function listener2() { }
 [page]         once: false
 [page]         passive: true
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "wheel"
 [page]         useCapture: false
 [page]     }
@@ -37,7 +34,6 @@
 [page]         listener: function listener2() { }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "keydown"
 [page]         useCapture: true
 [page]     }
@@ -48,7 +44,6 @@
 [page]         listener: function listener2() { }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "keydown"
 [page]         useCapture: true
 [page]     }
@@ -58,7 +53,6 @@
 [page]         listener: function listener2() { }
 [page]         once: true
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "keyup"
 [page]         useCapture: false
 [page]     }
@@ -68,7 +62,6 @@
 [page]         listener: function listener2() { }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "mousedown"
 [page]         useCapture: true
 [page]     }
@@ -78,7 +71,6 @@
 [page]         listener: function listener1() { }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "mousemove"
 [page]         useCapture: false
 [page]     }
@@ -89,7 +81,6 @@
 [page]         listener: function onclick(event) { alert(1) }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "click"
 [page]         useCapture: false
 [page]     }
@@ -99,7 +90,6 @@
 [page]         listener: function onmouseover(event) { listener2() }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "mouseover"
 [page]         useCapture: false
 [page]     }
@@ -110,7 +100,6 @@
 [page]         listener: function onload(event) { runTest() }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "load"
 [page]         useCapture: false
 [page]     }
@@ -120,7 +109,6 @@
 [page]         listener: function listener1() { }
 [page]         once: false
 [page]         passive: false
-[page]         remove: function remove() { [Command Line API] }
 [page]         type: "popstate"
 [page]         useCapture: false
 [page]     }
diff --git a/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners.html b/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners.html
index 96a21f8..c7ab057 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners.html
+++ b/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners.html
@@ -81,12 +81,13 @@
 function runTestsInPage(getEventListeners)
 {
     output("- inner -");
-    var innerListeners = getEventListeners(document.getElementById("inner"));
+    var innerElement = document.getElementById("inner");
+    var innerListeners = getEventListeners(innerElement);
     dumpObject(innerListeners);
-    innerListeners.keydown[0].remove();
-    innerListeners.wheel[0].remove();
+    innerElement.removeEventListener("keydown", innerListeners.keydown[0].listener, innerListeners.keydown[0].useCapture);
+    innerElement.removeEventListener("wheel", innerListeners.wheel[0].listener, innerListeners.wheel[0].useCapture);
     output("- inner after a removal -");
-    dumpObject(getEventListeners(document.getElementById("inner")));
+    dumpObject(getEventListeners(innerElement));
     output("- outer -");
     dumpObject(getEventListeners(document.getElementById("outer")));
     output("- attribute event listeners -");
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-custom-framework-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-custom-framework-expected.txt
index 4b85e26f..6a512f2 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-custom-framework-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-custom-framework-expected.txt
@@ -4,7 +4,7 @@
 == Incorrect fetchers
 
 ======== click ========
-== frameworkInternal
+== Framework
 [expanded] button#inspectedNodeRemoveevent-listener-sidebar-custom-framework.html:23
     useCapture: false
     passive: false
@@ -19,7 +19,7 @@
     }
 
 ======== customFirst ========
-== frameworkUser
+== FrameworkUser
 [expanded] button#inspectedNodeevent-listener-sidebar-custom-framework.html:13
     useCapture: true
     passive: false
@@ -30,7 +30,7 @@
     }
 
 ======== customSecond ========
-== frameworkUser
+== FrameworkUser
 [expanded] button#inspectedNodeevent-listener-sidebar-custom-framework.html:18
     useCapture: false
     passive: false
@@ -42,7 +42,7 @@
 == Exception in fetchers' getter
 
 ======== click ========
-== normal
+== Raw
 [expanded] button#inspectedNodeRemoveevent-listener-sidebar-custom-framework.html:23
     useCapture: false
     passive: false
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-expected.txt
index 4dcedae1..74dd114 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-expected.txt
@@ -3,49 +3,49 @@
 Inspect Me
 
 ======== click ========
-== normal
+== Raw
 [expanded] documentRemoveevent-listener-sidebar.html:6
     useCapture: false
     passive: false
     once: false
     handler: function documentClickHandler(event) { console.log("click - document - attribute"); }
-== normal
+== Raw
 [expanded] documentRemoveevent-listener-sidebar.html:31
     useCapture: true
     passive: false
     once: false
     handler: function () { console.log("click - document - handleEvent"); }
-== normal
+== Raw
 [expanded] documentRemoveevent-listener-sidebar.html:25
     useCapture: true
     passive: false
     once: false
     handler: function ObjectHandler() { document.addEventListener("click", this, true); }
-== normal
+== Raw
 [expanded] documentRemoveevent-listener-sidebar.html:19
     useCapture: true
     passive: false
     once: false
     handler: function (event) { console.log("click - document - capturing"); }
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar.html:17
     useCapture: false
     passive: false
     once: false
     handler: function (event) { console.log("click - button - bubbling (registered after attribute)"); }
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar.html:16
     useCapture: false
     passive: false
     once: false
     handler: function (event) { console.log("click - button - attribute"); }
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar.html:12
     useCapture: false
     passive: false
     once: false
     handler: function clickHandler(event) { console.log("click - button - bubbling (registered before attribute)"); }
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar.html:15
     useCapture: true
     passive: false
@@ -53,7 +53,7 @@
     handler: function (event) { console.log("click - button - capturing"); }
 
 ======== custom event ========
-== normal
+== Raw
 [expanded] bodyRemoveevent-listener-sidebar.html:10
     useCapture: true
     passive: false
@@ -61,7 +61,7 @@
     handler: function f() {}
 
 ======== hover ========
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar.html:14
     useCapture: false
     passive: false
@@ -69,7 +69,7 @@
     handler: function hoverHandler(event) { console.log("hover - button - bubbling"); }
 
 ======== load ========
-== normal
+== Raw
 [expanded] WindowRemoveevent-listener-sidebar.html:76
     useCapture: false
     passive: false
@@ -79,7 +79,7 @@
 }
 
 ======== wheel ========
-== normal
+== Raw
 [expanded] bodyRemoveToggle Passiveevent-listener-sidebar.html:10
     useCapture: false
     passive: true
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-jquery1-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-jquery1-expected.txt
index 8232364..bf223a0 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-jquery1-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-jquery1-expected.txt
@@ -3,25 +3,25 @@
 Inspect Me
 
 ======== click ========
-== frameworkUser
+== FrameworkUser
 [expanded] button#nodeRemoveevent-listener-sidebar-jquery1.html:11
     useCapture: true
     passive: false
     once: false
     handler: function (){ console.log("second jquery"); }
-== frameworkUser
+== FrameworkUser
 [expanded] button#nodeRemoveevent-listener-sidebar-jquery1.html:10
     useCapture: true
     passive: false
     once: false
     handler: function (){ console.log("first jquery"); }
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar-jquery1.html:12
     useCapture: false
     passive: false
     once: false
     handler: function () { console.log("addEventListener"); }
-== frameworkInternal
+== Framework
 [expanded] button#nodeRemovejquery-1.11.3.min.js:4
     useCapture: false
     passive: false
@@ -29,7 +29,7 @@
     handler: function (a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)}
 
 ======== load ========
-== normal
+== Raw
 [expanded] WindowRemoveevent-listener-sidebar-jquery1.html:36
     useCapture: false
     passive: false
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-jquery2-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-jquery2-expected.txt
index e7ba8c4..2fa1e901 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-jquery2-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-jquery2-expected.txt
@@ -3,31 +3,31 @@
 Inspect Me
 
 ======== click ========
-== frameworkUser
+== FrameworkUser
 [expanded] button#nodeRemoveevent-listener-sidebar-jquery2.html:11
     useCapture: true
     passive: false
     once: false
     handler: function (){ console.log("second jquery"); }
-== frameworkUser
+== FrameworkUser
 [expanded] button#nodeRemoveevent-listener-sidebar-jquery2.html:10
     useCapture: true
     passive: false
     once: false
     handler: function (){ console.log("first jquery"); }
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar-jquery2.html:13
     useCapture: false
     passive: false
     once: false
     handler: function () { console.log("onclick"); }
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar-jquery2.html:12
     useCapture: false
     passive: false
     once: false
     handler: function () { console.log("addEventListener"); }
-== frameworkInternal
+== Framework
 [expanded] button#nodeRemovejquery-2.1.4.min.js:3
     useCapture: false
     passive: false
@@ -35,7 +35,7 @@
     handler: function (b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}
 
 ======== load ========
-== normal
+== Raw
 [expanded] WindowRemoveevent-listener-sidebar-jquery2.html:52
     useCapture: false
     passive: false
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-remove-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-remove-expected.txt
index 44291c0..ceffa29 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-remove-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/event-listener-sidebar-remove-expected.txt
@@ -3,7 +3,7 @@
 Inspect Me Inspect Sibling
 
 ======== click ========
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar-remove.html:9
     useCapture: false
     passive: false
@@ -11,7 +11,7 @@
     handler: function f() {}
 
 ======== mouseover ========
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar-remove.html:9
     useCapture: false
     passive: false
@@ -20,7 +20,7 @@
 Listeners after removal:
 
 ======== mouseover ========
-== normal
+== Raw
 [expanded] button#nodeRemoveevent-listener-sidebar-remove.html:9
     useCapture: false
     passive: false
@@ -29,7 +29,7 @@
 Listeners for sibling node:
 
 ======== click ========
-== normal
+== Raw
 [expanded] button#node-siblingRemoveevent-listener-sidebar-remove.html:10
     useCapture: false
     passive: false
@@ -37,7 +37,7 @@
     handler: function g() {}
 
 ======== mouseover ========
-== normal
+== Raw
 [expanded] button#node-siblingRemoveevent-listener-sidebar-remove.html:10
     useCapture: false
     passive: false
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/event-listeners-about-blank-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/event-listeners-about-blank-expected.txt
index 1063ac2..cbb21bb 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/event-listeners-about-blank-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/event-listeners-about-blank-expected.txt
@@ -3,7 +3,7 @@
 
 
 ======== click ========
-== normal
+== Raw
 [expanded] bodyRemoveevent-listeners-about-blank.html:9
     useCapture: true
     passive: false
@@ -11,7 +11,7 @@
     handler: function f() {}
 
 ======== hover ========
-== normal
+== Raw
 [expanded] div#div-in-iframeRemoveevent-listeners-about-blank.html:9
     useCapture: true
     passive: false
@@ -19,7 +19,7 @@
     handler: function f() {}
 
 ======== wheel ========
-== normal
+== Raw
 [expanded] bodyRemoveToggle Passiveevent-listeners-about-blank.html:9
     useCapture: false
     passive: true
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage-expected.txt
index 8eca530..1bac6f4 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage-expected.txt
@@ -4,5 +4,6 @@
 TimelineControllerClient.recordingProgress
 TimelineControllerClient.loadingStarted
 TimelineControllerClient.loadingProgress
+TimelineControllerClient.processingStarted
 TimelineControllerClient.loadingComplete
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html b/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html
index b97c38ec..cc6e1d2 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html
@@ -39,6 +39,11 @@
             InspectorTest.addResult("TimelineControllerClient.loadingProgress");
         },
 
+        processingStarted: function()
+        {
+            InspectorTest.addResult("TimelineControllerClient.processingStarted");
+        },
+
         loadingComplete: function()
         {
             InspectorTest.addResult("TimelineControllerClient.loadingComplete");
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-record.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-record.html
index 8067445..c2f6f619 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-record.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-auto-record.html
@@ -11,7 +11,7 @@
 
     var callbackBarrier = new CallbackBarrier();
     InspectorTest.addSniffer(panel, "recordingStarted", recordingStarted);
-    InspectorTest.addSniffer(panel, "loadingComplete", callbackBarrier.createCallback());
+    InspectorTest.runWhenTimelineIsReady(callbackBarrier.createCallback());
 
     UI.viewManager.showView("console");
     InspectorTest.runWhenPageLoads(step1);
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html
index accadea..652d137 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-flame-chart-automatically-size-window.html
@@ -19,9 +19,7 @@
     }
 
     timeline.requestWindowTimes = requestWindowTimesHook;
-    InspectorTest.loadTimeline(InspectorTest.timelineData());
-
-    InspectorTest.completeTest();
+    InspectorTest.loadTimeline(InspectorTest.timelineData()).then(() => InspectorTest.completeTest());
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter.html
index 99ae408..ff2656f 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-misc/timeline-window-filter.html
@@ -10,13 +10,26 @@
     var timeline = UI.panels.timeline;
     var overviewPane = timeline._overviewPane;
 
-    InspectorTest.loadTimeline(InspectorTest.timelineData());
+    InspectorTest.loadTimeline(InspectorTest.timelineData()).then(onTimelineLoaded);
 
-    overviewPane._update();
-    InspectorTest.addResult("OverviewPane:");
-    overviewPane._overviewCalculator.setDisplayWidth(450);
-    dumpDividers(overviewPane._overviewCalculator);
-    InspectorTest.addResult("");
+    function onTimelineLoaded()
+    {
+        overviewPane._update();
+        InspectorTest.addResult("OverviewPane:");
+        overviewPane._overviewCalculator.setDisplayWidth(450);
+        dumpDividers(overviewPane._overviewCalculator);
+        InspectorTest.addResult("");
+
+        dumpFlameChartRecordsCountForRange(0, 1);
+        dumpFlameChartRecordsCountForRange(0.25, 0.75);
+        dumpFlameChartRecordsCountForRange(0.33, 0.66);
+
+        overviewPane._overviewGrid.setWindow(0.1, 0.9);
+
+        InspectorTest.addResult("--------------------------------------------------------");
+        InspectorTest.addResult("time range = " + timeline._windowStartTime + " - " + timeline._windowEndTime);
+        InspectorTest.completeTest();
+    }
 
     function dumpFlameChartRecordsCountForRange(windowLeft, windowRight)
     {
@@ -36,16 +49,6 @@
             dividers[i] -= calculator.zeroTime();
         InspectorTest.addResult("divider offsets: [" + dividers.join(", ") + "]. We are expecting round numbers.");
     }
-
-    dumpFlameChartRecordsCountForRange(0, 1);
-    dumpFlameChartRecordsCountForRange(0.25, 0.75);
-    dumpFlameChartRecordsCountForRange(0.33, 0.66);
-
-    overviewPane._overviewGrid.setWindow(0.1, 0.9);
-
-    InspectorTest.addResult("--------------------------------------------------------");
-    InspectorTest.addResult("time range = " + timeline._windowStartTime + " - " + timeline._windowEndTime);
-    InspectorTest.completeTest();
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time.html b/third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time.html
index 0495e7b..64e408d 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/trace-event-self-time.html
@@ -289,7 +289,7 @@
     var timelineController = InspectorTest.timelineController();
     timelineController._addCpuProfile(SDK.targetManager.mainTarget().id(), null, cpuProfile);
     timelineController.traceEventsCollected(rawTraceEvents);
-    timelineController._allSourcesFinished();
+    timelineController._finalizeTrace();
     var events = timelineController._performanceModel.timelineModel().inspectedTargetEvents();
     events.forEach(e => InspectorTest.addResult(`${e.name}: ${e.startTime} ${(e.selfTime || 0).toFixed(2)}/${(e.duration || 0).toFixed(2)}`));
     InspectorTest.completeTest();
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load-expected.txt
index 9d1fa2a..4d1cabd 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load-expected.txt
@@ -4,23 +4,27 @@
 Running: testNormal
 TimelineLoaderClient.loadingStarted()
 TimelineLoaderClient.loadingProgress()
+TimelineLoaderClient.processingStarted()
 TimelineLoaderClient.loadingComplete(true)
 Saved data is equal to restored data: true
 
 Running: testJSONObjectFormat
 TimelineLoaderClient.loadingStarted()
 TimelineLoaderClient.loadingProgress()
+TimelineLoaderClient.processingStarted()
 TimelineLoaderClient.loadingComplete(true)
 Saved data is equal to restored data: true
 
 Running: testJSONObjectFormatWithMetadata
 TimelineLoaderClient.loadingStarted()
 TimelineLoaderClient.loadingProgress()
+TimelineLoaderClient.processingStarted()
 TimelineLoaderClient.loadingComplete(true)
 Saved data is equal to restored data: true
 
 Running: testBroken
 TimelineLoaderClient.loadingStarted()
+TimelineLoaderClient.processingStarted()
 TimelineLoaderClient.loadingComplete(true)
 Model is empty: true
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load.html b/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load.html
index c2b44b4..4f1923b 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/tracing-timeline-load.html
@@ -6,7 +6,10 @@
 
 function test()
 {
-    InspectorTest.TestTimelineLoaderClient = function() {}
+    InspectorTest.TestTimelineLoaderClient = function(callback)
+    {
+        this._callback = callback;
+    }
 
     InspectorTest.TestTimelineLoaderClient.prototype = {
         loadingStarted: function()
@@ -19,11 +22,17 @@
             InspectorTest.addResult("TimelineLoaderClient.loadingProgress()");
         },
 
+        processingStarted: function()
+        {
+            InspectorTest.addResult("TimelineLoaderClient.processingStarted()");
+        },
+
         loadingComplete: function(model, storage)
         {
             this.model = model;
             this.storage = storage;
             InspectorTest.addResult(`TimelineLoaderClient.loadingComplete(${!!model})`);
+            this._callback();
         },
     }
 
@@ -42,20 +51,22 @@
         }
 
         InspectorTest.override(Timeline.TimelineLoader, "_createFileReader", createFileReader);
-        var delegate = new InspectorTest.TestTimelineLoaderClient();
+        var delegate = new InspectorTest.TestTimelineLoaderClient(onTimelineLoaded);
         Timeline.TimelineLoader.loadFromFile({}, delegate);
-
-        var saver = new Timeline.TracingTimelineSaver();
-        var stream = new InspectorTest.StringOutputStream(InspectorTest.safeWrap(checkSaveData));
-        var storage = delegate.storage;
-        stream.open("", storage.writeToStream.bind(storage, stream, saver));
+        function onTimelineLoaded()
+        {
+            var saver = new Timeline.TracingTimelineSaver();
+            var stream = new InspectorTest.StringOutputStream(InspectorTest.safeWrap(checkSaveData));
+            var storage = delegate.storage;
+            stream.open("", storage.writeToStream.bind(storage, stream, saver));
+        };
     }
 
     function runTestOnMalformedInput(input, callback)
     {
         function createFileReader(file, delegate)
         {
-            return new InspectorTest.FakeFileReader(input, delegate, checkLoadedData);
+            return new InspectorTest.FakeFileReader(input, delegate, () => {});
         }
 
         function checkLoadedData(data)
@@ -66,7 +77,7 @@
         }
 
         InspectorTest.override(Timeline.TimelineLoader, "_createFileReader", createFileReader);
-        var delegate = new InspectorTest.TestTimelineLoaderClient();
+        var delegate = new InspectorTest.TestTimelineLoaderClient(checkLoadedData);
         Timeline.TimelineLoader.loadFromFile({}, delegate);
     }
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
index 16a7662..25aa826 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3780,6 +3780,10 @@
     getter startTime
     method constructor
     method toJSON
+interface PerformanceLongTaskTiming : PerformanceEntry
+    attribute @@toStringTag
+    getter attribution
+    method constructor
 interface PerformanceMark : PerformanceEntry
     attribute @@toStringTag
     method constructor
@@ -5554,6 +5558,13 @@
     method constructor
     method getTags
     method register
+interface TaskAttributionTiming : PerformanceEntry
+    attribute @@toStringTag
+    getter containerId
+    getter containerName
+    getter containerSrc
+    getter containerType
+    method constructor
 interface Text : CharacterData
     attribute @@toStringTag
     getter assignedSlot
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
index e274878f..f0b97d2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3708,6 +3708,10 @@
     getter startTime
     method constructor
     method toJSON
+interface PerformanceLongTaskTiming : PerformanceEntry
+    attribute @@toStringTag
+    getter attribution
+    method constructor
 interface PerformanceMark : PerformanceEntry
     attribute @@toStringTag
     method constructor
@@ -5482,6 +5486,13 @@
     method constructor
     method getTags
     method register
+interface TaskAttributionTiming : PerformanceEntry
+    attribute @@toStringTag
+    getter containerId
+    getter containerName
+    getter containerSrc
+    getter containerType
+    method constructor
 interface Text : CharacterData
     attribute @@toStringTag
     getter assignedSlot
diff --git a/third_party/WebKit/LayoutTests/virtual/origin-trials-features-disabled/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt b/third_party/WebKit/LayoutTests/virtual/origin-trials-features-disabled/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt
deleted file mode 100644
index 8ffee0ef..0000000
--- a/third_party/WebKit/LayoutTests/virtual/origin-trials-features-disabled/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CONSOLE MESSAGE: line 15: Interfaces in document
-interface PerformanceLongTaskTiming
-    getter attribution
-    method constructor
-This is a testharness.js-based test.
-PASS LongTaskObserver related interfaces in Origin-Trial enabled document. 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/origin-trials-features-disabled/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt b/third_party/WebKit/LayoutTests/virtual/origin-trials-features-disabled/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt
deleted file mode 100644
index dda0b87c..0000000
--- a/third_party/WebKit/LayoutTests/virtual/origin-trials-features-disabled/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-CONSOLE MESSAGE: line 15: Interfaces before adding trial token
-
-CONSOLE MESSAGE: line 23: Interfaces after adding trial token
-interface PerformanceLongTaskTiming
-    getter attribution
-    method constructor
-This is a testharness.js-based test.
-PASS LongTaskObserver related interfaces before adding trial token via script. 
-PASS LongTaskObserver related interfaces after adding trial token via script. 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt
deleted file mode 100644
index 8ffee0ef..0000000
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-CONSOLE MESSAGE: line 15: Interfaces in document
-interface PerformanceLongTaskTiming
-    getter attribution
-    method constructor
-This is a testharness.js-based test.
-PASS LongTaskObserver related interfaces in Origin-Trial enabled document. 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt
deleted file mode 100644
index dda0b87c..0000000
--- a/third_party/WebKit/LayoutTests/virtual/stable/http/tests/origin_trials/webexposed/longtask-origin-trial-interfaces-script-added-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-CONSOLE MESSAGE: line 15: Interfaces before adding trial token
-
-CONSOLE MESSAGE: line 23: Interfaces after adding trial token
-interface PerformanceLongTaskTiming
-    getter attribution
-    method constructor
-This is a testharness.js-based test.
-PASS LongTaskObserver related interfaces before adding trial token via script. 
-PASS LongTaskObserver related interfaces after adding trial token via script. 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start-expected.txt
index 557cf88..aa6f69f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start-expected.txt
@@ -3,6 +3,8 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+PASS The index of first non-zero value is not equal to -1.
+PASS The first sample value is equal to 0.
 PASS The rendered buffer contains non-zero values after the first sample.
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
index 959475fa..de614d8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/oscillator-late-start.html
@@ -17,9 +17,7 @@
 
     var sampleRate = 44100;
 
-    // The long render length (20 seconds) is to make sure the |onstatechange|
-    // event gets fired to start the source, which can take quite a bit of time.
-    var renderLength = 20;
+    var renderLength = 1;
     
     var context = new OfflineAudioContext(1, sampleRate * renderLength, sampleRate);
     var osc = context.createOscillator();
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/late-start-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/late-start-testing.js
index 96f709b..eca771f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/late-start-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/late-start-testing.js
@@ -12,29 +12,20 @@
 
   node.connect(context.destination);
 
-  // Task: define |onstatechange| and start rendering.
+  // Task: schedule a suspend and start rendering.
   audit.defineTask('test-late-start', function (done) {
-
-    // Trigger playback at 0 second. The assumptions are:
-    //
-    // 1) The specified timing of start() call is already passed in terms of
-    // the context time. So the argument |0| will be clamped to the current
-    // context time.
-    // 2) The |onstatechange| event will be fired later than the 0 second
-    // context time.
-    //
+    // The node's start time will be clamped to the render quantum boundary
+    // >0.1 sec. Thus the rendered buffer will have non-zero frames.
     // See issue: crbug.com/462167
-    context.onstatechange = function () {
-      if (context.state === 'running') {
-        node.start(0);
-      }
-    };
+    context.suspend(0.1).then(() => {
+      node.start(0);
+      context.resume();
+    });
 
     // Start rendering and verify result: this verifies if 1) the rendered
     // buffer contains at least one non-zero value and 2) the non-zero value is
     // found later than the first output sample.
     context.startRendering().then(function (buffer) {
-
       var nonZeroValueIndex = -1;
       var channelData = buffer.getChannelData(0);
       for (var i = 0; i < channelData.length; i++) {
@@ -44,13 +35,14 @@
         }
       }
 
-      if (nonZeroValueIndex === -1) {
-        testFailed('The rendered buffer was all zeros.');
-      } else if (nonZeroValueIndex === 0) {
-        testFailed('The first sample was non-zero value. It should be zero.');
-      } else {
-        testPassed('The rendered buffer contains non-zero values after the first sample.');
-      }
+      var success =
+          Should('The index of first non-zero value',nonZeroValueIndex)
+              .notBeEqualTo(-1);
+      success = Should('The first sample value', channelData[0])
+          .beEqualTo(0) && success;
+      Should('The rendered buffer', success)
+          .summarize('contains non-zero values after the first sample',
+                     'was all zeros or has non-zero first sample.');
 
       done();
     });
@@ -66,4 +58,4 @@
     'finish-test'
   );
 
-}
\ No newline at end of file
+}
diff --git a/third_party/WebKit/PerformanceTests/Editing/move-down-with-hidden-elements.html b/third_party/WebKit/PerformanceTests/Editing/move-down-with-hidden-elements.html
new file mode 100644
index 0000000..17b86fd
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/Editing/move-down-with-hidden-elements.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<script src="../resources/runner.js"></script>
+<div id="sample"></div>
+<script>
+const kCount = 10;
+const kElements = 10000;
+
+const metaElements = (() => {
+  const result = [];
+  for (let count = 0; count < kElements; ++count)
+    result.push('<meta>', '</meta>');
+  return result;
+})();
+const sample = document.getElementById('sample');
+sample.innerHTML =   [
+  '<div hiddent>', ...metaElements, '</div>',
+  '<h1 id="target">first line of renderered text</h1>',
+  '<div hiddent>', ...metaElements, '</div>',
+].join('');
+
+const selection = window.getSelection();
+const target = document.getElementById('target');
+
+PerfTestRunner.measureRunsPerSecond({
+  description: 'Measures performance of move-down through non-renderered elements',
+  run: () => {
+    selection.collapse(target, 0);
+    selection.extend(target, target.childNodes.length);
+    for (let counter = 0; counter < kCount; ++counter)
+      selection.modify('move', 'forward', 'line');
+    },
+});
+</script>
diff --git a/third_party/WebKit/PerformanceTests/Editing/move-up-with-hidden-elements.html b/third_party/WebKit/PerformanceTests/Editing/move-up-with-hidden-elements.html
new file mode 100644
index 0000000..b2def76
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/Editing/move-up-with-hidden-elements.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<script src="../resources/runner.js"></script>
+<div id="sample"></div>
+<script>
+const kCount = 10;
+const kElements = 10000;
+
+const metaElements = (() => {
+  const result = [];
+  for (let count = 0; count < kElements; ++count)
+    result.push('<meta>', '</meta>');
+  return result;
+})();
+const sample = document.getElementById('sample');
+sample.innerHTML =   [
+  '<div hiddent>', ...metaElements, '</div>',
+  '<h1 id="target">first line of renderered text</h1>',
+  '<div hiddent>', ...metaElements, '</div>',
+].join('');
+
+const selection = window.getSelection();
+const target = document.getElementById('target');
+
+PerfTestRunner.measureRunsPerSecond({
+  description: 'Measures performance of move-up through non-renderered elements',
+  run: () => {
+    selection.collapse(target, 0);
+    selection.extend(target, target.childNodes.length);
+    for (let counter = 0; counter < kCount; ++counter)
+      selection.modify('move', 'backward', 'line');
+    },
+});
+</script>
diff --git a/third_party/WebKit/Source/bindings/bindings.gni b/third_party/WebKit/Source/bindings/bindings.gni
index a4ba8791..705182d 100644
--- a/third_party/WebKit/Source/bindings/bindings.gni
+++ b/third_party/WebKit/Source/bindings/bindings.gni
@@ -132,6 +132,8 @@
                     "core/v8/Transferables.h",
                     "core/v8/ToV8.cpp",
                     "core/v8/ToV8.h",
+                    "core/v8/UseCounterCallback.cpp",
+                    "core/v8/UseCounterCallback.h",
                     "core/v8/V8AbstractEventListener.cpp",
                     "core/v8/V8AbstractEventListener.h",
                     "core/v8/V8Binding.cpp",
diff --git a/third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp b/third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp
index 8f3a147d..2c2762a9 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ConditionalFeatures.cpp
@@ -33,12 +33,6 @@
           isolate, world, v8::Local<v8::Object>(), prototypeObject,
           interfaceObject);
     }
-  } else if (wrapperTypeInfo == &V8Window::wrapperTypeInfo) {
-    v8::Local<v8::Object> instanceObject = scriptState->context()->Global();
-    if (OriginTrials::longTaskObserverEnabled(executionContext)) {
-      V8Window::installLongTaskObserver(isolate, world, instanceObject,
-                                        prototypeObject, interfaceObject);
-    }
   } else if (wrapperTypeInfo == &V8Document::wrapperTypeInfo) {
     if (OriginTrials::setRootScrollerEnabled(executionContext)) {
       V8Document::installRootScroller(isolate, world, v8::Local<v8::Object>(),
@@ -67,13 +61,6 @@
     }
     return;
   }
-  if (feature == "LongTaskObserver") {
-    v8::Local<v8::Object> instanceObject = scriptState->context()->Global();
-    V8Window::installLongTaskObserver(isolate, world, instanceObject,
-                                      v8::Local<v8::Object>(),
-                                      v8::Local<v8::Function>());
-    return;
-  }
   if (feature == "RootScroller") {
     if (contextData->getExistingConstructorAndPrototypeForType(
             &V8Document::wrapperTypeInfo, &prototypeObject, &interfaceObject)) {
diff --git a/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp b/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp
new file mode 100644
index 0000000..89c7538
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.cpp
@@ -0,0 +1,137 @@
+// 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 "bindings/core/v8/UseCounterCallback.h"
+
+#include "bindings/core/v8/V8Binding.h"
+#include "bindings/core/v8/V8PerIsolateData.h"
+#include "core/frame/Deprecation.h"
+#include "core/frame/UseCounter.h"
+
+namespace blink {
+
+void useCounterCallback(v8::Isolate* isolate,
+                        v8::Isolate::UseCounterFeature feature) {
+  if (V8PerIsolateData::from(isolate)->isUseCounterDisabled())
+    return;
+
+  UseCounter::Feature blinkFeature;
+  bool deprecated = false;
+  switch (feature) {
+    case v8::Isolate::kUseAsm:
+      blinkFeature = UseCounter::UseAsm;
+      break;
+    case v8::Isolate::kBreakIterator:
+      blinkFeature = UseCounter::BreakIterator;
+      break;
+    case v8::Isolate::kLegacyConst:
+      blinkFeature = UseCounter::LegacyConst;
+      break;
+    case v8::Isolate::kSloppyMode:
+      blinkFeature = UseCounter::V8SloppyMode;
+      break;
+    case v8::Isolate::kStrictMode:
+      blinkFeature = UseCounter::V8StrictMode;
+      break;
+    case v8::Isolate::kStrongMode:
+      blinkFeature = UseCounter::V8StrongMode;
+      break;
+    case v8::Isolate::kRegExpPrototypeStickyGetter:
+      blinkFeature = UseCounter::V8RegExpPrototypeStickyGetter;
+      break;
+    case v8::Isolate::kRegExpPrototypeToString:
+      blinkFeature = UseCounter::V8RegExpPrototypeToString;
+      break;
+    case v8::Isolate::kRegExpPrototypeUnicodeGetter:
+      blinkFeature = UseCounter::V8RegExpPrototypeUnicodeGetter;
+      break;
+    case v8::Isolate::kIntlV8Parse:
+      blinkFeature = UseCounter::V8IntlV8Parse;
+      break;
+    case v8::Isolate::kIntlPattern:
+      blinkFeature = UseCounter::V8IntlPattern;
+      break;
+    case v8::Isolate::kIntlResolved:
+      blinkFeature = UseCounter::V8IntlResolved;
+      break;
+    case v8::Isolate::kPromiseChain:
+      blinkFeature = UseCounter::V8PromiseChain;
+      break;
+    case v8::Isolate::kPromiseAccept:
+      blinkFeature = UseCounter::V8PromiseAccept;
+      break;
+    case v8::Isolate::kPromiseDefer:
+      blinkFeature = UseCounter::V8PromiseDefer;
+      break;
+    case v8::Isolate::kHtmlCommentInExternalScript:
+      blinkFeature = UseCounter::V8HTMLCommentInExternalScript;
+      break;
+    case v8::Isolate::kHtmlComment:
+      blinkFeature = UseCounter::V8HTMLComment;
+      break;
+    case v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition:
+      blinkFeature = UseCounter::V8SloppyModeBlockScopedFunctionRedefinition;
+      break;
+    case v8::Isolate::kForInInitializer:
+      blinkFeature = UseCounter::V8ForInInitializer;
+      break;
+    case v8::Isolate::kArrayProtectorDirtied:
+      blinkFeature = UseCounter::V8ArrayProtectorDirtied;
+      break;
+    case v8::Isolate::kArraySpeciesModified:
+      blinkFeature = UseCounter::V8ArraySpeciesModified;
+      break;
+    case v8::Isolate::kArrayPrototypeConstructorModified:
+      blinkFeature = UseCounter::V8ArrayPrototypeConstructorModified;
+      break;
+    case v8::Isolate::kArrayInstanceProtoModified:
+      blinkFeature = UseCounter::V8ArrayInstanceProtoModified;
+      break;
+    case v8::Isolate::kArrayInstanceConstructorModified:
+      blinkFeature = UseCounter::V8ArrayInstanceConstructorModified;
+      break;
+    case v8::Isolate::kLegacyFunctionDeclaration:
+      blinkFeature = UseCounter::V8LegacyFunctionDeclaration;
+      break;
+    case v8::Isolate::kRegExpPrototypeSourceGetter:
+      blinkFeature = UseCounter::V8RegExpPrototypeSourceGetter;
+      break;
+    case v8::Isolate::kRegExpPrototypeOldFlagGetter:
+      blinkFeature = UseCounter::V8RegExpPrototypeOldFlagGetter;
+      break;
+    case v8::Isolate::kDecimalWithLeadingZeroInStrictMode:
+      blinkFeature = UseCounter::V8DecimalWithLeadingZeroInStrictMode;
+      break;
+    case v8::Isolate::kLegacyDateParser:
+      blinkFeature = UseCounter::V8LegacyDateParser;
+      break;
+    case v8::Isolate::kDefineGetterOrSetterWouldThrow:
+      blinkFeature = UseCounter::V8DefineGetterOrSetterWouldThrow;
+      break;
+    case v8::Isolate::kFunctionConstructorReturnedUndefined:
+      blinkFeature = UseCounter::V8FunctionConstructorReturnedUndefined;
+      break;
+    case v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy:
+      blinkFeature = UseCounter::V8AssigmentExpressionLHSIsCallInSloppy;
+      break;
+    case v8::Isolate::kAssigmentExpressionLHSIsCallInStrict:
+      blinkFeature = UseCounter::V8AssigmentExpressionLHSIsCallInStrict;
+      break;
+    case v8::Isolate::kPromiseConstructorReturnedUndefined:
+      blinkFeature = UseCounter::V8PromiseConstructorReturnedUndefined;
+      break;
+    default:
+      // This can happen if V8 has added counters that this version of Blink
+      // does not know about. It's harmless.
+      return;
+  }
+  if (deprecated) {
+    Deprecation::countDeprecation(currentExecutionContext(isolate),
+                                  blinkFeature);
+  } else {
+    UseCounter::count(currentExecutionContext(isolate), blinkFeature);
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.h b/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.h
new file mode 100644
index 0000000..c8aab78
--- /dev/null
+++ b/third_party/WebKit/Source/bindings/core/v8/UseCounterCallback.h
@@ -0,0 +1,19 @@
+// 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 UseCounterCallback_h
+#define UseCounterCallback_h
+
+#include <v8.h>
+#include "core/CoreExport.h"
+
+namespace blink {
+
+// Callback that is used to count the number of times a V8 feature is used.
+CORE_EXPORT void useCounterCallback(v8::Isolate*,
+                                    v8::Isolate::UseCounterFeature);
+
+}  // namespace blink
+
+#endif  // UseCounterCallback_h
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8EventListenerInfo.h b/third_party/WebKit/Source/bindings/core/v8/V8EventListenerInfo.h
index 4b20e36..12e7372 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8EventListenerInfo.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8EventListenerInfo.h
@@ -19,14 +19,12 @@
                       bool passive,
                       bool once,
                       v8::Local<v8::Object> handler,
-                      v8::MaybeLocal<v8::Function> removeFunction,
                       int backendNodeId)
       : eventType(eventType),
         useCapture(useCapture),
         passive(passive),
         once(once),
         handler(handler),
-        removeFunction(removeFunction),
         backendNodeId(backendNodeId) {}
 
   AtomicString eventType;
@@ -34,7 +32,6 @@
   bool passive;
   bool once;
   v8::Local<v8::Object> handler;
-  v8::MaybeLocal<v8::Function> removeFunction;
   int backendNodeId;
 };
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
index 4cc6e33..29dffc50 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -25,6 +25,9 @@
 
 #include "bindings/core/v8/V8Initializer.h"
 
+#include <v8-debug.h>
+#include <v8-profiler.h>
+#include <memory>
 #include "bindings/core/v8/DOMWrapperWorld.h"
 #include "bindings/core/v8/RejectedPromises.h"
 #include "bindings/core/v8/RetainedDOMInfo.h"
@@ -32,6 +35,7 @@
 #include "bindings/core/v8/ScriptValue.h"
 #include "bindings/core/v8/ScriptWrappableVisitor.h"
 #include "bindings/core/v8/SourceLocation.h"
+#include "bindings/core/v8/UseCounterCallback.h"
 #include "bindings/core/v8/V8Binding.h"
 #include "bindings/core/v8/V8DOMException.h"
 #include "bindings/core/v8/V8ErrorEvent.h"
@@ -62,9 +66,6 @@
 #include "wtf/RefPtr.h"
 #include "wtf/text/WTFString.h"
 #include "wtf/typed_arrays/ArrayBufferContents.h"
-#include <memory>
-#include <v8-debug.h>
-#include <v8-profiler.h>
 
 namespace blink {
 
@@ -331,6 +332,8 @@
   v8::Debug::SetLiveEditEnabled(isolate, false);
 
   isolate->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
+
+  isolate->SetUseCounterCallback(&useCounterCallback);
 }
 
 namespace {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
index 1c99e56..3762d024 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.cpp
@@ -25,21 +25,20 @@
 
 #include "bindings/core/v8/V8PerIsolateData.h"
 
+#include <v8-debug.h>
+#include <memory>
 #include "bindings/core/v8/DOMDataStore.h"
 #include "bindings/core/v8/ScriptSourceCode.h"
-#include "bindings/core/v8/V8Binding.h"
 #include "bindings/core/v8/V8HiddenValue.h"
 #include "bindings/core/v8/V8ObjectConstructor.h"
 #include "bindings/core/v8/V8PrivateProperty.h"
 #include "bindings/core/v8/V8ScriptRunner.h"
-#include "core/frame/Deprecation.h"
+#include "bindings/core/v8/V8ValueCache.h"
 #include "core/inspector/MainThreadDebugger.h"
 #include "platform/ScriptForbiddenScope.h"
 #include "public/platform/Platform.h"
 #include "wtf/LeakAnnotations.h"
 #include "wtf/PtrUtil.h"
-#include <memory>
-#include <v8-debug.h>
 
 namespace blink {
 
@@ -72,7 +71,6 @@
   isolate()->AddMicrotasksCompletedCallback(&microtasksCompletedCallback);
   if (isMainThread())
     mainThreadPerIsolateData = this;
-  isolate()->SetUseCounterCallback(&useCounterCallback);
 }
 
 V8PerIsolateData::~V8PerIsolateData() {}
@@ -96,129 +94,6 @@
       std::unique_ptr<gin::V8IdleTaskRunner>(taskRunner.release()));
 }
 
-void V8PerIsolateData::useCounterCallback(
-    v8::Isolate* isolate,
-    v8::Isolate::UseCounterFeature feature) {
-  if (V8PerIsolateData::from(isolate)->m_useCounterDisabled)
-    return;
-
-  UseCounter::Feature blinkFeature;
-  bool deprecated = false;
-  switch (feature) {
-    case v8::Isolate::kUseAsm:
-      blinkFeature = UseCounter::UseAsm;
-      break;
-    case v8::Isolate::kBreakIterator:
-      blinkFeature = UseCounter::BreakIterator;
-      break;
-    case v8::Isolate::kLegacyConst:
-      blinkFeature = UseCounter::LegacyConst;
-      break;
-    case v8::Isolate::kSloppyMode:
-      blinkFeature = UseCounter::V8SloppyMode;
-      break;
-    case v8::Isolate::kStrictMode:
-      blinkFeature = UseCounter::V8StrictMode;
-      break;
-    case v8::Isolate::kStrongMode:
-      blinkFeature = UseCounter::V8StrongMode;
-      break;
-    case v8::Isolate::kRegExpPrototypeStickyGetter:
-      blinkFeature = UseCounter::V8RegExpPrototypeStickyGetter;
-      break;
-    case v8::Isolate::kRegExpPrototypeToString:
-      blinkFeature = UseCounter::V8RegExpPrototypeToString;
-      break;
-    case v8::Isolate::kRegExpPrototypeUnicodeGetter:
-      blinkFeature = UseCounter::V8RegExpPrototypeUnicodeGetter;
-      break;
-    case v8::Isolate::kIntlV8Parse:
-      blinkFeature = UseCounter::V8IntlV8Parse;
-      break;
-    case v8::Isolate::kIntlPattern:
-      blinkFeature = UseCounter::V8IntlPattern;
-      break;
-    case v8::Isolate::kIntlResolved:
-      blinkFeature = UseCounter::V8IntlResolved;
-      break;
-    case v8::Isolate::kPromiseChain:
-      blinkFeature = UseCounter::V8PromiseChain;
-      break;
-    case v8::Isolate::kPromiseAccept:
-      blinkFeature = UseCounter::V8PromiseAccept;
-      break;
-    case v8::Isolate::kPromiseDefer:
-      blinkFeature = UseCounter::V8PromiseDefer;
-      break;
-    case v8::Isolate::kHtmlCommentInExternalScript:
-      blinkFeature = UseCounter::V8HTMLCommentInExternalScript;
-      break;
-    case v8::Isolate::kHtmlComment:
-      blinkFeature = UseCounter::V8HTMLComment;
-      break;
-    case v8::Isolate::kSloppyModeBlockScopedFunctionRedefinition:
-      blinkFeature = UseCounter::V8SloppyModeBlockScopedFunctionRedefinition;
-      break;
-    case v8::Isolate::kForInInitializer:
-      blinkFeature = UseCounter::V8ForInInitializer;
-      break;
-    case v8::Isolate::kArrayProtectorDirtied:
-      blinkFeature = UseCounter::V8ArrayProtectorDirtied;
-      break;
-    case v8::Isolate::kArraySpeciesModified:
-      blinkFeature = UseCounter::V8ArraySpeciesModified;
-      break;
-    case v8::Isolate::kArrayPrototypeConstructorModified:
-      blinkFeature = UseCounter::V8ArrayPrototypeConstructorModified;
-      break;
-    case v8::Isolate::kArrayInstanceProtoModified:
-      blinkFeature = UseCounter::V8ArrayInstanceProtoModified;
-      break;
-    case v8::Isolate::kArrayInstanceConstructorModified:
-      blinkFeature = UseCounter::V8ArrayInstanceConstructorModified;
-      break;
-    case v8::Isolate::kLegacyFunctionDeclaration:
-      blinkFeature = UseCounter::V8LegacyFunctionDeclaration;
-      break;
-    case v8::Isolate::kRegExpPrototypeSourceGetter:
-      blinkFeature = UseCounter::V8RegExpPrototypeSourceGetter;
-      break;
-    case v8::Isolate::kRegExpPrototypeOldFlagGetter:
-      blinkFeature = UseCounter::V8RegExpPrototypeOldFlagGetter;
-      break;
-    case v8::Isolate::kDecimalWithLeadingZeroInStrictMode:
-      blinkFeature = UseCounter::V8DecimalWithLeadingZeroInStrictMode;
-      break;
-    case v8::Isolate::kLegacyDateParser:
-      blinkFeature = UseCounter::V8LegacyDateParser;
-      break;
-    case v8::Isolate::kDefineGetterOrSetterWouldThrow:
-      blinkFeature = UseCounter::V8DefineGetterOrSetterWouldThrow;
-      break;
-    case v8::Isolate::kFunctionConstructorReturnedUndefined:
-      blinkFeature = UseCounter::V8FunctionConstructorReturnedUndefined;
-      break;
-    case v8::Isolate::kAssigmentExpressionLHSIsCallInSloppy:
-      blinkFeature = UseCounter::V8AssigmentExpressionLHSIsCallInSloppy;
-      break;
-    case v8::Isolate::kAssigmentExpressionLHSIsCallInStrict:
-      blinkFeature = UseCounter::V8AssigmentExpressionLHSIsCallInStrict;
-      break;
-    case v8::Isolate::kPromiseConstructorReturnedUndefined:
-      blinkFeature = UseCounter::V8PromiseConstructorReturnedUndefined;
-      break;
-    default:
-      // This can happen if V8 has added counters that this version of Blink
-      // does not know about. It's harmless.
-      return;
-  }
-  if (deprecated)
-    Deprecation::countDeprecation(currentExecutionContext(isolate),
-                                  blinkFeature);
-  else
-    UseCounter::count(currentExecutionContext(isolate), blinkFeature);
-}
-
 v8::Persistent<v8::Value>& V8PerIsolateData::ensureLiveRoot() {
   if (m_liveRoot.isEmpty())
     m_liveRoot.set(isolate(), v8::Null(isolate()));
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.h b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.h
index 0f3ff9cc..5e93353 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8PerIsolateData.h
@@ -122,6 +122,8 @@
   bool isReportingException() const { return m_isReportingException; }
   void setReportingException(bool value) { m_isReportingException = value; }
 
+  bool isUseCounterDisabled() const { return m_useCounterDisabled; }
+
   V8HiddenValue* hiddenValue() { return m_hiddenValue.get(); }
   V8PrivateProperty* privateProperty() { return m_privateProperty.get(); }
 
@@ -206,8 +208,6 @@
   explicit V8PerIsolateData(WebTaskRunner*);
   ~V8PerIsolateData();
 
-  static void useCounterCallback(v8::Isolate*, v8::Isolate::UseCounterFeature);
-
   typedef HashMap<const void*, v8::Eternal<v8::FunctionTemplate>>
       V8FunctionTemplateMap;
   V8FunctionTemplateMap& selectInterfaceTemplateMap(const DOMWrapperWorld&);
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8PrivateProperty.h b/third_party/WebKit/Source/bindings/core/v8/V8PrivateProperty.h
index f81ba58..f0d103bd 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8PrivateProperty.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8PrivateProperty.h
@@ -21,23 +21,24 @@
 class ScriptWrappable;
 
 // Apply |X| for each pair of (InterfaceName, PrivateKeyName).
-#define V8_PRIVATE_PROPERTY_FOR_EACH(X)      \
-  X(CustomEvent, Detail)                     \
-  X(CustomElement, ConnectedCallback)        \
-  X(CustomElement, DisconnectedCallback)     \
-  X(CustomElement, AdoptedCallback)          \
-  X(CustomElement, AttributeChangedCallback) \
-  X(DOMException, Error)                     \
-  X(ErrorEvent, Error)                       \
-  X(IDBObserver, Callback)                   \
-  X(IntersectionObserver, Callback)          \
-  X(MessageEvent, CachedData)                \
-  X(MutationObserver, Callback)              \
-  X(PerformanceObserver, Callback)           \
-  X(SameObject, NotificationActions)         \
-  X(SameObject, NotificationData)            \
-  X(SameObject, NotificationVibrate)         \
-  X(V8NodeFilterCondition, Filter)           \
+#define V8_PRIVATE_PROPERTY_FOR_EACH(X)               \
+  X(CustomEvent, Detail)                              \
+  X(CustomElement, ConnectedCallback)                 \
+  X(CustomElement, DisconnectedCallback)              \
+  X(CustomElement, AdoptedCallback)                   \
+  X(CustomElement, AttributeChangedCallback)          \
+  X(DOMException, Error)                              \
+  X(ErrorEvent, Error)                                \
+  X(IDBObserver, Callback)                            \
+  X(IntersectionObserver, Callback)                   \
+  X(MessageEvent, CachedData)                         \
+  X(MutationObserver, Callback)                       \
+  X(PerformanceObserver, Callback)                    \
+  X(SameObject, NotificationActions)                  \
+  X(SameObject, NotificationData)                     \
+  X(SameObject, NotificationVibrate)                  \
+  X(SameObject, PerformanceLongTaskTimingAttribution) \
+  X(V8NodeFilterCondition, Filter)                    \
   X(Window, DocumentCachedAccessor)
 
 // The getter's name for a private property.
diff --git a/third_party/WebKit/Source/bindings/core/v8/custom/V8HTMLPlugInElementCustom.cpp b/third_party/WebKit/Source/bindings/core/v8/custom/V8HTMLPlugInElementCustom.cpp
index bb9a760..08fe5d3 100644
--- a/third_party/WebKit/Source/bindings/core/v8/custom/V8HTMLPlugInElementCustom.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/custom/V8HTMLPlugInElementCustom.cpp
@@ -132,47 +132,4 @@
   setScriptableObjectProperty<V8HTMLObjectElement>(name, value, info);
 }
 
-namespace {
-
-template <typename ElementType>
-void invokeOnScriptableObject(const v8::FunctionCallbackInfo<v8::Value>& info) {
-  HTMLPlugInElement* impl = ElementType::toImpl(info.Holder());
-  RefPtr<SharedPersistent<v8::Object>> wrapper = impl->pluginWrapper();
-  if (!wrapper)
-    return;
-
-  v8::Local<v8::Object> instance = wrapper->newLocal(info.GetIsolate());
-  if (instance.IsEmpty())
-    return;
-
-  std::unique_ptr<v8::Local<v8::Value>[]> arguments =
-      wrapArrayUnique(new v8::Local<v8::Value>[ info.Length() ]);
-  for (int i = 0; i < info.Length(); ++i)
-    arguments[i] = info[i];
-
-  v8::Local<v8::Value> retVal;
-  if (!instance
-           ->CallAsFunction(info.GetIsolate()->GetCurrentContext(),
-                            info.Holder(), info.Length(), arguments.get())
-           .ToLocal(&retVal))
-    return;
-  v8SetReturnValue(info, retVal);
-}
-
-}  // namespace
-
-void V8HTMLEmbedElement::legacyCallCustom(
-    const v8::FunctionCallbackInfo<v8::Value>& info) {
-  invokeOnScriptableObject<V8HTMLEmbedElement>(info);
-  Deprecation::countDeprecation(currentExecutionContext(info.GetIsolate()),
-                                UseCounter::HTMLEmbedElementLegacyCall);
-}
-
-void V8HTMLObjectElement::legacyCallCustom(
-    const v8::FunctionCallbackInfo<v8::Value>& info) {
-  invokeOnScriptableObject<V8HTMLObjectElement>(info);
-  Deprecation::countDeprecation(currentExecutionContext(info.GetIsolate()),
-                                UseCounter::HTMLObjectElementLegacyCall);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModules.cpp b/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModules.cpp
index f8239852..122e8f4 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModules.cpp
+++ b/third_party/WebKit/Source/bindings/modules/v8/V8BindingForModules.cpp
@@ -394,9 +394,8 @@
   if (!value || value->isNull())
     return v8::Null(isolate);
 
-  const SharedBuffer* valueData = value->data();
   RefPtr<SerializedScriptValue> serializedValue =
-      SerializedScriptValue::create(valueData->data(), valueData->size());
+      value->createSerializedValue();
   return serializedValue->deserialize(isolate, nullptr, value->blobInfo());
 }
 
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
index 2f2f84f..af01def 100755
--- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
+++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -10,7 +10,15 @@
 import template_expander
 import make_style_builder
 
-from name_utilities import camel_case, lower_first
+from name_utilities import camel_case, lower_first, upper_first_letter
+
+
+# Temporary hard-coded list of fields that are not CSS properties.
+# Ideally these would be specified in a .in or .json5 file.
+NONPROPERTY_FIELDS = set([
+    # Style can not be shared.
+    'unique',
+])
 
 
 class Field(object):
@@ -60,8 +68,9 @@
         # Field family: one of these must be true
         self.is_property = field_family == 'property'
         self.is_inherited_flag = field_family == 'inherited_flag'
-        assert (self.is_property, self.is_inherited_flag).count(True) == 1, \
-            'Field family has to be exactly one of: property, inherited_flag'
+        self.is_nonproperty = field_family == 'nonproperty'
+        assert (self.is_property, self.is_inherited_flag, self.is_nonproperty).count(True) == 1, \
+            'Field family has to be exactly one of: property, inherited_flag, nonproperty'
 
         if self.is_property:
             self.is_inherited = kwargs.pop('inherited')
@@ -176,6 +185,28 @@
     )
 
 
+def _create_nonproperty_field(field_name):
+    """
+    Create a nonproperty field from its name and return the Field object.
+    """
+    member_name = 'm_' + field_name
+    field_name_upper = upper_first_letter(field_name)
+
+    return Field(
+        'nonproperty',
+        name=member_name,
+        property_name=field_name,
+        storage_type='bool',
+        storage_type_path=None,
+        size=1,
+        default_value='false',
+        getter_method_name=field_name,
+        setter_method_name='set' + field_name_upper,
+        initial_method_name='initial' + field_name_upper,
+        resetter_method_name='reset' + field_name_upper,
+    )
+
+
 def _create_fields(properties):
     """
     Create ComputedStyle fields from CSS properties and return a list of Field objects.
@@ -191,6 +222,9 @@
 
             fields.append(_create_property_field(property_))
 
+    for field_name in NONPROPERTY_FIELDS:
+        fields.append(_create_nonproperty_field(field_name))
+
     return fields
 
 
diff --git a/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py b/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py
index f86922f7..c398046 100755
--- a/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py
+++ b/third_party/WebKit/Source/build/scripts/make_css_value_keywords.py
@@ -165,8 +165,16 @@
         gperf_args = [self.gperf_path, '--key-positions=*', '-P', '-n']
         gperf_args.extend(['-m', '50'])  # Pick best of 50 attempts.
         gperf_args.append('-D')  # Allow duplicate hashes -> More compact code.
-        gperf = subprocess.Popen(gperf_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
-        return gperf.communicate(gperf_input)[0]
+
+        # If gperf isn't in the path we get an OSError. We don't want to use
+        # the normal solution of shell=True (as this has to run on many
+        # platforms), so instead we catch the error and raise a
+        # CalledProcessError like subprocess would do when shell=True is set.
+        try:
+            gperf = subprocess.Popen(gperf_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
+            return gperf.communicate(gperf_input)[0]
+        except OSError:
+            raise subprocess.CalledProcessError(127, gperf_args, output='Command not found.')
 
 
 if __name__ == "__main__":
diff --git a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
index b72300c1..b89cff5 100644
--- a/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/ComputedStyleBase.h.tmpl
@@ -1,4 +1,4 @@
-{% from 'macros.tmpl' import license %}
+{% from 'macros.tmpl' import license, print_if %}
 {{license()}}
 
 #ifndef ComputedStyleBase_h
@@ -11,9 +11,10 @@
 {% endfor %}
 
 {# Returns the default value for the field, converted to fit in the storage container. #}
-{% macro default_value(field) %}
+{% macro default_value(field) -%}
 {# We only support enum fields for now. #}
-static_cast<unsigned>({{field.default_value}}){% endmacro %}
+static_cast<unsigned>({{field.default_value}})
+{%- endmacro %}
 
 namespace blink {
 
@@ -23,25 +24,23 @@
  public:
   ALWAYS_INLINE ComputedStyleBase() :
   {% for field in fields %}
-      {% set trailing_comma = "," if field != fields[-1] else "" %}
-      {{field.name}}({{default_value(field)}}){{trailing_comma}}
+      {{field.name}}({{default_value(field)}}){{print_if(not loop.last, ',')}}
   {% endfor %}
   {}
   ~ComputedStyleBase() {}
 
   ALWAYS_INLINE ComputedStyleBase(const ComputedStyleBase& o) :
   {% for field in fields %}
-      {% set trailing_comma = "," if field != fields[-1] else "" %}
-      {{field.name}}(o.{{field.name}}){{trailing_comma}}
+      {{field.name}}(o.{{field.name}}){{print_if(not loop.last, ',')}}
   {% endfor %}
   {}
 
   bool operator==(const ComputedStyleBase& o) const {
     return true &&
     {% for field in fields %}
-        {{field.name}} == o.{{field.name}} &&
+        {{field.name}} == o.{{field.name}}{{print_if(not loop.last, ' &&')}}
     {% endfor %}
-        true;
+        ;
   }
 
   bool operator!=(const ComputedStyleBase& o) const { return !(*this == o); }
@@ -49,33 +48,33 @@
   inline bool inheritedEqual(const ComputedStyleBase& o) const {
     return true &&
     {% for field in fields if field.is_property and field.is_inherited %}
-        {{field.name}} == o.{{field.name}} &&
+        {{field.name}} == o.{{field.name}}{{print_if(not loop.last, ' &&')}}
     {% endfor %}
-        true;
+        ;
   }
 
   inline bool independentInheritedEqual(const ComputedStyleBase& o) const {
     return true &&
     {% for field in fields if field.is_property and field.is_inherited and field.is_independent %}
-        {{field.name}} == o.{{field.name}} &&
+        {{field.name}} == o.{{field.name}}{{print_if(not loop.last, ' &&')}}
     {% endfor %}
-        true;
+        ;
   }
 
   inline bool nonIndependentInheritedEqual(const ComputedStyleBase& o) const {
     return true &&
     {% for field in fields if field.is_property and field.is_inherited and not field.is_independent %}
-        {{field.name}} == o.{{field.name}} &&
+        {{field.name}} == o.{{field.name}}{{print_if(not loop.last, ' &&')}}
     {% endfor %}
-        true;
+        ;
   }
 
   inline bool nonInheritedEqual(const ComputedStyleBase& o) const {
     return true &&
     {% for field in fields if field.is_property and not field.is_inherited %}
-        {{field.name}} == o.{{field.name}} &&
+        {{field.name}} == o.{{field.name}}{{print_if(not loop.last, ' &&')}}
     {% endfor %}
-        true;
+        ;
   }
 
   void setBitDefaults() {
@@ -105,7 +104,11 @@
   // {{field.property_name}}
   inline static {{field.storage_type}} {{field.initial_method_name}}() { return {{field.default_value}}; }
   {{field.storage_type}} {{field.getter_method_name}}() const { return static_cast<{{field.storage_type}}>({{field.name}}); }
+  {% if field.is_nonproperty %}
+  void {{field.setter_method_name}}() { {{field.name}} = static_cast<unsigned>(true); }
+  {% else %}
   void {{field.setter_method_name}}({{field.storage_type}} v) { {{field.name}} = static_cast<unsigned>(v); }
+  {% endif %}
   inline void {{field.resetter_method_name}}() { {{field.name}} = {{default_value(field)}}; }
 
   {% endfor %}
diff --git a/third_party/WebKit/Source/build/scripts/templates/macros.tmpl b/third_party/WebKit/Source/build/scripts/templates/macros.tmpl
index 17a9f49..d861741 100644
--- a/third_party/WebKit/Source/build/scripts/templates/macros.tmpl
+++ b/third_party/WebKit/Source/build/scripts/templates/macros.tmpl
@@ -55,3 +55,8 @@
 {% endfor %}
 }
 {% endmacro %}
+
+
+{% macro print_if(predicate, str) -%}
+{% if predicate %}{{str}}{% endif %}
+{%- endmacro %}
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index 10ce582140..7a78493 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -2058,19 +2058,19 @@
 inline CSSIdentifierValue::CSSIdentifierValue(EPosition e)
     : CSSValue(IdentifierClass) {
   switch (e) {
-    case StaticPosition:
+    case EPosition::kStatic:
       m_valueID = CSSValueStatic;
       break;
-    case RelativePosition:
+    case EPosition::kRelative:
       m_valueID = CSSValueRelative;
       break;
-    case AbsolutePosition:
+    case EPosition::kAbsolute:
       m_valueID = CSSValueAbsolute;
       break;
-    case FixedPosition:
+    case EPosition::kFixed:
       m_valueID = CSSValueFixed;
       break;
-    case StickyPosition:
+    case EPosition::kSticky:
       m_valueID = CSSValueSticky;
       break;
   }
@@ -2080,21 +2080,21 @@
 inline EPosition CSSIdentifierValue::convertTo() const {
   switch (m_valueID) {
     case CSSValueStatic:
-      return StaticPosition;
+      return EPosition::kStatic;
     case CSSValueRelative:
-      return RelativePosition;
+      return EPosition::kRelative;
     case CSSValueAbsolute:
-      return AbsolutePosition;
+      return EPosition::kAbsolute;
     case CSSValueFixed:
-      return FixedPosition;
+      return EPosition::kFixed;
     case CSSValueSticky:
-      return StickyPosition;
+      return EPosition::kSticky;
     default:
       break;
   }
 
   ASSERT_NOT_REACHED();
-  return StaticPosition;
+  return EPosition::kStatic;
 }
 
 template <>
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 1b1b5cc2..69aa317 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -765,15 +765,33 @@
     "box-sizing",
     {
       name: "break-after",
+      // Storage for this property also covers these legacy properties:
+      // page-break-after, -webkit-column-break-after
+      initial_keyword: "auto",
+      keyword_only: true,
+      keywords: [
+        "auto", "avoid", "avoid-column", "avoid-page", "column", "left", "page", "recto", "right", "verso"
+      ],
       type_name: "EBreakBetween",
     },
     {
       name: "break-before",
+      // Storage for this property also covers these legacy properties:
+      // page-break-before, -webkit-column-break-before
+      initial_keyword: "auto",
+      keyword_only: true,
+      keywords: [
+        "auto", "avoid", "avoid-column", "avoid-page", "column", "left", "page", "recto", "right", "verso"
+      ],
       type_name: "EBreakBetween",
     },
     {
       name: "break-inside",
-      type_name: "EBreakInside",
+      // Storage for this property also covers these legacy properties:
+      // page-break-inside, -webkit-column-break-inside
+      initial_keyword: "auto",
+      keyword_only: true,
+      keywords: ["auto", "avoid", "avoid-column", "avoid-page"],
     },
     {
       name: "buffered-rendering",
diff --git a/third_party/WebKit/Source/core/css/OWNERS b/third_party/WebKit/Source/core/css/OWNERS
new file mode 100644
index 0000000..64176816
--- /dev/null
+++ b/third_party/WebKit/Source/core/css/OWNERS
@@ -0,0 +1,2 @@
+meade@chromium.org
+suzyh@chromium.org
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
index 1a23328..291b8c7 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
@@ -155,7 +155,7 @@
   style.setDisplay(style.isFloating() ? EDisplay::Block : EDisplay::Inline);
 
   // CSS2 says first-letter can't be positioned.
-  style.setPosition(StaticPosition);
+  style.setPosition(EPosition::kStatic);
 }
 
 void StyleAdjuster::adjustStyleForAlignment(ComputedStyle& style,
@@ -223,7 +223,7 @@
     // Frames and framesets never honor position:relative or position:absolute.
     // This is necessary to fix a crash where a site tries to position these
     // objects. They also never honor display.
-    style.setPosition(StaticPosition);
+    style.setPosition(EPosition::kStatic);
     style.setDisplay(EDisplay::Block);
     return;
   }
@@ -239,7 +239,7 @@
   if (isHTMLRTElement(element)) {
     // Ruby text does not support float or position. This might change with
     // evolution of the specification.
-    style.setPosition(StaticPosition);
+    style.setPosition(EPosition::kStatic);
     style.setFloating(EFloat::kNone);
     return;
   }
@@ -336,16 +336,16 @@
        style.display() == EDisplay::TableRowGroup ||
        style.display() == EDisplay::TableFooterGroup ||
        style.display() == EDisplay::TableRow) &&
-      style.position() == RelativePosition)
-    style.setPosition(StaticPosition);
+      style.position() == EPosition::kRelative)
+    style.setPosition(EPosition::kStatic);
 
   // Cannot support position: sticky for table columns and column groups because
   // current code is only doing background painting through columns / column
   // groups.
   if ((style.display() == EDisplay::TableColumnGroup ||
        style.display() == EDisplay::TableColumn) &&
-      style.position() == StickyPosition)
-    style.setPosition(StaticPosition);
+      style.position() == EPosition::kSticky)
+    style.setPosition(EPosition::kStatic);
 
   // writing-mode does not apply to table row groups, table column groups, table
   // rows, and table columns.
@@ -394,9 +394,10 @@
 
     // Per the spec, position 'static' and 'relative' in the top layer compute
     // to 'absolute'.
-    if (isInTopLayer(element, style) && (style.position() == StaticPosition ||
-                                         style.position() == RelativePosition))
-      style.setPosition(AbsolutePosition);
+    if (isInTopLayer(element, style) &&
+        (style.position() == EPosition::kStatic ||
+         style.position() == EPosition::kRelative))
+      style.setPosition(EPosition::kAbsolute);
 
     // Absolute/fixed positioned elements, floating elements and the document
     // element need block-like outside display.
@@ -423,7 +424,7 @@
     style.setHasCompositorProxy(true);
 
   // Make sure our z-index value is only applied if the object is positioned.
-  if (style.position() == StaticPosition &&
+  if (style.position() == EPosition::kStatic &&
       !parentStyleForcesZIndexToCreateStackingContext(parentStyle)) {
     style.setIsStackingContext(false);
     // TODO(alancutter): Avoid altering z-index here.
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
index 7f86007..0169ed7b 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp
@@ -562,7 +562,7 @@
   // document element so that the common case doesn't need to create a new
   // ComputedStyle in Document::inheritHtmlAndBodyElementStyles.
   documentStyle->setDisplay(EDisplay::Block);
-  documentStyle->setPosition(AbsolutePosition);
+  documentStyle->setPosition(EPosition::kAbsolute);
 
   // Document::inheritHtmlAndBodyElementStyles will set the final overflow
   // style values, but they should initially be auto to avoid premature
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 77c1366b..4294b0b7 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -386,6 +386,10 @@
 
 // This doesn't work with non-Document ExecutionContext.
 static void runAutofocusTask(ExecutionContext* context) {
+  // Document lifecycle check is done in Element::focus()
+  if (!context)
+    return;
+
   Document* document = toDocument(context);
   if (Element* element = document->autofocusElement()) {
     document->setAutofocusElement(0);
@@ -3172,7 +3176,7 @@
 
   DCHECK(m_parser);
   InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
-      this, "document.write", true);
+      this, "document.write", true, true);
   m_parser->insert(text);
 }
 
@@ -5722,10 +5726,12 @@
 
 void Document::addConsoleMessage(ConsoleMessage* consoleMessage) {
   if (!isContextThread()) {
-    postTask(TaskType::Unthrottled, BLINK_FROM_HERE,
-             createCrossThreadTask(
-                 &runAddConsoleMessageTask, consoleMessage->source(),
-                 consoleMessage->level(), consoleMessage->message()));
+    TaskRunnerHelper::get(TaskType::Unthrottled, this)
+        ->postTask(
+            BLINK_FROM_HERE,
+            crossThreadBind(&runAddConsoleMessageTask, consoleMessage->source(),
+                            consoleMessage->level(), consoleMessage->message(),
+                            wrapCrossThreadPersistent(this)));
     return;
   }
 
@@ -6312,8 +6318,9 @@
   m_hasAutofocused = true;
   DCHECK(!m_autofocusElement);
   m_autofocusElement = element;
-  postTask(TaskType::UserInteraction, BLINK_FROM_HERE,
-           createSameThreadTask(&runAutofocusTask));
+  TaskRunnerHelper::get(TaskType::UserInteraction, this)
+      ->postTask(BLINK_FROM_HERE,
+                 WTF::bind(&runAutofocusTask, wrapWeakPersistent(this)));
 }
 
 Element* Document::activeElement() const {
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
index 50498e1..f85f7ca 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.cpp
@@ -66,19 +66,36 @@
                            bool createdDuringDocumentWrite)
     : m_element(element),
       m_startLineNumber(WTF::OrdinalNumber::beforeFirst()),
-      m_parserInserted(parserInserted),
-      m_isExternalScript(false),
-      m_alreadyStarted(alreadyStarted),
       m_haveFiredLoad(false),
       m_willBeParserExecuted(false),
-      m_readyToBeParserExecuted(false),
       m_willExecuteWhenDocumentFinishedParsing(false),
-      m_forceAsync(!parserInserted),
       m_createdDuringDocumentWrite(createdDuringDocumentWrite),
       m_asyncExecType(ScriptRunner::None),
       m_documentWriteIntervention(
           DocumentWriteIntervention::DocumentWriteInterventionNone) {
   DCHECK(m_element);
+
+  // https://html.spec.whatwg.org/#already-started
+  // "The cloning steps for script elements must set the "already started"
+  //  flag on the copy if it is set on the element being cloned."
+  // TODO(hiroshige): Cloning is implemented together with
+  // {HTML,SVG}ScriptElement::cloneElementWithoutAttributesAndChildren().
+  // Clean up these later.
+  if (alreadyStarted)
+    m_alreadyStarted = true;
+
+  if (parserInserted) {
+    // https://html.spec.whatwg.org/#parser-inserted
+    // "It is set by the HTML parser and the XML parser
+    //  on script elements they insert"
+    m_parserInserted = true;
+
+    // https://html.spec.whatwg.org/#non-blocking
+    // "It is unset by the HTML parser and the XML parser
+    //  on script elements they insert."
+    m_nonBlocking = false;
+  }
+
   if (parserInserted && element->document().scriptableDocumentParser() &&
       !element->document().isInDocumentWrite())
     m_startLineNumber =
@@ -118,7 +135,11 @@
 }
 
 void ScriptLoader::handleAsyncAttribute() {
-  m_forceAsync = false;
+  // https://html.spec.whatwg.org/#non-blocking
+  // "In addition, whenever a script element whose "non-blocking" flag is set
+  //  has an async content attribute added, the element's "non-blocking" flag
+  //  must be unset."
+  m_nonBlocking = false;
 }
 
 void ScriptLoader::detach() {
@@ -199,14 +220,20 @@
                                       supportLegacyTypes);
 }
 
-// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script
+// https://html.spec.whatwg.org/#prepare-a-script
 bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition,
                                  LegacyTypeSupport supportLegacyTypes) {
+  // 1. "If the script element is marked as having "already started", then
+  //     abort these steps at this point. The script is not executed."
   if (m_alreadyStarted)
     return false;
 
   ScriptLoaderClient* client = this->client();
 
+  // 2. "If the element has its "parser-inserted" flag set, then
+  //     set was-parser-inserted to true and unset the element's
+  //     "parser-inserted" flag.
+  //     Otherwise, set was-parser-inserted to false."
   bool wasParserInserted;
   if (m_parserInserted) {
     wasParserInserted = true;
@@ -215,44 +242,75 @@
     wasParserInserted = false;
   }
 
+  // 3. "If was-parser-inserted is true and the element does not have an
+  //     async attribute, then set the element's "non-blocking" flag to true."
   if (wasParserInserted && !client->asyncAttributeValue())
-    m_forceAsync = true;
+    m_nonBlocking = true;
 
+  // 4. "If the element has no src attribute, and its child nodes, if any,
+  //     consist only of comment nodes and empty Text nodes,
+  //     then abort these steps at this point. The script is not executed."
   // FIXME: HTML5 spec says we should check that all children are either
   // comments or empty text nodes.
   if (!client->hasSourceAttribute() && !m_element->hasChildren())
     return false;
 
+  // 5. "If the element is not connected, then abort these steps.
+  //     The script is not executed."
   if (!m_element->isConnected())
     return false;
 
+  // 6.
+  // TODO(hiroshige): Annotate and/or cleanup this step.
   if (!isScriptTypeSupported(supportLegacyTypes))
     return false;
 
+  // 7. "If was-parser-inserted is true,
+  //     then flag the element as "parser-inserted" again,
+  //     and set the element's "non-blocking" flag to false."
   if (wasParserInserted) {
     m_parserInserted = true;
-    m_forceAsync = false;
+    m_nonBlocking = false;
   }
 
+  // 8. "Set the element's "already started" flag."
   m_alreadyStarted = true;
 
+  // 9. "If the element is flagged as "parser-inserted", but the element's
+  // node document is not the Document of the parser that created the element,
+  // then abort these steps."
   // FIXME: If script is parser inserted, verify it's still in the original
   // document.
   Document& elementDocument = m_element->document();
   Document* contextDocument = elementDocument.contextDocument();
-
-  if (!contextDocument || !contextDocument->allowExecutingScripts(m_element))
+  if (!contextDocument)
     return false;
 
+  // 10. "If scripting is disabled for the script element, then abort these
+  //      steps at this point. The script is not executed."
+  if (!contextDocument->allowExecutingScripts(m_element))
+    return false;
+
+  // 13.
   if (!isScriptForEventSupported())
     return false;
 
+  // 14. "If the script element has a charset attribute,
+  //      then let encoding be the result of
+  //      getting an encoding from the value of the charset attribute."
+  //     "If the script element does not have a charset attribute,
+  //      or if getting an encoding failed, let encoding
+  //      be the same as the encoding of the script element's node document."
+  // TODO(hiroshige): Should we handle failure in getting an encoding?
   String encoding;
   if (!client->charsetAttributeValue().isEmpty())
     encoding = client->charsetAttributeValue();
   else
     encoding = elementDocument.characterSet();
 
+  // Steps 15--20 are handled in fetchScript().
+
+  // 21. "If the element has a src content attribute, run these substeps:"
   if (client->hasSourceAttribute()) {
     FetchRequest::DeferOption defer = FetchRequest::NoDefer;
     if (!m_parserInserted || client->asyncAttributeValue() ||
@@ -265,6 +323,29 @@
       return false;
   }
 
+  // 22. "If the element does not have a src content attribute,
+  //      run these substeps:"
+
+  // 22.1. "Let source text be the value of the text IDL attribute."
+  // This step is done later:
+  // - in ScriptLoader::pendingScript() (Step 23, 6th Clause),
+  //   as Element::textFromChildren() in ScriptLoader::scriptContent(),
+  // - in HTMLParserScriptRunner::processScriptElementInternal()
+  //   (Duplicated code of Step 23, 6th Clause),
+  //   as Element::textContent(),
+  // - in XMLDocumentParser::endElementNs() (Step 23, 5th Clause),
+  //   as Element::textFromChildren() in ScriptLoader::scriptContent(),
+  // - PendingScript::getSource() (Indirectly used via
+  //   HTMLParserScriptRunner::processScriptElementInternal(),
+  //   Step 23, 5th Clause),
+  //   as Element::textContent().
+  // TODO(hiroshige): Make them merged or consistent.
+
+  // 22.2. "Switch on the script's type:"
+  // TODO(hiroshige): Clarify how Step 22.2 is implemented for "classic".
+  // TODO(hiroshige): Implement Step 22.2 for "module".
+
+  // [Intervention]
   // Since the asynchronous, low priority fetch for doc.written blocked
   // script is not for execution, return early from here. Watch for its
   // completion to be able to remove it from the memory cache.
@@ -275,26 +356,109 @@
     return true;
   }
 
+  // 23. "Then, follow the first of the following options that describes the
+  //      situation:"
+
+  // Three flags are used to instruct the caller of prepareScript() to execute
+  // a part of Step 23, when |m_willBeParserExecuted| is true:
+  // - |m_willBeParserExecuted|
+  // - |m_willExecuteWhenDocumentFinishedParsing|
+  // - |m_readyToBeParserExecuted|
+  // TODO(hiroshige): Clean up the dependency.
+
+  // 1st Clause:
+  // - "If the script's type is "classic", and
+  //    the element has a src attribute, and the element has a defer attribute,
+  //    and the element has been flagged as "parser-inserted",
+  //    and the element does not have an async attribute"
+  // TODO(hiroshige): Check the script's type and implement "module" case.
   if (client->hasSourceAttribute() && client->deferAttributeValue() &&
       m_parserInserted && !client->asyncAttributeValue()) {
+    // This clause is implemented by the caller-side of prepareScript():
+    // - HTMLParserScriptRunner::requestDeferredScript(), and
+    // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs()
     m_willExecuteWhenDocumentFinishedParsing = true;
     m_willBeParserExecuted = true;
-  } else if (client->hasSourceAttribute() && m_parserInserted &&
-             !client->asyncAttributeValue()) {
+
+    return true;
+  }
+
+  // 2nd Clause:
+  // - "If the script's type is "classic",
+  //    and the element has a src attribute,
+  //    and the element has been flagged as "parser-inserted",
+  //    and the element does not have an async attribute"
+  // TODO(hiroshige): Check the script's type.
+  if (client->hasSourceAttribute() && m_parserInserted &&
+      !client->asyncAttributeValue()) {
+    // This clause is implemented by the caller-side of prepareScript():
+    // - HTMLParserScriptRunner::requestParsingBlockingScript()
+    // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs()
     m_willBeParserExecuted = true;
-  } else if (!client->hasSourceAttribute() && m_parserInserted &&
-             !elementDocument.isScriptExecutionReady()) {
+
+    return true;
+  }
+
+  // 5th Clause:
+  // TODO(hiroshige): Reorder the clauses to match the spec.
+  // - "If the element does not have a src attribute,
+  //    and the element has been flagged as "parser-inserted",
+  //    and either the parser that created the script is an XML parser
+  //      or it's an HTML parser whose script nesting level is not greater than
+  //      one,
+  //    and the Document of the HTML parser or XML parser that created
+  //      the script element has a style sheet that is blocking scripts"
+  // The last part "... has a style sheet that is blocking scripts"
+  // is implemented in Document::isScriptExecutionReady().
+  // Part of the condition check is done in
+  // HTMLParserScriptRunner::processScriptElementInternal().
+  // TODO(hiroshige): Clean up the split condition check.
+  if (!client->hasSourceAttribute() && m_parserInserted &&
+      !elementDocument.isScriptExecutionReady()) {
+    // The former part of this clause is
+    // implemented by the caller-side of prepareScript():
+    // - HTMLParserScriptRunner::requestParsingBlockingScript()
+    // - TODO(hiroshige): Investigate XMLDocumentParser::endElementNs()
     m_willBeParserExecuted = true;
+    // "Set the element's "ready to be parser-executed" flag."
     m_readyToBeParserExecuted = true;
-  } else if (client->hasSourceAttribute() && !client->asyncAttributeValue() &&
-             !m_forceAsync) {
+
+    return true;
+  }
+
+  // 3rd Clause:
+  // - "If the script's type is "classic",
+  //    and the element has a src attribute,
+  //    and the element does not have an async attribute,
+  //    and the element does not have the "non-blocking" flag set"
+  // TODO(hiroshige): Check the script's type and implement "module" case.
+  if (client->hasSourceAttribute() && !client->asyncAttributeValue() &&
+      !m_nonBlocking) {
+    // "Add the element to the end of the list of scripts that will execute
+    // in order as soon as possible associated with the node document of the
+    // script element at the time the prepare a script algorithm started."
     m_pendingScript = PendingScript::create(m_element, m_resource.get());
     m_asyncExecType = ScriptRunner::InOrder;
+    // TODO(hiroshige): Here |contextDocument| is used as "node document"
+    // while Step 14 uses |elementDocument| as "node document". Fix this.
     contextDocument->scriptRunner()->queueScriptForExecution(this,
                                                              m_asyncExecType);
     // Note that watchForLoad can immediately call pendingScriptFinished.
     m_pendingScript->watchForLoad(this);
-  } else if (client->hasSourceAttribute()) {
+    // The part "When the script is ready..." is implemented in
+    // ScriptRunner::notifyScriptReady().
+    // TODO(hiroshige): Annotate it.
+
+    return true;
+  }
+
+  // 4th Clause:
+  // - "If the script's type is "classic", and the element has a src attribute"
+  // TODO(hiroshige): Check the script's type and implement "module" case.
+  if (client->hasSourceAttribute()) {
+    // "The element must be added to the set of scripts that will execute
+    //  as soon as possible of the node document of the script element at the
+    //  time the prepare a script algorithm started."
     m_pendingScript = PendingScript::create(m_element, m_resource.get());
     m_asyncExecType = ScriptRunner::Async;
     LocalFrame* frame = m_element->document().frame();
@@ -305,28 +469,47 @@
             m_pendingScript.get(), ScriptStreamer::Async, frame->settings(),
             scriptState, frame->frameScheduler()->loadingTaskRunner());
     }
+    // TODO(hiroshige): Here |contextDocument| is used as "node document"
+    // while Step 14 uses |elementDocument| as "node document". Fix this.
     contextDocument->scriptRunner()->queueScriptForExecution(this,
                                                              m_asyncExecType);
     // Note that watchForLoad can immediately call pendingScriptFinished.
     m_pendingScript->watchForLoad(this);
-  } else {
-    // Reset line numbering for nested writes.
-    TextPosition position = elementDocument.isInDocumentWrite()
-                                ? TextPosition()
-                                : scriptStartPosition;
-    KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInserted)
-                         ? elementDocument.url()
-                         : KURL();
-    if (!executeScript(
-            ScriptSourceCode(scriptContent(), scriptURL, position))) {
-      dispatchErrorEvent();
-      return false;
-    }
+    // The part "When the script is ready..." is implemented in
+    // ScriptRunner::notifyScriptReady().
+    // TODO(hiroshige): Annotate it.
+
+    return true;
+  }
+
+  // 6th Clause:
+  // - "Otherwise"
+  // "Immediately execute the script block,
+  //  even if other scripts are already executing."
+  // Note: this block is also duplicated in
+  // HTMLParserScriptRunner::processScriptElementInternal().
+  // TODO(hiroshige): Merge the duplicated code.
+
+  // This clause is executed only if the script's type is "classic"
+  // and the element doesn't have a src attribute.
+
+  // Reset line numbering for nested writes.
+  TextPosition position = elementDocument.isInDocumentWrite()
+                              ? TextPosition()
+                              : scriptStartPosition;
+  KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInserted)
+                       ? elementDocument.url()
+                       : KURL();
+
+  if (!executeScript(ScriptSourceCode(scriptContent(), scriptURL, position))) {
+    dispatchErrorEvent();
+    return false;
   }
 
   return true;
 }
 
+// Steps 15--21 of https://html.spec.whatwg.org/#prepare-a-script
 bool ScriptLoader::fetchScript(const String& sourceUrl,
                                const String& encoding,
                                FetchRequest::DeferOption defer) {
@@ -337,26 +520,47 @@
     return false;
 
   DCHECK(!m_resource);
+  // 21. "If the element has a src content attribute, run these substeps:"
   if (!stripLeadingAndTrailingHTMLSpaces(sourceUrl).isEmpty()) {
+    // 21.4. "Parse src relative to the element's node document."
     FetchRequest request(
         ResourceRequest(elementDocument->completeURL(sourceUrl)),
         m_element->localName());
 
+    // 15. "Let CORS setting be the current state of the element's
+    //      crossorigin content attribute."
     CrossOriginAttributeValue crossOrigin = crossOriginAttributeValue(
         m_element->fastGetAttribute(HTMLNames::crossoriginAttr));
+
+    // 16. "Let module script credentials mode be determined by switching
+    //      on CORS setting:"
+    // TODO(hiroshige): Implement this step for "module".
+
+    // 21.6, "classic": "Fetch a classic script given ... CORS setting
+    //                   ... and encoding."
     if (crossOrigin != CrossOriginAttributeNotSet)
       request.setCrossOriginAccessControl(elementDocument->getSecurityOrigin(),
                                           crossOrigin);
+
     request.setCharset(encoding);
 
+    // 17. "If the script element has a nonce attribute,
+    //      then let cryptographic nonce be that attribute's value.
+    //      Otherwise, let cryptographic nonce be the empty string."
     if (ContentSecurityPolicy::isNonceableElement(m_element.get()))
       request.setContentSecurityPolicyNonce(client()->nonce());
 
+    // 19. "Let parser state be "parser-inserted"
+    //      if the script element has been flagged as "parser-inserted",
+    //      and "not parser-inserted" otherwise."
     request.setParserDisposition(isParserInserted() ? ParserInserted
                                                     : NotParserInserted);
 
     request.setDefer(defer);
 
+    // 18. "If the script element has an integrity attribute,
+    //      then let integrity metadata be that attribute's value.
+    //      Otherwise, let integrity metadata be the empty string."
     String integrityAttr =
         m_element->fastGetAttribute(HTMLNames::integrityAttr);
     if (!integrityAttr.isEmpty()) {
@@ -366,6 +570,7 @@
       request.setIntegrityMetadata(metadataSet);
     }
 
+    // [Intervention]
     if (m_documentWriteIntervention ==
         DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) {
       request.mutableResourceRequest().setHTTPHeaderField(
@@ -373,16 +578,43 @@
           "<https://www.chromestatus.com/feature/5718547946799104>");
     }
 
+    // 21.6. "Switch on the script's type:"
+
+    // - "classic":
+    //   "Fetch a classic script given url, settings, cryptographic nonce,
+    //    integrity metadata, parser state, CORS setting, and encoding."
     m_resource = ScriptResource::fetch(request, elementDocument->fetcher());
 
+    // - "module":
+    //   "Fetch a module script graph given url, settings, "script",
+    //    cryptographic nonce, parser state, and
+    //    module script credentials mode."
+    // TODO(kouhei, hiroshige): Implement this.
+
+    // "When the chosen algorithm asynchronously completes, set
+    //  the script's script to the result. At that time, the script is ready."
+    // When the script is ready, PendingScriptClient::pendingScriptFinished()
+    // is used as the notification, and the action to take when
+    // the script is ready is specified later, in
+    // - ScriptLoader::prepareScript(), or
+    // - HTMLParserScriptRunner,
+    // depending on the conditions in Step 23 of "prepare a script".
+
+    // 21.3. "Set the element's from an external file flag."
     m_isExternalScript = true;
   }
 
   if (!m_resource) {
+    // 21.2. "If src is the empty string, queue a task to
+    //        fire an event named error at the element, and abort these steps."
+    // 21.5. "If the previous step failed, queue a task to
+    //        fire an event named error at the element, and abort these steps."
+    // TODO(hiroshige): Make this asynchronous.
     dispatchErrorEvent();
     return false;
   }
 
+  // [Intervention]
   if (m_createdDuringDocumentWrite &&
       m_resource->resourceRequest().getCachePolicy() ==
           WebCachePolicy::ReturnCacheDataDontLoad) {
@@ -611,16 +843,30 @@
          !element() || !element()->isConnected();
 }
 
+// Step 13 of https://html.spec.whatwg.org/#prepare-a-script
 bool ScriptLoader::isScriptForEventSupported() const {
+  // 1. "Let for be the value of the for attribute."
   String eventAttribute = client()->eventAttributeValue();
+  // 2. "Let event be the value of the event attribute."
   String forAttribute = client()->forAttributeValue();
+
+  // "If the script element has an event attribute and a for attribute, and
+  //  the script's type is "classic", then run these substeps:"
+  // TODO(hiroshige): Check the script's type.
   if (eventAttribute.isNull() || forAttribute.isNull())
     return true;
 
+  // 3. "Strip leading and trailing ASCII whitespace from event and for."
   forAttribute = forAttribute.stripWhiteSpace();
+  // 4. "If for is not an ASCII case-insensitive match for the string
+  //     "window",
+  //     then abort these steps at this point. The script is not executed."
   if (!equalIgnoringCase(forAttribute, "window"))
     return false;
   eventAttribute = eventAttribute.stripWhiteSpace();
+  // 5. "If event is not an ASCII case-insensitive match for either the
+  //     string "onload" or the string "onload()",
+  //     then abort these steps at this point. The script is not executed.
   return equalIgnoringCase(eventAttribute, "onload") ||
          equalIgnoringCase(eventAttribute, "onload()");
 }
diff --git a/third_party/WebKit/Source/core/dom/ScriptLoader.h b/third_party/WebKit/Source/core/dom/ScriptLoader.h
index 3935fe1..d483642b 100644
--- a/third_party/WebKit/Source/core/dom/ScriptLoader.h
+++ b/third_party/WebKit/Source/core/dom/ScriptLoader.h
@@ -64,6 +64,7 @@
       const String& languageAttributeValue,
       LegacyTypeSupport supportLegacyTypes);
 
+  // https://html.spec.whatwg.org/#prepare-a-script
   bool prepareScript(
       const TextPosition& scriptStartPosition = TextPosition::minimumPosition(),
       LegacyTypeSupport = DisallowLegacyTypeInTypeAttribute);
@@ -91,7 +92,7 @@
   }
   bool isParserInserted() const { return m_parserInserted; }
   bool alreadyStarted() const { return m_alreadyStarted; }
-  bool forceAsync() const { return m_forceAsync; }
+  bool isNonBlocking() const { return m_nonBlocking; }
 
   // Helper functions used by our parent classes.
   void didNotifySubtreeInsertionsToDocument();
@@ -142,16 +143,40 @@
   Member<ScriptResource> m_resource;
   WTF::OrdinalNumber m_startLineNumber;
 
-  bool m_parserInserted : 1;
-  bool m_isExternalScript : 1;
-  bool m_alreadyStarted : 1;
-  bool m_haveFiredLoad : 1;
+  // https://html.spec.whatwg.org/#script-processing-model
+  // "A script element has several associated pieces of state.":
+
+  // https://html.spec.whatwg.org/#already-started
+  // "Initially, script elements must have this flag unset"
+  bool m_alreadyStarted = false;
+
+  // https://html.spec.whatwg.org/#parser-inserted
+  // "Initially, script elements must have this flag unset."
+  bool m_parserInserted = false;
+
+  // https://html.spec.whatwg.org/#non-blocking
+  // "Initially, script elements must have this flag set."
+  bool m_nonBlocking = true;
+
+  // https://html.spec.whatwg.org/#ready-to-be-parser-executed
+  // "Initially, script elements must have this flag unset"
+  bool m_readyToBeParserExecuted = false;
+
+  // https://html.spec.whatwg.org/#concept-script-type
+  // TODO(hiroshige): Implement "script's type".
+
+  // https://html.spec.whatwg.org/#concept-script-external
+  // "It is determined when the script is prepared"
+  bool m_isExternalScript = false;
+
+  bool m_haveFiredLoad;
+
   // Same as "The parser will handle executing the script."
-  bool m_willBeParserExecuted : 1;
-  bool m_readyToBeParserExecuted : 1;
-  bool m_willExecuteWhenDocumentFinishedParsing : 1;
-  bool m_forceAsync : 1;
-  const bool m_createdDuringDocumentWrite : 1;
+  bool m_willBeParserExecuted;
+
+  bool m_willExecuteWhenDocumentFinishedParsing;
+
+  const bool m_createdDuringDocumentWrite;
 
   ScriptRunner::AsyncExecutionType m_asyncExecType;
   enum DocumentWriteIntervention {
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index 20b6dfd..67954983 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -95,31 +95,39 @@
 }
 
 Node* DOMSelection::anchorNode() const {
-  if (!isAvailable())
-    return 0;
-
-  return shadowAdjustedNode(anchorPosition(visibleSelection()));
+  if (Range* range = primaryRangeOrNull()) {
+    if (!frame() || visibleSelection().isBaseFirst())
+      return range->startContainer();
+    return range->endContainer();
+  }
+  return nullptr;
 }
 
 int DOMSelection::anchorOffset() const {
-  if (!isAvailable())
-    return 0;
-
-  return shadowAdjustedOffset(anchorPosition(visibleSelection()));
+  if (Range* range = primaryRangeOrNull()) {
+    if (!frame() || visibleSelection().isBaseFirst())
+      return range->startOffset();
+    return range->endOffset();
+  }
+  return 0;
 }
 
 Node* DOMSelection::focusNode() const {
-  if (!isAvailable())
-    return 0;
-
-  return shadowAdjustedNode(focusPosition(visibleSelection()));
+  if (Range* range = primaryRangeOrNull()) {
+    if (!frame() || visibleSelection().isBaseFirst())
+      return range->endContainer();
+    return range->startContainer();
+  }
+  return nullptr;
 }
 
 int DOMSelection::focusOffset() const {
-  if (!isAvailable())
-    return 0;
-
-  return shadowAdjustedOffset(focusPosition(visibleSelection()));
+  if (Range* range = primaryRangeOrNull()) {
+    if (!frame() || visibleSelection().isBaseFirst())
+      return range->endOffset();
+    return range->startOffset();
+  }
+  return 0;
 }
 
 Node* DOMSelection::baseNode() const {
@@ -153,21 +161,20 @@
 bool DOMSelection::isCollapsed() const {
   if (!isAvailable() || selectionShadowAncestor(frame()))
     return true;
-  return !frame()->selection().isRange();
+  if (Range* range = primaryRangeOrNull())
+    return range->collapsed();
+  return true;
 }
 
 String DOMSelection::type() const {
   if (!isAvailable())
     return String();
-
-  FrameSelection& selection = frame()->selection();
-
   // This is a WebKit DOM extension, incompatible with an IE extension
   // IE has this same attribute, but returns "none", "text" and "control"
   // http://msdn.microsoft.com/en-us/library/ms534692(VS.85).aspx
-  if (selection.isNone())
+  if (rangeCount() == 0)
     return "None";
-  if (selection.isCaret())
+  if (isCollapsed())
     return "Caret";
   return "Range";
 }
@@ -414,7 +421,8 @@
                                         .build());
 }
 
-Range* DOMSelection::getRangeAt(int index, ExceptionState& exceptionState) {
+Range* DOMSelection::getRangeAt(int index,
+                                ExceptionState& exceptionState) const {
   if (!isAvailable())
     return nullptr;
 
@@ -435,26 +443,33 @@
   return range;
 }
 
-Range* DOMSelection::createRangeFromSelectionEditor() {
+Range* DOMSelection::primaryRangeOrNull() const {
+  return rangeCount() > 0 ? getRangeAt(0, ASSERT_NO_EXCEPTION) : nullptr;
+}
+
+Range* DOMSelection::createRangeFromSelectionEditor() const {
   Position anchor = anchorPosition(visibleSelection());
-  if (!anchor.anchorNode()->isInShadowTree())
+  if (isSelectionOfDocument() && !anchor.anchorNode()->isInShadowTree())
     return frame()->selection().firstRange();
 
   Node* node = shadowAdjustedNode(anchor);
   if (!node)  // crbug.com/595100
     return nullptr;
-  if (!visibleSelection().isBaseFirst())
-    return Range::create(*anchor.document(), focusNode(), focusOffset(), node,
-                         anchorOffset());
-  return Range::create(*anchor.document(), node, anchorOffset(), focusNode(),
-                       focusOffset());
+  Position focus = focusPosition(visibleSelection());
+  if (!visibleSelection().isBaseFirst()) {
+    return Range::create(*anchor.document(), shadowAdjustedNode(focus),
+                         shadowAdjustedOffset(focus), node,
+                         shadowAdjustedOffset(anchor));
+  }
+  return Range::create(*anchor.document(), node, shadowAdjustedOffset(anchor),
+                       shadowAdjustedNode(focus), shadowAdjustedOffset(focus));
 }
 
 bool DOMSelection::isSelectionOfDocument() const {
   return m_treeScope == m_treeScope->document();
 }
 
-void DOMSelection::cacheRangeIfSelectionOfDocument(Range* range) {
+void DOMSelection::cacheRangeIfSelectionOfDocument(Range* range) const {
   if (!isSelectionOfDocument())
     return;
   frame()->selection().cacheRangeOfDocument(range);
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.h b/third_party/WebKit/Source/core/editing/DOMSelection.h
index fa2cf7e..9723ea4 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.h
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.h
@@ -89,7 +89,7 @@
   void collapseToEnd(ExceptionState&);
   void collapseToStart(ExceptionState&);
   void extend(Node*, int offset, ExceptionState&);
-  Range* getRangeAt(int, ExceptionState&);
+  Range* getRangeAt(int, ExceptionState&) const;
   void removeAllRanges();
   void addRange(Range*);
   void deleteFromDocument();
@@ -117,11 +117,11 @@
   bool isValidForPosition(Node*) const;
 
   void addConsoleError(const String& message);
-
-  Range* createRangeFromSelectionEditor();
+  Range* primaryRangeOrNull() const;
+  Range* createRangeFromSelectionEditor() const;
 
   bool isSelectionOfDocument() const;
-  void cacheRangeIfSelectionOfDocument(Range*);
+  void cacheRangeIfSelectionOfDocument(Range*) const;
   Range* documentCachedRange() const;
   void clearCachedRangeIfSelectionOfDocument();
 
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
index dd5e4e66..b289e5d 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -81,21 +81,19 @@
   return true;
 }
 
-DispatchEventResult dispatchBeforeInputFromComposition(
-    EventTarget* target,
-    InputEvent::InputType inputType,
-    const String& data,
-    InputEvent::EventCancelable cancelable) {
+void dispatchBeforeInputFromComposition(EventTarget* target,
+                                        InputEvent::InputType inputType,
+                                        const String& data) {
   if (!RuntimeEnabledFeatures::inputEventEnabled())
-    return DispatchEventResult::NotCanceled;
+    return;
   if (!target)
-    return DispatchEventResult::NotCanceled;
+    return;
   // TODO(chongz): Pass appropriate |ranges| after it's defined on spec.
   // http://w3c.github.io/editing/input-events.html#dom-inputevent-inputtype
   InputEvent* beforeInputEvent = InputEvent::createBeforeInput(
-      inputType, data, cancelable, InputEvent::EventIsComposing::IsComposing,
-      nullptr);
-  return target->dispatchEvent(beforeInputEvent);
+      inputType, data, InputEvent::NotCancelable,
+      InputEvent::EventIsComposing::IsComposing, nullptr);
+  target->dispatchEvent(beforeInputEvent);
 }
 
 // Used to insert/replace text during composition update and confirm
@@ -127,21 +125,8 @@
   if (!target)
     return;
 
-  // TODO(chongz): Fire 'beforeinput' for the composed text being
-  // replaced/deleted.
-
-  // Only the last confirmed text is cancelable.
-  InputEvent::EventCancelable beforeInputCancelable =
-      (compositionType ==
-       TypingCommand::TextCompositionType::TextCompositionUpdate)
-          ? InputEvent::EventCancelable::NotCancelable
-          : InputEvent::EventCancelable::IsCancelable;
-  DispatchEventResult result = dispatchBeforeInputFromComposition(
-      target, InputEvent::InputType::InsertText, text, beforeInputCancelable);
-
-  if (beforeInputCancelable == InputEvent::EventCancelable::IsCancelable &&
-      result != DispatchEventResult::NotCanceled)
-    return;
+  dispatchBeforeInputFromComposition(
+      target, InputEvent::InputType::InsertCompositionText, text);
 
   // 'beforeinput' event handler may destroy document.
   if (!frame.document())
@@ -343,12 +328,6 @@
   if (!isAvailable())
     return false;
 
-  // If text is empty, then delete the old composition here. If text is
-  // non-empty, InsertTextCommand::input will delete the old composition with
-  // an optimized replace operation.
-  if (text.isEmpty())
-    TypingCommand::deleteSelection(document(), 0);
-
   clear();
 
   insertTextDuringCompositionWithEvents(
@@ -462,12 +441,6 @@
 
   clear();
 
-  // TODO(chongz): Figure out which InputType should we use here.
-  dispatchBeforeInputFromComposition(
-      document().focusedElement(),
-      InputEvent::InputType::DeleteComposedCharacterBackward, nullAtom,
-      InputEvent::EventCancelable::NotCancelable);
-  dispatchCompositionUpdateEvent(frame(), emptyString);
   insertTextDuringCompositionWithEvents(
       frame(), emptyString, 0,
       TypingCommand::TextCompositionType::TextCompositionCancel);
diff --git a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
index d89e9b1..af4913f 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
@@ -1034,7 +1034,7 @@
   // Delete the existing composition.
   document().setTitle(emptyString);
   controller().setComposition("", underlines, 0, 0);
-  EXPECT_STREQ("beforeinput.data:;compositionend.data:;",
+  EXPECT_STREQ("beforeinput.data:;input.data:;compositionend.data:;",
                document().title().utf8().data());
 }
 
@@ -1088,7 +1088,7 @@
   document().setTitle(emptyString);
   document().updateStyleAndLayout();
   controller().commitText("", underlines, 1);
-  EXPECT_STREQ("beforeinput.data:;compositionend.data:;",
+  EXPECT_STREQ("beforeinput.data:;input.data:;compositionend.data:;",
                document().title().utf8().data());
 }
 
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.h b/third_party/WebKit/Source/core/editing/VisibleSelection.h
index dcf1ee5..6da5081c 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.h
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.h
@@ -116,6 +116,7 @@
     return !isNone() && !start().isOrphan() && !end().isOrphan();
   }
 
+  // True if base() <= extent().
   bool isBaseFirst() const { return m_baseIsFirst; }
   bool isDirectional() const { return m_isDirectional; }
   void setIsDirectional(bool isDirectional) { m_isDirectional = isDirectional; }
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index c9d2451..aa29a5f5 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -99,8 +99,7 @@
       case InputEvent::InputType::InsertFromPaste:
       case InputEvent::InputType::InsertFromDrop:
       case InputEvent::InputType::InsertReplacementText:
-      case InputEvent::InputType::DeleteComposedCharacterForward:
-      case InputEvent::InputType::DeleteComposedCharacterBackward:
+      case InputEvent::InputType::InsertCompositionText:
       case InputEvent::InputType::DeleteWordBackward:
       case InputEvent::InputType::DeleteWordForward:
       case InputEvent::InputType::DeleteLineBackward:
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index a10d26b..96643333 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -453,19 +453,18 @@
 InputEvent::InputType TypingCommand::inputType() const {
   using InputType = InputEvent::InputType;
 
+  if (m_compositionType != TextCompositionNone)
+    return InputType::InsertCompositionText;
+
   switch (m_commandType) {
     // TODO(chongz): |DeleteSelection| is used by IME but we don't have
     // direction info.
     case DeleteSelection:
       return InputType::DeleteContentBackward;
     case DeleteKey:
-      if (m_compositionType != TextCompositionNone)
-        return InputType::DeleteComposedCharacterBackward;
       return deletionInputTypeFromTextGranularity(DeleteDirection::Backward,
                                                   m_granularity);
     case ForwardDeleteKey:
-      if (m_compositionType != TextCompositionNone)
-        return InputType::DeleteComposedCharacterForward;
       return deletionInputTypeFromTextGranularity(DeleteDirection::Forward,
                                                   m_granularity);
     case InsertText:
diff --git a/third_party/WebKit/Source/core/events/InputEvent.cpp b/third_party/WebKit/Source/core/events/InputEvent.cpp
index c4679d3c..fec9334 100644
--- a/third_party/WebKit/Source/core/events/InputEvent.cpp
+++ b/third_party/WebKit/Source/core/events/InputEvent.cpp
@@ -26,10 +26,7 @@
     {InputEvent::InputType::InsertFromPaste, "insertFromPaste"},
     {InputEvent::InputType::InsertFromDrop, "insertFromDrop"},
     {InputEvent::InputType::InsertReplacementText, "insertReplacementText"},
-    {InputEvent::InputType::DeleteComposedCharacterForward,
-     "deleteComposedCharacterForward"},
-    {InputEvent::InputType::DeleteComposedCharacterBackward,
-     "deleteComposedCharacterBackward"},
+    {InputEvent::InputType::InsertCompositionText, "insertCompositionText"},
     {InputEvent::InputType::DeleteWordBackward, "deleteWordBackward"},
     {InputEvent::InputType::DeleteWordForward, "deleteWordForward"},
     {InputEvent::InputType::DeleteLineBackward, "deleteLineBackward"},
diff --git a/third_party/WebKit/Source/core/events/InputEvent.h b/third_party/WebKit/Source/core/events/InputEvent.h
index 3d0f4f2e..5810fe66 100644
--- a/third_party/WebKit/Source/core/events/InputEvent.h
+++ b/third_party/WebKit/Source/core/events/InputEvent.h
@@ -35,9 +35,8 @@
     InsertFromPaste,
     InsertFromDrop,
     InsertReplacementText,
+    InsertCompositionText,
     // Deletion.
-    DeleteComposedCharacterForward,
-    DeleteComposedCharacterBackward,
     DeleteWordBackward,
     DeleteWordForward,
     DeleteLineBackward,
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
index e7cfb468..5031128 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -274,9 +274,7 @@
     HeapVector<Member<PointerEvent>> coalescedPointerEvents;
     for (const auto& coalescedMouseEvent : coalescedMouseEvents) {
       DCHECK_EQ(mouseEvent.id, coalescedMouseEvent.id);
-      // TODO(crbug.com/684292): We need further investigation of why the
-      // following DCHECK fails.
-      // DCHECK_EQ(mouseEvent.pointerType, coalescedMouseEvent.pointerType);
+      DCHECK_EQ(mouseEvent.pointerType, coalescedMouseEvent.pointerType);
       PointerEventInit coalescedEventInit = pointerEventInit;
       updateMousePointerEventInit(coalescedMouseEvent, view,
                                   &coalescedEventInit);
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index 7dbd450..b9d0ff3 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -382,13 +382,6 @@
     case UseCounter::VRDeprecatedGetPose:
       return replacedBy("VRDisplay.getPose()", "VRDisplay.getFrameData()");
 
-    case UseCounter::HTMLEmbedElementLegacyCall:
-      return willBeRemoved("HTMLEmbedElement legacy caller", M58,
-                           "5715026367217664");
-
-    case UseCounter::HTMLObjectElementLegacyCall:
-      return willBeRemoved("HTMLObjectElement legacy caller", M58,
-                           "5715026367217664");
     case UseCounter::
         ServiceWorkerRespondToNavigationRequestWithRedirectedResponse:
       return String::format(
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 5811c81..60ef11f 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -1954,7 +1954,7 @@
   for (const auto& viewportConstrainedObject : *m_viewportConstrainedObjects) {
     LayoutObject* layoutObject = viewportConstrainedObject;
     PaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer();
-    if (layoutObject->style()->position() == StickyPosition) {
+    if (layoutObject->style()->position() == EPosition::kSticky) {
       // TODO(skobes): Resolve circular dependency between scroll offset and
       // compositing state, and remove this disabler. https://crbug.com/420741
       DisableCompositingQueryAsserts disabler;
@@ -2799,6 +2799,12 @@
     return;
 
   // Avoid drawing two sets of scrollbars when visual viewport is enabled.
+  visualViewportScrollbarsChanged();
+}
+
+// TODO(pdr): This logic is similar to adjustScrollbarExistence and the common
+// logic should be factored into a helper.
+void FrameView::visualViewportScrollbarsChanged() {
   bool hasHorizontalScrollbar = horizontalScrollbar();
   bool hasVerticalScrollbar = verticalScrollbar();
   bool shouldHaveHorizontalScrollbar = false;
@@ -2809,8 +2815,12 @@
   m_scrollbarManager.setHasVerticalScrollbar(shouldHaveVerticalScrollbar);
 
   if (hasHorizontalScrollbar != shouldHaveHorizontalScrollbar ||
-      hasVerticalScrollbar != shouldHaveVerticalScrollbar)
+      hasVerticalScrollbar != shouldHaveVerticalScrollbar) {
     scrollbarExistenceDidChange();
+
+    if (!visualViewportSuppliesScrollbars())
+      updateScrollbarGeometry();
+  }
 }
 
 void FrameView::updateWidgetGeometriesIfNeeded() {
@@ -4910,8 +4920,8 @@
 
   for (const LayoutObject* layoutObject : *viewportConstrainedObjects()) {
     DCHECK(layoutObject->isBoxModelObject() && layoutObject->hasLayer());
-    DCHECK(layoutObject->style()->position() == FixedPosition ||
-           layoutObject->style()->position() == StickyPosition);
+    DCHECK(layoutObject->style()->position() == EPosition::kFixed ||
+           layoutObject->style()->position() == EPosition::kSticky);
     PaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer();
 
     // Whether the Layer sticks to the viewport is a tree-depenent
@@ -5164,4 +5174,8 @@
   m_animationHost = std::move(host);
 }
 
+LayoutUnit FrameView::caretWidth() const {
+  return LayoutUnit(getHostWindow()->windowToViewportScalar(1));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index f9384441..1e6ffcb3 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -831,6 +831,12 @@
   // Returns the GeometryMapper associated with the root local frame.
   GeometryMapper& geometryMapper();
 
+  // The visual viewport can supply scrollbars which affect the existence of
+  // our scrollbars (see: computeScrollbarExistence).
+  void visualViewportScrollbarsChanged();
+
+  LayoutUnit caretWidth() const;
+
  protected:
   // Scroll the content via the compositor.
   bool scrollContentsFastPath(const IntSize& scrollDelta);
@@ -1206,6 +1212,8 @@
   std::unique_ptr<GeometryMapper> m_geometryMapper;
 
   Member<PrintContext> m_printContext;
+
+  FRIEND_TEST_ALL_PREFIXES(WebViewTest, DeviceEmulationResetScrollbars);
 };
 
 inline void FrameView::incrementVisuallyNonEmptyCharacterCount(unsigned count) {
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 52e6e65..eb7c407 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -38,7 +38,6 @@
 #include "core/css/resolver/StyleResolver.h"
 #include "core/dom/DOMImplementation.h"
 #include "core/dom/DocumentUserGestureToken.h"
-#include "core/dom/ExecutionContextTask.h"
 #include "core/dom/FrameRequestCallback.h"
 #include "core/dom/SandboxFlags.h"
 #include "core/dom/TaskRunnerHelper.h"
@@ -392,9 +391,9 @@
   // workaround to avoid Editing code crashes.  We should always dispatch
   // 'load' event asynchronously.  crbug.com/569511.
   if (ScopedEventQueue::instance()->shouldQueueEvents() && m_document) {
-    m_document->postTask(
-        TaskType::Networking, BLINK_FROM_HERE,
-        createSameThreadTask(&LocalDOMWindow::dispatchLoadEvent,
+    TaskRunnerHelper::get(TaskType::Networking, m_document)
+        ->postTask(BLINK_FROM_HERE,
+                   WTF::bind(&LocalDOMWindow::dispatchLoadEvent,
                              wrapPersistent(this)));
     return;
   }
diff --git a/third_party/WebKit/Source/core/frame/Location.cpp b/third_party/WebKit/Source/core/frame/Location.cpp
index 9a1ebf4..44ee661 100644
--- a/third_party/WebKit/Source/core/frame/Location.cpp
+++ b/third_party/WebKit/Source/core/frame/Location.cpp
@@ -37,6 +37,7 @@
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
 #include "core/loader/FrameLoader.h"
+#include "platform/instrumentation/tracing/TraceEvent.h"
 #include "platform/weborigin/KURL.h"
 #include "platform/weborigin/SecurityOrigin.h"
 
@@ -209,6 +210,7 @@
                        LocalDOMWindow* enteredWindow,
                        const String& hash,
                        ExceptionState& exceptionState) {
+  TRACE_EVENT0("blink", "Location::setHash");
   if (!m_frame)
     return;
   KURL url = toLocalFrame(m_frame)->document()->url();
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.cpp b/third_party/WebKit/Source/core/frame/UseCounter.cpp
index f424c14..79272a3 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.cpp
+++ b/third_party/WebKit/Source/core/frame/UseCounter.cpp
@@ -1125,6 +1125,7 @@
       TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("blink.feature_usage"),
                    "FeatureFirstUsed", "feature", feature);
       featuresHistogram().count(feature);
+      notifyFeatureCounted(feature);
     }
     m_featuresRecorded.quickSet(feature);
   }
@@ -1143,6 +1144,10 @@
   return m_featuresRecorded.quickGet(feature);
 }
 
+DEFINE_TRACE(UseCounter) {
+  visitor->trace(m_observers);
+}
+
 void UseCounter::didCommitLoad(KURL url) {
   m_legacyCounter.updateMeasurements();
 
@@ -1193,6 +1198,11 @@
   return m_CSSRecorded.quickGet(unresolvedProperty);
 }
 
+void UseCounter::addObserver(Observer* observer) {
+  DCHECK(!m_observers.contains(observer));
+  m_observers.insert(observer);
+}
+
 bool UseCounter::isCounted(Document& document, const String& string) {
   Frame* frame = document.frame();
   if (!frame)
@@ -1249,6 +1259,17 @@
   recordMeasurement(feature);
 }
 
+void UseCounter::notifyFeatureCounted(Feature feature) {
+  DCHECK(!m_muteCount);
+  DCHECK(!m_disableReporting);
+  HeapHashSet<Member<Observer>> toBeRemoved;
+  for (auto observer : m_observers) {
+    if (observer->onCountFeature(feature))
+      toBeRemoved.insert(observer);
+  }
+  m_observers.removeAll(toBeRemoved);
+}
+
 EnumerationHistogram& UseCounter::featuresHistogram() const {
   // Every SVGImage has it's own Page instance, and multiple web pages can
   // share the usage of a single SVGImage.  Ideally perhaps we'd delegate
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index e82f4e3..aa2da26 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -26,14 +26,16 @@
 #ifndef UseCounter_h
 #define UseCounter_h
 
+#include <v8.h>
 #include "core/CSSPropertyNames.h"
 #include "core/CoreExport.h"
 #include "core/css/parser/CSSParserMode.h"
+#include "platform/heap/GarbageCollected.h"
+#include "platform/heap/HeapAllocator.h"
 #include "platform/weborigin/KURL.h"
 #include "wtf/BitVector.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/text/WTFString.h"
-#include <v8.h>
 
 namespace blink {
 
@@ -55,7 +57,8 @@
 // "Automatically send usage statistics and crash reports to Google" setting
 // enabled:
 // http://www.google.com/chrome/intl/en/privacy.html
-
+//
+// Changes on UseCounter are observable by UseCounter::Observer.
 class CORE_EXPORT UseCounter {
   DISALLOW_NEW();
   WTF_MAKE_NONCOPYABLE(UseCounter);
@@ -160,8 +163,6 @@
     DOMNodeInsertedIntoDocumentEvent = 147,
     DOMCharacterDataModifiedEvent = 148,
     DocumentAllLegacyCall = 150,
-    HTMLEmbedElementLegacyCall = 152,
-    HTMLObjectElementLegacyCall = 153,
     GetMatchedCSSRules = 155,
     PrefixedAudioDecodedByteCount = 164,
     PrefixedVideoDecodedByteCount = 165,
@@ -1469,6 +1470,19 @@
     NumberOfFeatures,  // This enum value must be last.
   };
 
+  // An interface to observe UseCounter changes. Note that this is never
+  // notified when the counter is disabled by |m_muteCount| or
+  // |m_disableReporting|.
+  class Observer : public GarbageCollected<Observer> {
+   public:
+    // Notified when a feature is counted for the first time. This should return
+    // true if it no longer needs to observe changes so that the counter can
+    // remove a reference to the observer and stop notifications.
+    virtual bool onCountFeature(Feature) = 0;
+
+    DEFINE_INLINE_VIRTUAL_TRACE() {}
+  };
+
   // "count" sets the bit for this feature to 1. Repeated calls are ignored.
   static void count(const Frame*, Feature);
   static void count(const Document&, Feature);
@@ -1489,6 +1503,9 @@
   static bool isCounted(Document&, const String&);
   bool isCounted(CSSPropertyID unresolvedProperty);
 
+  // Retains a reference to the observer to notify of UseCounter changes.
+  void addObserver(Observer*);
+
   // Invoked when a new document is loaded into the main frame of the page.
   void didCommitLoad(KURL);
 
@@ -1505,7 +1522,14 @@
   // reporting disabled.
   bool hasRecordedMeasurement(Feature) const;
 
+  DECLARE_TRACE();
+
  private:
+  // Notifies that a feature is newly counted to |m_observers|. This shouldn't
+  // be called when the counter is disabled by |m_muteCount| or
+  // |m_disableReporting|.
+  void notifyFeatureCounted(Feature);
+
   EnumerationHistogram& featuresHistogram() const;
   EnumerationHistogram& cssHistogram() const;
 
@@ -1523,6 +1547,8 @@
   BitVector m_featuresRecorded;
   BitVector m_CSSRecorded;
 
+  HeapHashSet<Member<Observer>> m_observers;
+
   // Encapsulates the work to preserve the old "FeatureObserver" histogram with
   // original semantics
   // TODO(rbyers): remove this - http://crbug.com/676837
diff --git a/third_party/WebKit/Source/core/frame/UseCounterTest.cpp b/third_party/WebKit/Source/core/frame/UseCounterTest.cpp
index 3d72ec4..6db3efa 100644
--- a/third_party/WebKit/Source/core/frame/UseCounterTest.cpp
+++ b/third_party/WebKit/Source/core/frame/UseCounterTest.cpp
@@ -26,6 +26,77 @@
 
 namespace blink {
 
+template <typename T>
+void histogramBasicTest(const std::string& histogram,
+                        const std::string& legacyHistogram,
+                        const std::vector<std::string>& unaffectedHistograms,
+                        T item,
+                        T secondItem,
+                        std::function<bool(T)> counted,
+                        std::function<void(T)> count,
+                        std::function<int(T)> histogramMap,
+                        std::function<void(KURL)> didCommitLoad,
+                        const std::string& url,
+                        int pageVisitBucket) {
+  HistogramTester histogramTester;
+
+  // Test recording a single (arbitrary) counter
+  EXPECT_FALSE(counted(item));
+  count(item);
+  EXPECT_TRUE(counted(item));
+  histogramTester.expectUniqueSample(histogram, histogramMap(item), 1);
+  histogramTester.expectTotalCount(legacyHistogram, 0);
+
+  // Test that repeated measurements have no effect
+  count(item);
+  histogramTester.expectUniqueSample(histogram, histogramMap(item), 1);
+  histogramTester.expectTotalCount(legacyHistogram, 0);
+
+  // Test recording a different sample
+  EXPECT_FALSE(counted(secondItem));
+  count(secondItem);
+  EXPECT_TRUE(counted(secondItem));
+  histogramTester.expectBucketCount(histogram, histogramMap(item), 1);
+  histogramTester.expectBucketCount(histogram, histogramMap(secondItem), 1);
+  histogramTester.expectTotalCount(histogram, 2);
+  histogramTester.expectTotalCount(legacyHistogram, 0);
+
+  // After a page load, the histograms will be updated, even when the URL
+  // scheme is internal
+  didCommitLoad(URLTestHelpers::toKURL(url));
+  histogramTester.expectBucketCount(histogram, histogramMap(item), 1);
+  histogramTester.expectBucketCount(histogram, histogramMap(secondItem), 1);
+  histogramTester.expectBucketCount(histogram, pageVisitBucket, 1);
+  histogramTester.expectTotalCount(histogram, 3);
+
+  // And verify the legacy histogram now looks the same
+  histogramTester.expectBucketCount(legacyHistogram, histogramMap(item), 1);
+  histogramTester.expectBucketCount(legacyHistogram, histogramMap(secondItem),
+                                    1);
+  histogramTester.expectBucketCount(legacyHistogram, pageVisitBucket, 1);
+  histogramTester.expectTotalCount(legacyHistogram, 3);
+
+  // Now a repeat measurement should get recorded again, exactly once
+  EXPECT_FALSE(counted(item));
+  count(item);
+  count(item);
+  EXPECT_TRUE(counted(item));
+  histogramTester.expectBucketCount(histogram, histogramMap(item), 2);
+  histogramTester.expectTotalCount(histogram, 4);
+
+  // And on the next page load, the legacy histogram will again be updated
+  didCommitLoad(URLTestHelpers::toKURL(url));
+  histogramTester.expectBucketCount(legacyHistogram, histogramMap(item), 2);
+  histogramTester.expectBucketCount(legacyHistogram, histogramMap(secondItem),
+                                    1);
+  histogramTester.expectBucketCount(legacyHistogram, pageVisitBucket, 2);
+  histogramTester.expectTotalCount(legacyHistogram, 5);
+
+  for (size_t i = 0; i < unaffectedHistograms.size(); ++i) {
+    histogramTester.expectTotalCount(unaffectedHistograms[i], 0);
+  }
+}
+
 // Failing on Android: crbug.com/667913
 #if OS(ANDROID)
 #define MAYBE_RecordingFeatures DISABLED_RecordingFeatures
@@ -34,223 +105,83 @@
 #endif
 TEST(UseCounterTest, MAYBE_RecordingFeatures) {
   UseCounter useCounter;
-  HistogramTester histogramTester;
-
-  // Test recording a single (arbitrary) counter
-  EXPECT_FALSE(useCounter.hasRecordedMeasurement(UseCounter::Fetch));
-  useCounter.recordMeasurement(UseCounter::Fetch);
-  EXPECT_TRUE(useCounter.hasRecordedMeasurement(UseCounter::Fetch));
-  histogramTester.expectUniqueSample(kFeaturesHistogramName, UseCounter::Fetch,
-                                     1);
-  histogramTester.expectTotalCount(kLegacyFeaturesHistogramName, 0);
-
-  // Test that repeated measurements have no effect
-  useCounter.recordMeasurement(UseCounter::Fetch);
-  histogramTester.expectUniqueSample(kFeaturesHistogramName, UseCounter::Fetch,
-                                     1);
-  histogramTester.expectTotalCount(kLegacyFeaturesHistogramName, 0);
-
-  // Test recording a different sample
-  EXPECT_FALSE(useCounter.hasRecordedMeasurement(UseCounter::FetchBodyStream));
-  useCounter.recordMeasurement(UseCounter::FetchBodyStream);
-  EXPECT_TRUE(useCounter.hasRecordedMeasurement(UseCounter::FetchBodyStream));
-  histogramTester.expectBucketCount(kFeaturesHistogramName, UseCounter::Fetch,
-                                    1);
-  histogramTester.expectBucketCount(kFeaturesHistogramName,
-                                    UseCounter::FetchBodyStream, 1);
-  histogramTester.expectTotalCount(kFeaturesHistogramName, 2);
-  histogramTester.expectTotalCount(kLegacyFeaturesHistogramName, 0);
-
-  // Test the impact of page load on the new histogram
-  useCounter.didCommitLoad(URLTestHelpers::toKURL("https://dummysite.com/"));
-  histogramTester.expectBucketCount(kFeaturesHistogramName, UseCounter::Fetch,
-                                    1);
-  histogramTester.expectBucketCount(kFeaturesHistogramName,
-                                    UseCounter::FetchBodyStream, 1);
-  histogramTester.expectBucketCount(kFeaturesHistogramName,
-                                    UseCounter::PageVisits, 1);
-  histogramTester.expectTotalCount(kFeaturesHistogramName, 3);
-
-  // And verify the legacy histogram now looks the same
-  histogramTester.expectBucketCount(kLegacyFeaturesHistogramName,
-                                    UseCounter::Fetch, 1);
-  histogramTester.expectBucketCount(kLegacyFeaturesHistogramName,
-                                    UseCounter::FetchBodyStream, 1);
-  histogramTester.expectBucketCount(kLegacyFeaturesHistogramName,
-                                    UseCounter::PageVisits, 1);
-  histogramTester.expectTotalCount(kLegacyFeaturesHistogramName, 3);
-
-  // Now a repeat measurement should get recorded again, exactly once
-  EXPECT_FALSE(useCounter.hasRecordedMeasurement(UseCounter::Fetch));
-  useCounter.recordMeasurement(UseCounter::Fetch);
-  useCounter.recordMeasurement(UseCounter::Fetch);
-  EXPECT_TRUE(useCounter.hasRecordedMeasurement(UseCounter::Fetch));
-  histogramTester.expectBucketCount(kFeaturesHistogramName, UseCounter::Fetch,
-                                    2);
-  histogramTester.expectTotalCount(kFeaturesHistogramName, 4);
-
-  // And on the next page load, the legacy histogram will again be updated
-  useCounter.didCommitLoad(URLTestHelpers::toKURL("https://dummysite.com/"));
-  histogramTester.expectBucketCount(kLegacyFeaturesHistogramName,
-                                    UseCounter::Fetch, 2);
-  histogramTester.expectBucketCount(kLegacyFeaturesHistogramName,
-                                    UseCounter::FetchBodyStream, 1);
-  histogramTester.expectBucketCount(kLegacyFeaturesHistogramName,
-                                    UseCounter::PageVisits, 2);
-  histogramTester.expectTotalCount(kLegacyFeaturesHistogramName, 5);
-
-  // None of this should update any of the SVG histograms
-  histogramTester.expectTotalCount(kSVGFeaturesHistogramName, 0);
-  histogramTester.expectTotalCount(kSVGCSSHistogramName, 0);
+  histogramBasicTest<UseCounter::Feature>(
+      kFeaturesHistogramName, kLegacyFeaturesHistogramName,
+      {kSVGFeaturesHistogramName, kSVGCSSHistogramName}, UseCounter::Fetch,
+      UseCounter::FetchBodyStream,
+      [&](UseCounter::Feature feature) -> bool {
+        return useCounter.hasRecordedMeasurement(feature);
+      },
+      [&](UseCounter::Feature feature) {
+        useCounter.recordMeasurement(feature);
+      },
+      [](UseCounter::Feature feature) -> int { return feature; },
+      [&](KURL kurl) { useCounter.didCommitLoad(kurl); },
+      "https://dummysite.com/", UseCounter::PageVisits);
 }
 
 TEST(UseCounterTest, RecordingCSSProperties) {
   UseCounter useCounter;
-  HistogramTester histogramTester;
-
-  // Test recording a single (arbitrary) property
-  EXPECT_FALSE(useCounter.isCounted(CSSPropertyFont));
-  useCounter.count(HTMLStandardMode, CSSPropertyFont);
-  EXPECT_TRUE(useCounter.isCounted(CSSPropertyFont));
-  histogramTester.expectUniqueSample(
-      kCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      1);
-  histogramTester.expectTotalCount(kLegacyCSSHistogramName, 0);
-
-  // Test that repeated measurements have no effect
-  useCounter.count(HTMLStandardMode, CSSPropertyFont);
-  histogramTester.expectUniqueSample(
-      kCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      1);
-  histogramTester.expectTotalCount(kLegacyCSSHistogramName, 0);
-
-  // Test recording a different sample
-  EXPECT_FALSE(useCounter.isCounted(CSSPropertyZoom));
-  useCounter.count(HTMLStandardMode, CSSPropertyZoom);
-  EXPECT_TRUE(useCounter.isCounted(CSSPropertyZoom));
-  histogramTester.expectBucketCount(
-      kCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      1);
-  histogramTester.expectBucketCount(
-      kCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyZoom),
-      1);
-  histogramTester.expectTotalCount(kCSSHistogramName, 2);
-  histogramTester.expectTotalCount(kLegacyCSSHistogramName, 0);
-
-  // Test the impact of page load on the new histogram
-  useCounter.didCommitLoad(URLTestHelpers::toKURL("https://dummysite.com/"));
-  histogramTester.expectBucketCount(
-      kCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      1);
-  histogramTester.expectBucketCount(
-      kCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyZoom),
-      1);
-  histogramTester.expectBucketCount(kCSSHistogramName, 1, 1);
-  histogramTester.expectTotalCount(kCSSHistogramName, 3);
-
-  // And verify the legacy histogram now looks the same
-  histogramTester.expectBucketCount(
-      kLegacyCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      1);
-  histogramTester.expectBucketCount(
-      kLegacyCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyZoom),
-      1);
-  histogramTester.expectBucketCount(kLegacyCSSHistogramName, 1, 1);
-  histogramTester.expectTotalCount(kLegacyCSSHistogramName, 3);
-
-  // Now a repeat measurement should get recorded again, exactly once
-  EXPECT_FALSE(useCounter.isCounted(CSSPropertyFont));
-  useCounter.count(HTMLStandardMode, CSSPropertyFont);
-  useCounter.count(HTMLStandardMode, CSSPropertyFont);
-  EXPECT_TRUE(useCounter.isCounted(CSSPropertyFont));
-  histogramTester.expectBucketCount(
-      kCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      2);
-  histogramTester.expectTotalCount(kCSSHistogramName, 4);
-
-  // And on the next page load, the legacy histogram will again be updated
-  useCounter.didCommitLoad(URLTestHelpers::toKURL("https://dummysite.com/"));
-  histogramTester.expectBucketCount(
-      kLegacyCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      2);
-  histogramTester.expectBucketCount(
-      kLegacyCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyZoom),
-      1);
-  histogramTester.expectBucketCount(kLegacyCSSHistogramName, 1, 2);
-  histogramTester.expectTotalCount(kLegacyCSSHistogramName, 5);
-
-  // None of this should update any of the SVG histograms
-  histogramTester.expectTotalCount(kSVGFeaturesHistogramName, 0);
-  histogramTester.expectTotalCount(kSVGCSSHistogramName, 0);
+  histogramBasicTest<CSSPropertyID>(
+      kCSSHistogramName, kLegacyCSSHistogramName,
+      {kSVGFeaturesHistogramName, kSVGCSSHistogramName}, CSSPropertyFont,
+      CSSPropertyZoom,
+      [&](CSSPropertyID property) -> bool {
+        return useCounter.isCounted(property);
+      },
+      [&](CSSPropertyID property) {
+        useCounter.count(HTMLStandardMode, property);
+      },
+      [](CSSPropertyID property) -> int {
+        return UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(property);
+      },
+      [&](KURL kurl) { useCounter.didCommitLoad(kurl); },
+      "https://dummysite.com/", 1 /* page visit bucket */);
 }
 
 // Failing on Android: crbug.com/667913
 #if OS(ANDROID)
-#define MAYBE_SVGImageContext DISABLED_SVGImageContext
+#define MAYBE_SVGImageContextFeatures DISABLED_SVGImageContextFeatures
 #else
-#define MAYBE_SVGImageContext SVGImageContext
+#define MAYBE_SVGImageContextFeatures SVGImageContextFeatures
 #endif
-
-TEST(UseCounterTest, MAYBE_SVGImageContext) {
+TEST(UseCounterTest, MAYBE_SVGImageContextFeatures) {
   UseCounter useCounter(UseCounter::SVGImageContext);
-  HistogramTester histogramTester;
+  histogramBasicTest<UseCounter::Feature>(
+      kSVGFeaturesHistogramName, kLegacyFeaturesHistogramName,
+      {kFeaturesHistogramName, kCSSHistogramName},
+      UseCounter::SVGSMILAdditiveAnimation,
+      UseCounter::SVGSMILAnimationElementTiming,
+      [&](UseCounter::Feature feature) -> bool {
+        return useCounter.hasRecordedMeasurement(feature);
+      },
+      [&](UseCounter::Feature feature) {
+        useCounter.recordMeasurement(feature);
+      },
+      [](UseCounter::Feature feature) -> int { return feature; },
+      [&](KURL kurl) { useCounter.didCommitLoad(kurl); }, "about:blank",
+      // In practice SVGs always appear to be loaded with an about:blank URL
+      UseCounter::PageVisits);
+}
 
-  // Verify that SVGImage related feature counters get recorded in a separate
-  // histogram.
-  EXPECT_FALSE(
-      useCounter.hasRecordedMeasurement(UseCounter::SVGSMILAdditiveAnimation));
-  useCounter.recordMeasurement(UseCounter::SVGSMILAdditiveAnimation);
-  EXPECT_TRUE(
-      useCounter.hasRecordedMeasurement(UseCounter::SVGSMILAdditiveAnimation));
-  histogramTester.expectUniqueSample(kSVGFeaturesHistogramName,
-                                     UseCounter::SVGSMILAdditiveAnimation, 1);
-
-  // And for the CSS counters
-  EXPECT_FALSE(useCounter.isCounted(CSSPropertyFont));
-  useCounter.count(HTMLStandardMode, CSSPropertyFont);
-  EXPECT_TRUE(useCounter.isCounted(CSSPropertyFont));
-  histogramTester.expectUniqueSample(
-      kSVGCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      1);
-
-  // After a page load, the histograms will be updated, even when the URL
-  // scheme is internal (in practice SVGs always appear to get loaded with
-  // an about:blank URL).
-  useCounter.didCommitLoad(URLTestHelpers::toKURL("about:blank"));
-  histogramTester.expectBucketCount(kSVGFeaturesHistogramName,
-                                    UseCounter::PageVisits, 1);
-  histogramTester.expectTotalCount(kSVGFeaturesHistogramName, 2);
-  histogramTester.expectBucketCount(kSVGCSSHistogramName, 1, 1);
-  histogramTester.expectTotalCount(kSVGCSSHistogramName, 2);
-
-  // And the legacy histogram will be updated to include these
-  histogramTester.expectBucketCount(kLegacyFeaturesHistogramName,
-                                    UseCounter::SVGSMILAdditiveAnimation, 1);
-  histogramTester.expectBucketCount(kLegacyFeaturesHistogramName,
-                                    UseCounter::PageVisits, 1);
-  histogramTester.expectTotalCount(kLegacyFeaturesHistogramName, 2);
-  histogramTester.expectBucketCount(
-      kLegacyCSSHistogramName,
-      UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(CSSPropertyFont),
-      1);
-  histogramTester.expectBucketCount(kLegacyCSSHistogramName, 1, 1);
-  histogramTester.expectTotalCount(kLegacyCSSHistogramName, 2);
-
-  // None of this should update the non-legacy non-SVG histograms
-  histogramTester.expectTotalCount(kCSSHistogramName, 0);
-  histogramTester.expectTotalCount(kFeaturesHistogramName, 0);
+TEST(UseCounterTest, SVGImageContextCSSProperties) {
+  UseCounter useCounter(UseCounter::SVGImageContext);
+  histogramBasicTest<CSSPropertyID>(
+      kSVGCSSHistogramName, kLegacyCSSHistogramName,
+      {kFeaturesHistogramName, kCSSHistogramName}, CSSPropertyFont,
+      CSSPropertyZoom,
+      [&](CSSPropertyID property) -> bool {
+        return useCounter.isCounted(property);
+      },
+      [&](CSSPropertyID property) {
+        useCounter.count(HTMLStandardMode, property);
+      },
+      [](CSSPropertyID property) -> int {
+        return UseCounter::mapCSSPropertyIdToCSSSampleIdForHistogram(property);
+      },
+      [&](KURL kurl) { useCounter.didCommitLoad(kurl); }, "about:blank",
+      // In practice SVGs always appear to be loaded with an about:blank URL
+      1 /* page visit bucket */);
 }
 
 // Failing on Android: crbug.com/667913
@@ -259,7 +190,6 @@
 #else
 #define MAYBE_InspectorDisablesMeasurement InspectorDisablesMeasurement
 #endif
-
 TEST(UseCounterTest, MAYBE_InspectorDisablesMeasurement) {
   UseCounter useCounter;
   HistogramTester histogramTester;
diff --git a/third_party/WebKit/Source/core/frame/VisualViewport.cpp b/third_party/WebKit/Source/core/frame/VisualViewport.cpp
index 5585ea1..a107295 100644
--- a/third_party/WebKit/Source/core/frame/VisualViewport.cpp
+++ b/third_party/WebKit/Source/core/frame/VisualViewport.cpp
@@ -424,6 +424,13 @@
 
   setupScrollbar(WebScrollbar::Horizontal);
   setupScrollbar(WebScrollbar::Vertical);
+
+  // Ensure existing FrameView scrollbars are removed if the visual viewport
+  // scrollbars are now supplied, or created if the visual viewport no longer
+  // supplies scrollbars.
+  LocalFrame* frame = mainFrame();
+  if (frame && frame->view())
+    frame->view()->visualViewportScrollbarsChanged();
 }
 
 void VisualViewport::setupScrollbar(WebScrollbar::Orientation orientation) {
diff --git a/third_party/WebKit/Source/core/html/HTMLEmbedElement.idl b/third_party/WebKit/Source/core/html/HTMLEmbedElement.idl
index ee74abae..91d2e6c 100644
--- a/third_party/WebKit/Source/core/html/HTMLEmbedElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLEmbedElement.idl
@@ -20,11 +20,8 @@
 
 // https://html.spec.whatwg.org/#the-embed-element
 
-// TODO(foolip): HTMLEmbedElement should not have [Custom=LegacyCallAsFunction].
-// https://crbug.com/663662
 // TODO(yukishiino): HTMLEmbedElement should not have [OverrideBuiltins].
 [
-    Custom=LegacyCallAsFunction,
     OverrideBuiltins,
 ] interface HTMLEmbedElement : HTMLElement {
     [CEReactions, Reflect, URL] attribute DOMString src;
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index 37c93ef..c6863dd 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -38,7 +38,6 @@
 #include "core/InputTypeNames.h"
 #include "core/dom/AXObjectCache.h"
 #include "core/dom/Document.h"
-#include "core/dom/ExecutionContextTask.h"
 #include "core/dom/IdTargetObserver.h"
 #include "core/dom/StyleChangeReason.h"
 #include "core/dom/TaskRunnerHelper.h"
@@ -1264,10 +1263,11 @@
 
   if (m_inputTypeView->shouldSubmitImplicitly(evt)) {
     // FIXME: Remove type check.
-    if (type() == InputTypeNames::search)
-      document().postTask(TaskType::UserInteraction, BLINK_FROM_HERE,
-                          createSameThreadTask(&HTMLInputElement::onSearch,
-                                               wrapPersistent(this)));
+    if (type() == InputTypeNames::search) {
+      TaskRunnerHelper::get(TaskType::UserInteraction, &document())
+          ->postTask(BLINK_FROM_HERE, WTF::bind(&HTMLInputElement::onSearch,
+                                                wrapPersistent(this)));
+    }
     // Form submission finishes editing, just as loss of focus does.
     // If there was a change, send the event now.
     if (wasChangedSinceLastFormControlChangeEvent())
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.idl b/third_party/WebKit/Source/core/html/HTMLObjectElement.idl
index d4b3b6ae..cb88965 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.idl
@@ -20,11 +20,8 @@
 
 // https://html.spec.whatwg.org/#the-object-element
 
-// TODO(foolip): HTMLObjectElement should not have
-// [Custom=LegacyCallAsFunction]. https://crbug.com/663662
 // TODO(yukishiino): HTMLObjectElement should not have [OverrideBuiltins].
 [
-    Custom=LegacyCallAsFunction,
     OverrideBuiltins,
 ] interface HTMLObjectElement : HTMLElement {
     [CEReactions, Reflect, URL] attribute DOMString data;
diff --git a/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp b/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
index 0110fca0..e48b704 100644
--- a/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLScriptElement.cpp
@@ -126,7 +126,7 @@
 }
 
 bool HTMLScriptElement::async() const {
-  return fastHasAttribute(asyncAttr) || (m_loader->forceAsync());
+  return fastHasAttribute(asyncAttr) || m_loader->isNonBlocking();
 }
 
 KURL HTMLScriptElement::src() const {
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index bed8a48..bf75ddf 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -37,7 +37,6 @@
 #include "core/dom/AXObjectCache.h"
 #include "core/dom/Attribute.h"
 #include "core/dom/ElementTraversal.h"
-#include "core/dom/ExecutionContextTask.h"
 #include "core/dom/MutationCallback.h"
 #include "core/dom/MutationObserver.h"
 #include "core/dom/MutationObserverInit.h"
@@ -895,9 +894,9 @@
   // inserted before executing scrollToOptionTask().
   m_optionToScrollTo = option;
   if (!hasPendingTask)
-    document().postTask(
-        TaskType::UserInteraction, BLINK_FROM_HERE,
-        createSameThreadTask(&HTMLSelectElement::scrollToOptionTask,
+    TaskRunnerHelper::get(TaskType::UserInteraction, &document())
+        ->postTask(BLINK_FROM_HERE,
+                   WTF::bind(&HTMLSelectElement::scrollToOptionTask,
                              wrapPersistent(this)));
 }
 
diff --git a/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp b/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp
index 97b1f0f7..8731c69 100644
--- a/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/SearchInputType.cpp
@@ -33,7 +33,6 @@
 #include "bindings/core/v8/ExceptionState.h"
 #include "core/HTMLNames.h"
 #include "core/InputTypeNames.h"
-#include "core/dom/ExecutionContextTask.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/dom/shadow/ShadowRoot.h"
 #include "core/events/KeyboardEvent.h"
@@ -107,10 +106,9 @@
 
   if (!length) {
     m_searchEventTimer.stop();
-    element().document().postTask(
-        TaskType::UserInteraction, BLINK_FROM_HERE,
-        createSameThreadTask(&HTMLInputElement::onSearch,
-                             wrapPersistent(&element())));
+    TaskRunnerHelper::get(TaskType::UserInteraction, &element().document())
+        ->postTask(BLINK_FROM_HERE, WTF::bind(&HTMLInputElement::onSearch,
+                                              wrapPersistent(&element())));
     return;
   }
 
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
index 3b41d8d..df5a192 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScriptRunner.cpp
@@ -438,7 +438,11 @@
   return true;
 }
 
+// 2nd Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script
 void HTMLParserScriptRunner::requestParsingBlockingScript(Element* element) {
+  // "The element is the pending parsing-blocking script of the Document of
+  //  the parser that created the element.
+  //  (There can only be one such script per Document at a time.)"
   if (!requestPendingScript(m_parserBlockingScript.get(), element))
     return;
 
@@ -462,6 +466,7 @@
   }
 }
 
+// 1st Clause, Step 23 of https://html.spec.whatwg.org/#prepare-a-script
 void HTMLParserScriptRunner::requestDeferredScript(Element* element) {
   PendingScript* pendingScript = PendingScript::create(nullptr, nullptr);
   if (!requestPendingScript(pendingScript, element))
@@ -478,6 +483,10 @@
   }
 
   DCHECK(pendingScript->resource());
+
+  // "Add the element to the end of the list of scripts that will execute
+  //  when the document has finished parsing associated with the Document
+  //  of the parser that created the element."
   m_scriptsToExecuteAfterParsing.append(pendingScript);
 }
 
@@ -525,16 +534,28 @@
 
     scriptLoader->prepareScript(scriptStartPosition);
 
+    // A part of Step 23 of https://html.spec.whatwg.org/#prepare-a-script:
     if (!scriptLoader->willBeParserExecuted())
       return;
 
     if (scriptLoader->willExecuteWhenDocumentFinishedParsing()) {
+      // 1st Clause of Step 23.
       requestDeferredScript(script);
     } else if (scriptLoader->readyToBeParserExecuted()) {
+      // 5th Clause of Step 23.
+      // "If ... it's an HTML parser
+      //  whose script nesting level is not greater than one"
       if (m_reentryPermit->scriptNestingLevel() == 1u) {
+        // "The element is the pending parsing-blocking script of the
+        //  Document of the parser that created the element.
+        //  (There can only be one such script per Document at a time.)"
         m_parserBlockingScript->setElement(script);
         m_parserBlockingScript->setStartingPosition(scriptStartPosition);
       } else {
+        // 6th Clause of Step 23.
+        // "Immediately execute the script block,
+        //  even if other scripts are already executing."
+        // TODO(hiroshige): Merge the block into ScriptLoader::prepareScript().
         DCHECK_GT(m_reentryPermit->scriptNestingLevel(), 1u);
         m_parserBlockingScript->dispose();
         ScriptSourceCode sourceCode(script->textContent(),
@@ -543,6 +564,7 @@
         doExecuteScript(script, sourceCode, scriptStartPosition);
       }
     } else {
+      // 2nd Clause of Step 23.
       requestParsingBlockingScript(script);
     }
   }
diff --git a/third_party/WebKit/Source/core/html/track/vtt/VTTCue.cpp b/third_party/WebKit/Source/core/html/track/vtt/VTTCue.cpp
index 7fc6070..38691219 100644
--- a/third_party/WebKit/Source/core/html/track/vtt/VTTCue.cpp
+++ b/third_party/WebKit/Source/core/html/track/vtt/VTTCue.cpp
@@ -223,7 +223,7 @@
   // longer necessary, since cues having the region parameter set do not have
   // any positioning parameters. Also, in this case, the regions themselves
   // have positioning information.
-  if (style.position() == RelativePosition)
+  if (style.position() == EPosition::kRelative)
     return HTMLDivElement::createLayoutObject(style);
 
   return new LayoutVTTCue(this, m_snapToLinesPosition);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
index ebe550f9..98b1a0c 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
@@ -75,108 +75,6 @@
 static const char enabled[] = "enabled";
 }
 
-static void removeEventListenerCallback(
-    const v8::FunctionCallbackInfo<v8::Value>& info) {
-  v8::Isolate* isolate = info.GetIsolate();
-  v8::Local<v8::Context> context = isolate->GetCurrentContext();
-  v8::Local<v8::Object> data = info.Data().As<v8::Object>();
-
-  v8::Local<v8::Value> v8Target;
-  if (!data->Get(context, v8String(isolate, "target")).ToLocal(&v8Target) ||
-      !v8Target->IsObject())
-    return;
-  EventTarget* target = V8EventTarget::toImplWithTypeCheck(isolate, v8Target);
-  // We need to handle LocalDOMWindow specially, because LocalDOMWindow wrapper
-  // exists on prototype chain.
-  if (!target)
-    target = toDOMWindow(isolate, v8Target);
-  if (!target || !target->getExecutionContext())
-    return;
-
-  v8::Local<v8::Value> v8Handler;
-  if (!data->Get(context, v8String(isolate, "handler")).ToLocal(&v8Handler) ||
-      !v8Handler->IsObject())
-    return;
-  v8::Local<v8::Value> v8Type;
-  if (!data->Get(context, v8String(isolate, "type")).ToLocal(&v8Type) ||
-      !v8Type->IsString())
-    return;
-  AtomicString type =
-      AtomicString(toCoreString(v8::Local<v8::String>::Cast(v8Type)));
-  v8::Local<v8::Value> v8UseCapture;
-  if (!data->Get(context, v8String(isolate, "useCapture"))
-           .ToLocal(&v8UseCapture) ||
-      !v8UseCapture->IsBoolean())
-    return;
-  bool useCapture = v8::Local<v8::Boolean>::Cast(v8UseCapture)->Value();
-
-  EventListener* eventListener = nullptr;
-  EventListenerVector* listeners = target->getEventListeners(type);
-  if (!listeners)
-    return;
-  for (size_t i = 0; i < listeners->size(); ++i) {
-    if (listeners->at(i).capture() != useCapture)
-      continue;
-    V8AbstractEventListener* v8Listener =
-        V8AbstractEventListener::cast(listeners->at(i).listener());
-    if (!v8Listener)
-      continue;
-    if (!v8Listener->hasExistingListenerObject())
-      continue;
-    if (!v8Listener->getExistingListenerObject()
-             ->Equals(context, v8Handler)
-             .FromMaybe(false))
-      continue;
-    eventListener = v8Listener;
-    break;
-  }
-  if (!eventListener)
-    return;
-  EventListenerOptions options;
-  options.setCapture(useCapture);
-  target->removeEventListener(type, eventListener, options);
-}
-
-static void returnDataCallback(
-    const v8::FunctionCallbackInfo<v8::Value>& info) {
-  info.GetReturnValue().Set(info.Data());
-}
-
-static v8::MaybeLocal<v8::Function> createRemoveFunction(
-    v8::Local<v8::Context> context,
-    v8::Local<v8::Value> object,
-    v8::Local<v8::Object> handler,
-    AtomicString type,
-    bool useCapture) {
-  v8::Isolate* isolate = context->GetIsolate();
-  v8::Local<v8::Object> data = v8::Object::New(isolate);
-  if (!data->Set(context, v8String(isolate, "target"), object).FromMaybe(false))
-    return v8::MaybeLocal<v8::Function>();
-  if (!data->Set(context, v8String(isolate, "handler"), handler)
-           .FromMaybe(false))
-    return v8::MaybeLocal<v8::Function>();
-  if (!data->Set(context, v8String(isolate, "type"), v8String(isolate, type))
-           .FromMaybe(false))
-    return v8::MaybeLocal<v8::Function>();
-  if (!data->Set(context, v8String(isolate, "useCapture"),
-                 v8Boolean(useCapture, isolate))
-           .FromMaybe(false))
-    return v8::MaybeLocal<v8::Function>();
-  v8::Local<v8::Function> removeFunction =
-      v8::Function::New(context, removeEventListenerCallback, data, 0,
-                        v8::ConstructorBehavior::kThrow)
-          .ToLocalChecked();
-  v8::Local<v8::Function> toStringFunction;
-  if (v8::Function::New(
-          context, returnDataCallback,
-          v8String(isolate, "function remove() { [Command Line API] }"), 0,
-          v8::ConstructorBehavior::kThrow)
-          .ToLocal(&toStringFunction))
-    removeFunction->Set(v8String(context->GetIsolate(), "toString"),
-                        toStringFunction);
-  return removeFunction;
-}
-
 static void collectEventListeners(v8::Isolate* isolate,
                                   EventTarget* target,
                                   v8::Local<v8::Value> targetWrapper,
@@ -222,14 +120,9 @@
             reportForAllContexts ? context : isolate->GetCurrentContext(),
             targetNode);
       }
-      v8::MaybeLocal<v8::Function> removeFunction =
-          !targetWrapper.IsEmpty()
-              ? createRemoveFunction(context, targetWrapper, handler, type,
-                                     useCapture)
-              : v8::MaybeLocal<v8::Function>();
-      eventInformation->push_back(V8EventListenerInfo(
-          type, useCapture, listeners->at(k).passive(), listeners->at(k).once(),
-          handler, removeFunction, backendNodeId));
+      eventInformation->push_back(
+          V8EventListenerInfo(type, useCapture, listeners->at(k).passive(),
+                              listeners->at(k).once(), handler, backendNodeId));
     }
   }
 }
@@ -604,10 +497,6 @@
         m_v8Session->wrapObject(context, function, objectGroupId));
     value->setOriginalHandler(
         m_v8Session->wrapObject(context, info.handler, objectGroupId));
-    v8::Local<v8::Function> removeFunction;
-    if (info.removeFunction.ToLocal(&removeFunction))
-      value->setRemoveFunction(
-          m_v8Session->wrapObject(context, removeFunction, objectGroupId));
     if (info.backendNodeId)
       value->setBackendNodeId(info.backendNodeId);
   }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp
index 0470465..192eb38 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.cpp
@@ -39,6 +39,7 @@
 #include "core/inspector/InspectorNetworkAgent.h"
 #include "core/inspector/InspectorPageAgent.h"
 #include "core/inspector/InspectorSession.h"
+#include "core/inspector/InspectorTraceEvents.h"
 #include "core/inspector/MainThreadDebugger.h"
 #include "core/inspector/ThreadDebugger.h"
 #include "core/inspector/WorkerInspectorController.h"
@@ -94,7 +95,8 @@
 
 NativeBreakpoint::NativeBreakpoint(ExecutionContext* context,
                                    const char* name,
-                                   bool sync)
+                                   bool sync,
+                                   bool trace)
     : m_instrumentingAgents(instrumentingAgentsFor(context)), m_sync(sync) {
   if (!m_instrumentingAgents ||
       !m_instrumentingAgents->hasInspectorDOMDebuggerAgents())
@@ -102,9 +104,19 @@
   for (InspectorDOMDebuggerAgent* domDebuggerAgent :
        m_instrumentingAgents->inspectorDOMDebuggerAgents())
     domDebuggerAgent->allowNativeBreakpoint(name, nullptr, m_sync);
+  if (trace) {
+    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
+                         "InstrumentedAPI", TRACE_EVENT_SCOPE_THREAD, "data",
+                         InspectorInstrumentedAPIEvent::data(name));
+  }
 }
 
 NativeBreakpoint::NativeBreakpoint(ExecutionContext* context,
+                                   const char* name,
+                                   bool sync)
+    : NativeBreakpoint(context, name, sync, false) {}
+
+NativeBreakpoint::NativeBreakpoint(ExecutionContext* context,
                                    EventTarget* eventTarget,
                                    Event* event)
     : m_instrumentingAgents(instrumentingAgentsFor(context)), m_sync(false) {
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.h b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.h
index 3ccaf34d..56be2c8 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.h
@@ -62,6 +62,7 @@
   STACK_ALLOCATED();
 
  public:
+  NativeBreakpoint(ExecutionContext*, const char* name, bool sync, bool trace);
   NativeBreakpoint(ExecutionContext*, const char* name, bool sync);
   NativeBreakpoint(ExecutionContext*, EventTarget*, Event*);
   ~NativeBreakpoint();
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
index 8280c6a3..205ae7d 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
@@ -1066,4 +1066,12 @@
   return value;
 }
 
+std::unique_ptr<TracedValue> InspectorInstrumentedAPIEvent::data(
+    const String& name) {
+  std::unique_ptr<TracedValue> value(TracedValue::create());
+  value->setString("name", name);
+  setCallStack(value.get());
+  return value;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
index b5e314c..745f786 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
@@ -381,6 +381,10 @@
                                      const HitTestResult&);
 }
 
+namespace InspectorInstrumentedAPIEvent {
+std::unique_ptr<TracedValue> data(const String&);
+}
+
 CORE_EXPORT String toHexString(const void* p);
 CORE_EXPORT void setCallStack(TracedValue*);
 
diff --git a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
index 312f70a..ca16ea3 100644
--- a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
+++ b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
@@ -422,10 +422,6 @@
                        v8::Boolean::New(isolate, info.once));
     createDataProperty(context, listenerObject, v8String(isolate, "type"),
                        v8String(isolate, currentEventType));
-    v8::Local<v8::Function> removeFunction;
-    if (info.removeFunction.ToLocal(&removeFunction))
-      createDataProperty(context, listenerObject, v8String(isolate, "remove"),
-                         removeFunction);
     createDataPropertyInArray(context, listeners, outputIndex++,
                               listenerObject);
   }
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index 224f7f28..12ad17f 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -3263,7 +3263,6 @@
                     { "name": "columnNumber", "type": "integer", "description": "Column number in the script (0-based)." },
                     { "name": "handler", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event handler function value." },
                     { "name": "originalHandler", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event original handler function value." },
-                    { "name": "removeFunction", "$ref": "Runtime.RemoteObject", "optional": true, "description": "Event listener remove function." },
                     { "name": "backendNodeId", "$ref": "DOM.BackendNodeId", "optional": true, "description": "Node the listener is added to (if any)." }
                 ],
                 "experimental": true
diff --git a/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp b/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
index d7f74d7..0dfd5d3 100644
--- a/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
+++ b/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
@@ -41,8 +41,14 @@
        line = line->nextRootBox()) {
     LayoutUnit lineTopInFlowThread =
         m_flowThreadOffset + line->lineTopWithLeading();
-    if (lineTopInFlowThread < logicalTopInFlowThread())
-      continue;
+    if (lineTopInFlowThread < logicalTopInFlowThread()) {
+      // If the line is fully about the flow thread portion range we're working
+      // with, we can skip it. If its logical top is outside the range, but its
+      // logical bottom protrudes into the range, we need to examine it.
+      LayoutUnit lineBottom = line->lineBottomWithLeading();
+      if (m_flowThreadOffset + lineBottom <= logicalTopInFlowThread())
+        continue;
+    }
     if (lineTopInFlowThread >= logicalBottomInFlowThread())
       break;
     examineLine(*line);
@@ -233,6 +239,8 @@
   LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop;
   LayoutUnit minimumLogialHeight =
       columnLogicalHeightRequirementForLine(line.block().styleRef(), line);
+  if (lineTopInFlowThread < LayoutUnit())
+    minimumLogialHeight += lineTopInFlowThread;
   m_tallestUnbreakableLogicalHeight =
       std::max(m_tallestUnbreakableLogicalHeight, minimumLogialHeight);
   ASSERT(
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index b653ab5..f5f4e687 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -216,7 +216,7 @@
 
   if (oldStyle && parent()) {
     if (oldStyle->position() != newStyle.position() &&
-        newStyle.position() != StaticPosition) {
+        newStyle.position() != EPosition::kStatic) {
       // In LayoutObject::styleWillChange() we already removed ourself from our
       // old containing block's positioned descendant list, and we will be
       // inserted to the new containing block's list during layout. However the
@@ -518,7 +518,7 @@
   for (auto* positionedObject : *positionedDescendants) {
     // Fixed positioned elements don't contribute to layout overflow, since they
     // don't scroll with the content.
-    if (positionedObject->style()->position() != FixedPosition)
+    if (positionedObject->style()->position() != EPosition::kFixed)
       addOverflowFromChild(positionedObject,
                            toLayoutSize(positionedObject->location()));
   }
@@ -677,7 +677,7 @@
 void LayoutBlock::markFixedPositionObjectForLayoutIfNeeded(
     LayoutObject* child,
     SubtreeLayoutScope& layoutScope) {
-  if (child->style()->position() != FixedPosition)
+  if (child->style()->position() != EPosition::kFixed)
     return;
 
   bool hasStaticBlockPosition =
@@ -688,7 +688,8 @@
     return;
 
   LayoutObject* o = child->parent();
-  while (o && !o->isLayoutView() && o->style()->position() != AbsolutePosition)
+  while (o && !o->isLayoutView() &&
+         o->style()->position() != EPosition::kAbsolute)
     o = o->parent();
   // The LayoutView is absolute-positioned, but does not move.
   if (o->isLayoutView())
@@ -2059,7 +2060,7 @@
       continue;
     LayoutBlock* block = toLayoutBlock(box);
     if (!block->recalcOverflowAfterStyleChange() ||
-        box->style()->position() == FixedPosition)
+        box->style()->position() == EPosition::kFixed)
       continue;
 
     childrenOverflowChanged = true;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 9e2f3a0..98e2213 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -4317,8 +4317,8 @@
   if (dialog->getCenteringMode() == HTMLDialogElement::NotCentered)
     return;
 
-  bool canCenterDialog = (style()->position() == AbsolutePosition ||
-                          style()->position() == FixedPosition) &&
+  bool canCenterDialog = (style()->position() == EPosition::kAbsolute ||
+                          style()->position() == EPosition::kFixed) &&
                          style()->hasAutoTopAndBottom();
 
   if (dialog->getCenteringMode() == HTMLDialogElement::Centered) {
@@ -4334,7 +4334,7 @@
   }
 
   FrameView* frameView = document().view();
-  LayoutUnit top = LayoutUnit((style()->position() == FixedPosition)
+  LayoutUnit top = LayoutUnit((style()->position() == EPosition::kFixed)
                                   ? 0
                                   : frameView->scrollOffsetInt().height());
   int visibleHeight = frameView->visibleContentRect(IncludeScrollbars).height();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index e012639..7bfe241 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -215,7 +215,7 @@
       } else {
         markContainerChainForLayout();
       }
-      if (oldStyle->position() == StaticPosition)
+      if (oldStyle->position() == EPosition::kStatic)
         setShouldDoFullPaintInvalidation();
       else if (newStyle.hasOutOfFlowPosition())
         parent()->setChildNeedsLayout();
@@ -699,7 +699,7 @@
 
   // If we are fixed-position and stick to the viewport, it is useless to
   // scroll the parent.
-  if (style()->position() == FixedPosition &&
+  if (style()->position() == EPosition::kFixed &&
       containerForFixedPosition() == view()) {
     return;
   }
@@ -1540,7 +1540,7 @@
 
 static bool isCandidateForOpaquenessTest(const LayoutBox& childBox) {
   const ComputedStyle& childStyle = childBox.styleRef();
-  if (childStyle.position() != StaticPosition &&
+  if (childStyle.position() != EPosition::kStatic &&
       childBox.containingBlock() != childBox.parent())
     return false;
   if (childStyle.visibility() != EVisibility::kVisible ||
@@ -1915,7 +1915,7 @@
 
   LayoutBoxModelObject* cb = toLayoutBoxModelObject(container());
   LayoutUnit height = containingBlockLogicalHeightForPositioned(cb);
-  if (styleRef().position() != AbsolutePosition)
+  if (styleRef().position() != EPosition::kAbsolute)
     height -= cb->paddingLogicalHeight();
   return height;
 }
@@ -1981,7 +1981,7 @@
 void LayoutBox::mapLocalToAncestor(const LayoutBoxModelObject* ancestor,
                                    TransformState& transformState,
                                    MapCoordinatesFlags mode) const {
-  bool isFixedPos = style()->position() == FixedPosition;
+  bool isFixedPos = style()->position() == EPosition::kFixed;
 
   // If this box has a transform or contains paint, it acts as a fixed position
   // container for fixed descendants, and may itself also be fixed position. So
@@ -2000,7 +2000,7 @@
   if (this == ancestor)
     return;
 
-  bool isFixedPos = style()->position() == FixedPosition;
+  bool isFixedPos = style()->position() == EPosition::kFixed;
 
   // If this box has a transform or contains paint, it acts as a fixed position
   // container for fixed descendants, and may itself also be fixed position. So
@@ -2025,7 +2025,7 @@
   if (o->hasOverflowClip())
     offset -= toLayoutBox(o)->scrolledContentOffset();
 
-  if (style()->position() == AbsolutePosition && o->isInFlowPositioned() &&
+  if (style()->position() == EPosition::kAbsolute && o->isInFlowPositioned() &&
       o->isLayoutInline())
     offset += toLayoutInline(o)->offsetForInFlowPositionedInline(*this);
 
@@ -2397,7 +2397,7 @@
 
   const ComputedStyle& styleToUse = styleRef();
   EPosition position = styleToUse.position();
-  if (position == AbsolutePosition && container->isInFlowPositioned() &&
+  if (position == EPosition::kAbsolute && container->isInFlowPositioned() &&
       container->isLayoutInline()) {
     topLeft +=
         toLayoutInline(container)->offsetForInFlowPositionedInline(*this);
@@ -2428,15 +2428,15 @@
     rect.move(-containerOffset);
     // If the ancestor is fixed, then the rect is already in its coordinates so
     // doesn't need viewport-adjusting.
-    if (ancestor->style()->position() != FixedPosition &&
-        container->isLayoutView() && position == FixedPosition)
+    if (ancestor->style()->position() != EPosition::kFixed &&
+        container->isLayoutView() && position == EPosition::kFixed)
       rect.move(toLayoutView(container)->offsetForFixedPosition(true));
     return true;
   }
 
   if (container->isLayoutView())
     return toLayoutView(container)->mapToVisualRectInAncestorSpace(
-        ancestor, rect, position == FixedPosition ? IsFixed : 0,
+        ancestor, rect, position == EPosition::kFixed ? IsFixed : 0,
         visualRectFlags);
   else
     return container->mapToVisualRectInAncestorSpace(ancestor, rect,
@@ -3607,8 +3607,8 @@
     return containingBlockLogicalHeightForPositioned(containingBlock, false);
 
   // Use viewport as container for top-level fixed-position elements.
-  if (style()->position() == FixedPosition && containingBlock->isLayoutView() &&
-      !document().printing()) {
+  if (style()->position() == EPosition::kFixed &&
+      containingBlock->isLayoutView() && !document().printing()) {
     const LayoutView* view = toLayoutView(containingBlock);
     if (FrameView* frameView = view->frameView()) {
       // Don't use visibleContentRect since the PaintLayer's size has not been
@@ -3668,8 +3668,8 @@
     return containingBlockLogicalWidthForPositioned(containingBlock, false);
 
   // Use viewport as container for top-level fixed-position elements.
-  if (style()->position() == FixedPosition && containingBlock->isLayoutView() &&
-      !document().printing()) {
+  if (style()->position() == EPosition::kFixed &&
+      containingBlock->isLayoutView() && !document().printing()) {
     const LayoutView* view = toLayoutView(containingBlock);
     if (FrameView* frameView = view->frameView()) {
       // Don't use visibleContentRect since the PaintLayer's size has not been
@@ -4550,13 +4550,13 @@
   // They never refer to children.
   // FIXME: Paint the carets inside empty blocks differently than the carets
   // before/after elements.
-
-  LayoutRect rect(location(), LayoutSize(caretWidth(), size().height()));
+  LayoutUnit caretWidth = frameView()->caretWidth();
+  LayoutRect rect(location(), LayoutSize(caretWidth, size().height()));
   bool ltr =
       box ? box->isLeftToRightDirection() : style()->isLeftToRightDirection();
 
   if ((!caretOffset) ^ ltr)
-    rect.move(LayoutSize(size().width() - caretWidth(), LayoutUnit()));
+    rect.move(LayoutSize(size().width() - caretWidth, LayoutUnit()));
 
   if (box) {
     RootInlineBox& rootBox = box->root();
@@ -5049,7 +5049,7 @@
   // actually look for replaced elements.
   if (isAtomicInlineLevel() || hasUnsplittableScrollingOverflow() ||
       (parent() && isWritingModeRoot()) ||
-      (isOutOfFlowPositioned() && style()->position() == FixedPosition))
+      (isOutOfFlowPositioned() && style()->position() == EPosition::kFixed))
     return ForbidBreaks;
 
   EBreakInside breakValue = breakInside();
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
index 09baabe..fca4c5fd 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -348,8 +348,8 @@
   // re-raster (rect-based invalidation) is needed, display items should
   // still update their paint offset.
   if (oldStyle) {
-    bool newStyleIsFixedPosition = style()->position() == FixedPosition;
-    bool oldStyleIsFixedPosition = oldStyle->position() == FixedPosition;
+    bool newStyleIsFixedPosition = style()->position() == EPosition::kFixed;
+    bool oldStyleIsFixedPosition = oldStyle->position() == EPosition::kFixed;
     if (newStyleIsFixedPosition != oldStyleIsFixedPosition)
       ObjectPaintInvalidator(*this)
           .invalidateDisplayItemClientsIncludingNonCompositingDescendants(
@@ -378,11 +378,13 @@
   }
 
   if (FrameView* frameView = view()->frameView()) {
-    bool newStyleIsViewportConstained = style()->position() == FixedPosition;
+    bool newStyleIsViewportConstained =
+        style()->position() == EPosition::kFixed;
     bool oldStyleIsViewportConstrained =
-        oldStyle && oldStyle->position() == FixedPosition;
-    bool newStyleIsSticky = style()->position() == StickyPosition;
-    bool oldStyleIsSticky = oldStyle && oldStyle->position() == StickyPosition;
+        oldStyle && oldStyle->position() == EPosition::kFixed;
+    bool newStyleIsSticky = style()->position() == EPosition::kSticky;
+    bool oldStyleIsSticky =
+        oldStyle && oldStyle->position() == EPosition::kSticky;
 
     if (newStyleIsSticky != oldStyleIsSticky) {
       if (newStyleIsSticky) {
@@ -1045,7 +1047,7 @@
     if (offsetParentObject->isLayoutInline()) {
       const LayoutInline* inlineParent = toLayoutInline(offsetParentObject);
 
-      if (isBox() && style()->position() == AbsolutePosition &&
+      if (isBox() && style()->position() == EPosition::kAbsolute &&
           inlineParent->isInFlowPositioned()) {
         // Offset for absolute elements with inline parent is a special
         // case in the CSS spec
@@ -1176,6 +1178,7 @@
 
   LayoutUnit x = borderLeft() + paddingLeft();
   LayoutUnit maxX = width - borderRight() - paddingRight();
+  LayoutUnit caretWidth = frameView()->caretWidth();
 
   switch (alignment) {
     case AlignLeft:
@@ -1190,12 +1193,12 @@
         x -= textIndentOffset / 2;
       break;
     case AlignRight:
-      x = maxX - caretWidth();
+      x = maxX - caretWidth;
       if (!currentStyle.isLeftToRightDirection())
         x -= textIndentOffset;
       break;
   }
-  x = std::min(x, (maxX - caretWidth()).clampNegativeToZero());
+  x = std::min(x, (maxX - caretWidth).clampNegativeToZero());
 
   const Font& font = style()->font();
   const SimpleFontData* fontData = font.primaryFont();
@@ -1211,8 +1214,8 @@
       height;
   LayoutUnit y = paddingTop() + borderTop() + (verticalSpace / 2);
   return currentStyle.isHorizontalWritingMode()
-             ? LayoutRect(x, y, caretWidth(), height)
-             : LayoutRect(y, x, height, caretWidth());
+             ? LayoutRect(x, y, caretWidth, height)
+             : LayoutRect(y, x, height, caretWidth);
 }
 
 const LayoutObject* LayoutBoxModelObject::pushMappingToContainer(
@@ -1226,7 +1229,7 @@
     return nullptr;
 
   bool isInline = isLayoutInline();
-  bool isFixedPos = !isInline && style()->position() == FixedPosition;
+  bool isFixedPos = !isInline && style()->position() == EPosition::kFixed;
   bool containsFixedPosition = canContainFixedPositionObjects();
 
   LayoutSize adjustmentForSkippedAncestor;
diff --git a/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp b/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp
index 69567cf..db84d64 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutFullScreen.cpp
@@ -111,7 +111,7 @@
   fullscreenStyle->setAlignItemsPosition(ItemPositionCenter);
   fullscreenStyle->setFlexDirection(FlowColumn);
 
-  fullscreenStyle->setPosition(FixedPosition);
+  fullscreenStyle->setPosition(EPosition::kFixed);
   fullscreenStyle->setLeft(Length(0, blink::Fixed));
   fullscreenStyle->setTop(Length(0, blink::Fixed));
   IntSize viewportSize = document().page()->frameHost().visualViewport().size();
diff --git a/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp b/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp
index ffcc1e67..989d93a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGeometryMap.cpp
@@ -195,7 +195,8 @@
   for (const LayoutObject* current = layoutObject;;
        current = current->parent()) {
     const ComputedStyle& style = current->styleRef();
-    if (style.position() == FixedPosition || style.isFlippedBlocksWritingMode())
+    if (style.position() == EPosition::kFixed ||
+        style.isFlippedBlocksWritingMode())
       return false;
 
     if (current->style()->canContainFixedPositionObjects() ||
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
index f7087839..5b3254c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -204,10 +204,10 @@
   // If we are changing to/from static, we need to reposition
   // out-of-flow positioned descendants.
   if (oldStyle && oldStyle->position() != newStyle.position() &&
-      (newStyle.position() == StaticPosition ||
-       oldStyle->position() == StaticPosition)) {
+      (newStyle.position() == EPosition::kStatic ||
+       oldStyle->position() == EPosition::kStatic)) {
     LayoutBlock* absContainingBlock = nullptr;
-    if (oldStyle->position() == StaticPosition) {
+    if (oldStyle->position() == EPosition::kStatic) {
       absContainingBlock = containingBlockForAbsolutePosition();
     } else {
       // When position was not static, containingBlockForAbsolutePosition
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
index 434e957..21083bc7 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
@@ -1113,9 +1113,9 @@
       newStyle.hasTransformRelatedProperty())
     return true;
   return (oldStyle.hasInFlowPosition() &&
-          newStyle.position() == StaticPosition) ||
+          newStyle.position() == EPosition::kStatic) ||
          (newStyle.hasInFlowPosition() &&
-          oldStyle.position() == StaticPosition);
+          oldStyle.position() == EPosition::kStatic);
 }
 
 static inline bool needsToRemoveFromFlowThread(const ComputedStyle& oldStyle,
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index e913d31e1..35313327dd 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -28,6 +28,9 @@
 
 #include "core/layout/LayoutObject.h"
 
+#include <algorithm>
+#include <memory>
+
 #include "core/animation/ElementAnimations.h"
 #include "core/css/resolver/StyleResolver.h"
 #include "core/dom/AXObjectCache.h"
@@ -85,8 +88,6 @@
 #include "wtf/allocator/Partitions.h"
 #include "wtf/text/StringBuilder.h"
 #include "wtf/text/WTFString.h"
-#include <algorithm>
-#include <memory>
 #ifndef NDEBUG
 #include <stdio.h>
 #endif
@@ -99,11 +100,6 @@
 
 }  // namespace
 
-const LayoutUnit& caretWidth() {
-  static LayoutUnit gCaretWidth(1);
-  return gCaretWidth;
-}
-
 #if DCHECK_IS_ON()
 
 LayoutObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(
@@ -922,9 +918,9 @@
   if (!object && isLayoutScrollbarPart())
     object = toLayoutScrollbarPart(this)->scrollbarStyleSource();
   if (!isTextOrSVGChild()) {
-    if (m_style->position() == FixedPosition)
+    if (m_style->position() == EPosition::kFixed)
       return containerForFixedPosition(skipInfo);
-    if (m_style->position() == AbsolutePosition)
+    if (m_style->position() == EPosition::kAbsolute)
       return containingBlockForAbsolutePosition(skipInfo);
   }
   if (isColumnSpanAll()) {
@@ -2115,8 +2111,9 @@
                                    : TransformState::FlattenTransform);
     // If the ancestor is fixed, then the rect is already in its coordinates so
     // doesn't need viewport-adjusting.
-    if (ancestor->style()->position() != FixedPosition &&
-        container->isLayoutView() && styleRef().position() == FixedPosition) {
+    if (ancestor->style()->position() != EPosition::kFixed &&
+        container->isLayoutView() &&
+        styleRef().position() == EPosition::kFixed) {
       LayoutSize adjustment = toLayoutView(container)->offsetForFixedPosition();
       transformState.move(adjustment.width(), adjustment.height());
     }
@@ -2194,8 +2191,9 @@
     transformState.move(-containerOffset.width(), -containerOffset.height());
     // If the ancestor is fixed, then the rect is already in its coordinates so
     // doesn't need viewport-adjusting.
-    if (ancestor->style()->position() != FixedPosition &&
-        container->isLayoutView() && styleRef().position() == FixedPosition) {
+    if (ancestor->style()->position() != EPosition::kFixed &&
+        container->isLayoutView() &&
+        styleRef().position() == EPosition::kFixed) {
       LayoutSize adjustment = toLayoutView(container)->offsetForFixedPosition();
       transformState.move(adjustment.width(), adjustment.height());
     }
@@ -2485,10 +2483,10 @@
     return parent();
 
   EPosition pos = m_style->position();
-  if (pos == FixedPosition)
+  if (pos == EPosition::kFixed)
     return containerForFixedPosition(skipInfo);
 
-  if (pos == AbsolutePosition) {
+  if (pos == EPosition::kAbsolute) {
     return containerForAbsolutePosition(skipInfo);
   }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 67d3cac..5ec3340c 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -84,8 +84,6 @@
 
 enum ScheduleRelayoutBehavior { ScheduleRelayout, DontScheduleRelayout };
 
-const LayoutUnit& caretWidth();
-
 struct AnnotatedRegionValue {
   DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
   bool operator==(const AnnotatedRegionValue& o) const {
@@ -577,11 +575,11 @@
   void setChildrenInline(bool b) { m_bitfields.setChildrenInline(b); }
 
   bool alwaysCreateLineBoxesForLayoutInline() const {
-    ASSERT(isLayoutInline());
+    DCHECK(isLayoutInline());
     return m_bitfields.alwaysCreateLineBoxesForLayoutInline();
   }
   void setAlwaysCreateLineBoxesForLayoutInline(bool alwaysCreateLineBoxes) {
-    ASSERT(isLayoutInline());
+    DCHECK(isLayoutInline());
     m_bitfields.setAlwaysCreateLineBoxesForLayoutInline(alwaysCreateLineBoxes);
   }
 
@@ -750,10 +748,11 @@
     return m_bitfields.isStickyPositioned();
   }
   bool isFixedPositioned() const {
-    return isOutOfFlowPositioned() && style()->position() == FixedPosition;
+    return isOutOfFlowPositioned() && style()->position() == EPosition::kFixed;
   }
   bool isAbsolutePositioned() const {
-    return isOutOfFlowPositioned() && style()->position() == AbsolutePosition;
+    return isOutOfFlowPositioned() &&
+           style()->position() == EPosition::kAbsolute;
   }
   bool isPositioned() const { return m_bitfields.isPositioned(); }
 
@@ -881,7 +880,7 @@
   }
 
   Document& document() const {
-    ASSERT(m_node || parent());  // crbug.com/402056
+    DCHECK(m_node || parent());  // crbug.com/402056
     return m_node ? m_node->document() : parent()->document();
   }
   LocalFrame* frame() const { return document().frame(); }
@@ -1011,8 +1010,9 @@
   }
 
   void setPositionState(EPosition position) {
-    ASSERT((position != AbsolutePosition && position != FixedPosition) ||
-           isBox());
+    DCHECK(
+        (position != EPosition::kAbsolute && position != EPosition::kFixed) ||
+        isBox());
     m_bitfields.setPositionedState(position);
   }
   void clearPositionedState() { m_bitfields.clearPositionedState(); }
@@ -1319,7 +1319,7 @@
   // FIXME: It would be better if style() returned a const reference.
   const ComputedStyle& styleRef() const { return mutableStyleRef(); }
   ComputedStyle& mutableStyleRef() const {
-    ASSERT(m_style);
+    DCHECK(m_style);
     return *m_style;
   }
 
@@ -1988,7 +1988,7 @@
   virtual void willBeRemovedFromTree();
 
   void setDocumentForAnonymous(Document* document) {
-    ASSERT(isAnonymous());
+    DCHECK(isAnonymous());
     m_node = document;
   }
 
@@ -2459,21 +2459,21 @@
       return m_positionedState != IsStaticallyPositioned;
     }
 
-    void setPositionedState(int positionState) {
+    void setPositionedState(EPosition positionState) {
       // This maps FixedPosition and AbsolutePosition to
       // IsOutOfFlowPositioned, saving one bit.
       switch (positionState) {
-        case StaticPosition:
+        case EPosition::kStatic:
           m_positionedState = IsStaticallyPositioned;
           break;
-        case RelativePosition:
+        case EPosition::kRelative:
           m_positionedState = IsRelativelyPositioned;
           break;
-        case AbsolutePosition:
-        case FixedPosition:
+        case EPosition::kAbsolute:
+        case EPosition::kFixed:
           m_positionedState = IsOutOfFlowPositioned;
           break;
-        case StickyPosition:
+        case EPosition::kSticky:
           m_positionedState = IsStickyPositioned;
           break;
         default:
@@ -2481,7 +2481,9 @@
           break;
       }
     }
-    void clearPositionedState() { m_positionedState = StaticPosition; }
+    void clearPositionedState() {
+      m_positionedState = static_cast<unsigned>(EPosition::kStatic);
+    }
 
     ALWAYS_INLINE SelectionState getSelectionState() const {
       return static_cast<SelectionState>(m_selectionState);
@@ -2734,7 +2736,7 @@
 
 inline LayoutUnit adjustLayoutUnitForAbsoluteZoom(LayoutUnit value,
                                                   LayoutObject& layoutObject) {
-  ASSERT(layoutObject.style());
+  DCHECK(layoutObject.style());
   return adjustLayoutUnitForAbsoluteZoom(value, *layoutObject.style());
 }
 
@@ -2754,7 +2756,7 @@
 
 inline double adjustScrollForAbsoluteZoom(double value,
                                           LayoutObject& layoutObject) {
-  ASSERT(layoutObject.style());
+  DCHECK(layoutObject.style());
   return adjustScrollForAbsoluteZoom(value, *layoutObject.style());
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
index f550155..a07ad8e 100644
--- a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
@@ -132,8 +132,7 @@
   // If the height is a percentage and the width is auto, then the
   // containingBlocks's height changing can cause this node to change it's
   // preferred width because it maintains aspect ratio.
-  return hasRelativeLogicalHeight() && style()->logicalWidth().isAuto() &&
-         !hasAutoHeightOrContainingBlockWithAutoHeight();
+  return hasRelativeLogicalHeight() && style()->logicalWidth().isAuto();
 }
 
 static inline bool layoutObjectHasAspectRatio(
diff --git a/third_party/WebKit/Source/core/layout/LayoutState.cpp b/third_party/WebKit/Source/core/layout/LayoutState.cpp
index a3f4bf14..ab542023 100644
--- a/third_party/WebKit/Source/core/layout/LayoutState.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutState.cpp
@@ -79,7 +79,7 @@
   // away we are from the start of the pagination context.
   m_paginationOffset = m_next->m_paginationOffset;
   bool fixed = layoutObject.isOutOfFlowPositioned() &&
-               layoutObject.style()->position() == FixedPosition;
+               layoutObject.style()->position() == EPosition::kFixed;
   if (fixed)
     return;
   m_paginationOffset =
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp
index 3f4d6a8..194611d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -763,11 +763,12 @@
 
   // Go ahead and round left to snap it to the nearest pixel.
   LayoutUnit left = box->positionForOffset(caretOffset);
+  LayoutUnit caretWidth = frameView()->caretWidth();
 
   // Distribute the caret's width to either side of the offset.
-  LayoutUnit caretWidthLeftOfOffset = caretWidth() / 2;
+  LayoutUnit caretWidthLeftOfOffset = caretWidth / 2;
   left -= caretWidthLeftOfOffset;
-  LayoutUnit caretWidthRightOfOffset = caretWidth() - caretWidthLeftOfOffset;
+  LayoutUnit caretWidthRightOfOffset = caretWidth - caretWidthLeftOfOffset;
 
   left = LayoutUnit(left.round());
 
@@ -817,7 +818,7 @@
 
   if (rightAligned) {
     left = std::max(left, leftEdge);
-    left = std::min(left, rootRight - caretWidth());
+    left = std::min(left, rootRight - caretWidth);
   } else {
     left = std::min(left, rightEdge - caretWidthRightOfOffset);
     left = std::max(left, rootLeft);
@@ -825,8 +826,8 @@
 
   return LayoutRect(
       style()->isHorizontalWritingMode()
-          ? IntRect(left.toInt(), top, caretWidth().toInt(), height)
-          : IntRect(top, left.toInt(), height, caretWidth().toInt()));
+          ? IntRect(left.toInt(), top, caretWidth.toInt(), height)
+          : IntRect(top, left.toInt(), height, caretWidth.toInt()));
 }
 
 ALWAYS_INLINE float LayoutText::widthFromFont(
diff --git a/third_party/WebKit/Source/core/layout/LayoutView.cpp b/third_party/WebKit/Source/core/layout/LayoutView.cpp
index 97b8fa5..0d20215 100644
--- a/third_party/WebKit/Source/core/layout/LayoutView.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutView.cpp
@@ -103,7 +103,7 @@
 
   setPreferredLogicalWidthsDirty(MarkOnlyThis);
 
-  setPositionState(AbsolutePosition);  // to 0,0 :)
+  setPositionState(EPosition::kAbsolute);  // to 0,0 :)
 }
 
 LayoutView::~LayoutView() {}
diff --git a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp
index 6ba4b70b..a1a3952 100644
--- a/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp
+++ b/third_party/WebKit/Source/core/layout/PaintInvalidationState.cpp
@@ -251,7 +251,7 @@
 
   EPosition position = m_currentObject.styleRef().position();
 
-  if (position == FixedPosition) {
+  if (position == EPosition::kFixed) {
     // Use slow path to get the offset of the fixed-position, and enable fast
     // path for descendants.
     FloatPoint fixedOffset = m_currentObject.localToAncestorPoint(
@@ -275,7 +275,7 @@
     return;
   }
 
-  if (position == AbsolutePosition) {
+  if (position == EPosition::kAbsolute) {
     m_cachedOffsetsEnabled = m_cachedOffsetsForAbsolutePositionEnabled;
     if (!m_cachedOffsetsEnabled)
       return;
diff --git a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
index af61f4e..85000041 100644
--- a/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
+++ b/third_party/WebKit/Source/core/layout/TextAutosizer.cpp
@@ -821,7 +821,8 @@
 
   if (const ComputedStyle* style = layoutObject->style()) {
     data.m_packedStyleProperties = static_cast<unsigned>(style->direction());
-    data.m_packedStyleProperties |= (style->position() << 1);
+    data.m_packedStyleProperties |=
+        (static_cast<unsigned>(style->position()) << 1);
     data.m_packedStyleProperties |=
         (static_cast<unsigned>(style->floating()) << 4);
     data.m_packedStyleProperties |=
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
index bbb796b..cb2b7ed 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -289,7 +289,7 @@
 
 void CompositedLayerMapping::updateStickyConstraints(
     const ComputedStyle& style) {
-  bool sticky = style.position() == EPosition::StickyPosition;
+  bool sticky = style.position() == EPosition::kSticky;
   const PaintLayer* ancestorOverflowLayer =
       m_owningLayer.ancestorOverflowLayer();
   // TODO(flackr): Do we still need this?
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
index 9ed2189..92b93ede 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
@@ -30,7 +30,7 @@
     const PaintLayer* layer) {
   LayoutObject* current = layer->layoutObject();
   while (current) {
-    if (current->style()->position() == FixedPosition) {
+    if (current->style()->position() == EPosition::kFixed) {
       for (current = current->parent();
            current && !current->canContainFixedPositionObjects();
            current = current->parent()) {
@@ -101,7 +101,7 @@
   const PaintLayer* previousOverflowLayer = layer->ancestorOverflowLayer();
   layer->updateAncestorOverflowLayer(info.lastOverflowClipLayer);
   if (info.lastOverflowClipLayer && layer->needsCompositingInputsUpdate() &&
-      layer->layoutObject()->style()->position() == StickyPosition) {
+      layer->layoutObject()->style()->position() == EPosition::kSticky) {
     if (info.lastOverflowClipLayer != previousOverflowLayer &&
         !RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
       // Old ancestor scroller should no longer have these constraints.
@@ -176,7 +176,7 @@
                                       ? parent
                                       : parent->filterAncestor();
       bool layerIsFixedPosition =
-          layer->layoutObject()->style()->position() == FixedPosition;
+          layer->layoutObject()->style()->position() == EPosition::kFixed;
       properties.nearestFixedPositionLayer =
           layerIsFixedPosition ? layer : parent->nearestFixedPositionLayer();
 
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp
index 87354d5..e735a2c 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingLayerAssigner.cpp
@@ -125,7 +125,7 @@
   if (!squashingState.haveAssignedBackingsToEntireSquashingLayerSubtree)
     return SquashingDisallowedReasonWouldBreakPaintOrder;
 
-  ASSERT(squashingState.hasMostRecentMapping);
+  DCHECK(squashingState.hasMostRecentMapping);
   const PaintLayer& squashingLayer =
       squashingState.mostRecentMapping->owningLayer();
 
@@ -192,7 +192,7 @@
   if (layer->nearestFixedPositionLayer() !=
       squashingLayer.nearestFixedPositionLayer())
     return SquashingDisallowedReasonNearestFixedPositionMismatch;
-  ASSERT(layer->layoutObject()->style()->position() != FixedPosition);
+  DCHECK(layer->layoutObject()->style()->position() != EPosition::kFixed);
 
   if ((squashingLayer.layoutObject()->style()->subtreeWillChangeContents() &&
        squashingLayer.layoutObject()
@@ -224,8 +224,8 @@
   if (compositedLayerUpdate == PutInSquashingLayer) {
     // A layer that is squashed with other layers cannot have its own
     // CompositedLayerMapping.
-    ASSERT(!layer->hasCompositedLayerMapping());
-    ASSERT(squashingState.hasMostRecentMapping);
+    DCHECK(!layer->hasCompositedLayerMapping());
+    DCHECK(squashingState.hasMostRecentMapping);
 
     bool changedSquashingLayer =
         squashingState.mostRecentMapping->updateSquashingLayerAssignment(
@@ -332,7 +332,7 @@
   // At this point, if the layer is to be separately composited, then its
   // backing becomes the most recent in paint-order.
   if (layer->compositingState() == PaintsIntoOwnBacking) {
-    ASSERT(!requiresSquashing(layer->getCompositingReasons()));
+    DCHECK(!requiresSquashing(layer->getCompositingReasons()));
     squashingState.updateSquashingStateForNewMapping(
         layer->compositedLayerMapping(), layer->hasCompositedLayerMapping(),
         layersNeedingPaintInvalidation);
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp
index 51f4310b..e6b4a2d2 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingReasonFinder.cpp
@@ -200,8 +200,8 @@
 
 bool CompositingReasonFinder::requiresCompositingForScrollDependentPosition(
     const PaintLayer* layer) const {
-  if (layer->layoutObject()->style()->position() != FixedPosition &&
-      layer->layoutObject()->style()->position() != StickyPosition)
+  if (layer->layoutObject()->style()->position() != EPosition::kFixed &&
+      layer->layoutObject()->style()->position() != EPosition::kSticky)
     return false;
 
   if (!(m_compositingTriggers & ViewportConstrainedPositionedTrigger) &&
@@ -216,7 +216,7 @@
   // container rather than the enclosing frame.
   if (layer->sticksToViewport())
     return m_layoutView.frameView()->isScrollable();
-  return layer->layoutObject()->style()->position() == StickyPosition &&
+  return layer->layoutObject()->style()->position() == EPosition::kSticky &&
          layer->ancestorOverflowLayer()->scrollsOverflow();
 }
 
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp
index 69a2df2..a50e7c71 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingRequirementsUpdater.cpp
@@ -190,7 +190,7 @@
     if (layer->layoutObject()->hasClipRelatedProperty())
       subtreeReasons |= CompositingReasonClipsCompositingDescendants;
 
-    if (layer->layoutObject()->style()->position() == FixedPosition)
+    if (layer->layoutObject()->style()->position() == EPosition::kFixed)
       subtreeReasons |= CompositingReasonPositionFixedWithCompositedDescendants;
   }
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_absolute_utils_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_absolute_utils_test.cc
index 334757fe..d74585b 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_absolute_utils_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_absolute_utils_test.cc
@@ -27,18 +27,14 @@
     container_size_ = NGLogicalSize(LayoutUnit(200), LayoutUnit(300));
     NGConstraintSpaceBuilder builder(kHorizontalTopBottom);
     builder.SetAvailableSize(container_size_);
-    ltr_space_ = builder.SetWritingMode(kHorizontalTopBottom)
-                     .SetTextDirection(TextDirection::kLtr)
-                     .ToConstraintSpace();
-    rtl_space_ = builder.SetWritingMode(kHorizontalTopBottom)
-                     .SetTextDirection(TextDirection::kRtl)
-                     .ToConstraintSpace();
-    vertical_lr_space_ = builder.SetWritingMode(kVerticalLeftRight)
-                             .SetTextDirection(TextDirection::kLtr)
-                             .ToConstraintSpace();
-    vertical_rl_space_ = builder.SetWritingMode(kVerticalLeftRight)
-                             .SetTextDirection(TextDirection::kLtr)
-                             .ToConstraintSpace();
+    ltr_space_ = builder.SetTextDirection(TextDirection::kLtr)
+                     .ToConstraintSpace(kHorizontalTopBottom);
+    rtl_space_ = builder.SetTextDirection(TextDirection::kRtl)
+                     .ToConstraintSpace(kHorizontalTopBottom);
+    vertical_lr_space_ = builder.SetTextDirection(TextDirection::kLtr)
+                             .ToConstraintSpace(kVerticalLeftRight);
+    vertical_rl_space_ = builder.SetTextDirection(TextDirection::kLtr)
+                             .ToConstraintSpace(kVerticalRightLeft);
   }
 
   void SetHorizontalStyle(LayoutUnit left,
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 0d92903..5eabe82 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -430,7 +430,7 @@
     if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock) {
       NGBlockNode* current_block_child = toNGBlockNode(current_child_);
       EPosition position = current_block_child->Style().position();
-      if (position == AbsolutePosition || position == FixedPosition) {
+      if (position == EPosition::kAbsolute || position == EPosition::kFixed) {
         builder_->AddOutOfFlowChildCandidate(current_block_child,
                                              GetChildSpaceOffset());
         current_child_ = current_block_child->NextSibling();
@@ -755,20 +755,22 @@
   DCHECK(current_child_);
   if (current_child_->Type() == NGLayoutInputNode::kLegacyInline) {
     // TODO(kojii): Setup space_builder_ appropriately for inline child.
-    return space_builder_->ToConstraintSpace();
+    return space_builder_->ToConstraintSpace(
+        FromPlatformWritingMode(Style().getWritingMode()));
     // Calculate margins in parent's writing mode.
   }
-  curr_child_margins_ = CalculateMargins(*space_builder_->ToConstraintSpace(),
-                                         CurrentChildStyle());
+  curr_child_margins_ =
+      CalculateMargins(*space_builder_->ToConstraintSpace(
+                           FromPlatformWritingMode(Style().getWritingMode())),
+                       CurrentChildStyle());
 
   const ComputedStyle& current_child_style = CurrentChildStyle();
+
   bool is_new_bfc = IsNewFormattingContextForInFlowBlockLevelChild(
       ConstraintSpace(), current_child_style);
   space_builder_->SetIsNewFormattingContext(is_new_bfc)
       .SetIsShrinkToFit(
           ShouldShrinkToFit(ConstraintSpace(), CurrentChildStyle()))
-      .SetWritingMode(
-          FromPlatformWritingMode(current_child_style.getWritingMode()))
       .SetTextDirection(current_child_style.direction());
   LayoutUnit space_available = SpaceAvailableForCurrentChild();
   space_builder_->SetFragmentainerSpaceAvailable(space_available);
@@ -813,7 +815,8 @@
 
   space_builder_->SetBfcOffset(curr_bfc_offset_);
 
-  return space_builder_->ToConstraintSpace();
+  return space_builder_->ToConstraintSpace(
+      FromPlatformWritingMode(current_child_style.getWritingMode()));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
index 4e2bf33..b8611401 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -34,9 +34,8 @@
       .SetAvailableSize(size)
       .SetPercentageResolutionSize(size)
       .SetTextDirection(direction)
-      .SetWritingMode(writing_mode)
       .SetIsShrinkToFit(shrink_to_fit)
-      .ToConstraintSpace();
+      .ToConstraintSpace(writing_mode);
 }
 
 typedef bool TestParamLayoutNG;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
index f95e7fd3..7e8127a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
@@ -118,7 +118,7 @@
       NGConstraintSpaceBuilder(
           FromPlatformWritingMode(Style().getWritingMode()))
           .SetTextDirection(Style().direction())
-          .ToConstraintSpace();
+          .ToConstraintSpace(FromPlatformWritingMode(Style().getWritingMode()));
 
   // TODO(cbiesinger): For orthogonal children, we need to always synthesize.
   NGBlockLayoutAlgorithm minmax_algorithm(layout_box_, &Style(), FirstChild(),
@@ -141,7 +141,7 @@
           .SetTextDirection(Style().direction())
           .SetAvailableSize({LayoutUnit::max(), LayoutUnit()})
           .SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()})
-          .ToConstraintSpace();
+          .ToConstraintSpace(FromPlatformWritingMode(Style().getWritingMode()));
 
   physical_fragment = Layout(constraint_space);
   NGBoxFragment max_fragment(FromPlatformWritingMode(Style().getWritingMode()),
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.cc b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.cc
index 36f5a94..1e653fc 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space.cc
@@ -100,7 +100,7 @@
           box.sizesLogicalWidthToFitContent(box.styleRef().logicalWidth()))
       .SetIsNewFormattingContext(is_new_fc)
       .SetTextDirection(box.styleRef().direction())
-      .ToConstraintSpace();
+      .ToConstraintSpace(writing_mode);
 }
 
 void NGConstraintSpace::AddExclusion(const NGExclusion& exclusion) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.cc
index 6bbcc37..f5e88ddf 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.cc
@@ -15,7 +15,6 @@
       initial_containing_block_size_(
           parent_space->InitialContainingBlockSize()),
       fragmentainer_space_available_(NGSizeIndefinite),
-      writing_mode_(parent_space->WritingMode()),
       parent_writing_mode_(parent_space->WritingMode()),
       is_fixed_size_inline_(false),
       is_fixed_size_block_(false),
@@ -31,8 +30,7 @@
 NGConstraintSpaceBuilder::NGConstraintSpaceBuilder(NGWritingMode writing_mode)
     : initial_containing_block_size_{NGSizeIndefinite, NGSizeIndefinite},
       fragmentainer_space_available_(NGSizeIndefinite),
-      writing_mode_(writing_mode),
-      parent_writing_mode_(writing_mode_),
+      parent_writing_mode_(writing_mode),
       is_fixed_size_inline_(false),
       is_fixed_size_block_(false),
       is_shrink_to_fit_(false),
@@ -119,18 +117,12 @@
   return *this;
 }
 
-NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetWritingMode(
-    NGWritingMode writing_mode) {
-  writing_mode_ = writing_mode;
-  return *this;
-}
-
-NGConstraintSpace* NGConstraintSpaceBuilder::ToConstraintSpace() {
-
+NGConstraintSpace* NGConstraintSpaceBuilder::ToConstraintSpace(
+    NGWritingMode out_writing_mode) {
   // Whether the child and the containing block are parallel to each other.
   // Example: vertical-rl and vertical-lr
   bool is_in_parallel_flow = (parent_writing_mode_ == kHorizontalTopBottom) ==
-                             (writing_mode_ == kHorizontalTopBottom);
+                             (out_writing_mode == kHorizontalTopBottom);
 
   NGLogicalSize available_size = available_size_;
   NGLogicalSize percentage_resolution_size = percentage_resolution_size_;
@@ -144,7 +136,7 @@
   // https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto
   if (available_size.inline_size == NGSizeIndefinite) {
     DCHECK(!is_in_parallel_flow);
-    if (writing_mode_ == kHorizontalTopBottom) {
+    if (out_writing_mode == kHorizontalTopBottom) {
       available_size.inline_size = initial_containing_block_size_.width;
     } else {
       available_size.inline_size = initial_containing_block_size_.height;
@@ -152,7 +144,7 @@
   }
   if (percentage_resolution_size.inline_size == NGSizeIndefinite) {
     DCHECK(!is_in_parallel_flow);
-    if (writing_mode_ == kHorizontalTopBottom) {
+    if (out_writing_mode == kHorizontalTopBottom) {
       percentage_resolution_size.inline_size =
           initial_containing_block_size_.width;
     } else {
@@ -169,7 +161,7 @@
 
   if (is_in_parallel_flow) {
     return new NGConstraintSpace(
-        static_cast<NGWritingMode>(writing_mode_),
+        static_cast<NGWritingMode>(out_writing_mode),
         static_cast<TextDirection>(text_direction_), available_size,
         percentage_resolution_size, initial_containing_block_size_,
         fragmentainer_space_available_, is_fixed_size_inline_,
@@ -180,11 +172,10 @@
         margin_strut, bfc_offset, exclusions);
   }
   return new NGConstraintSpace(
-      static_cast<NGWritingMode>(writing_mode_),
-      static_cast<TextDirection>(text_direction_), available_size,
-      percentage_resolution_size, initial_containing_block_size_,
-      fragmentainer_space_available_, is_fixed_size_block_,
-      is_fixed_size_inline_, is_shrink_to_fit_,
+      out_writing_mode, static_cast<TextDirection>(text_direction_),
+      available_size, percentage_resolution_size,
+      initial_containing_block_size_, fragmentainer_space_available_,
+      is_fixed_size_block_, is_fixed_size_inline_, is_shrink_to_fit_,
       is_block_direction_triggers_scrollbar_,
       is_inline_direction_triggers_scrollbar_,
       static_cast<NGFragmentationType>(fragmentation_type_), is_new_fc_,
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.h
index a9918a4..61549af0 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder.h
@@ -44,8 +44,6 @@
   NGConstraintSpaceBuilder& SetFragmentationType(NGFragmentationType);
   NGConstraintSpaceBuilder& SetIsNewFormattingContext(bool is_new_fc);
 
-  NGConstraintSpaceBuilder& SetWritingMode(NGWritingMode writing_mode);
-
   NGConstraintSpaceBuilder& SetMarginStrut(const NGMarginStrut& margin_strut);
 
   NGConstraintSpaceBuilder& SetBfcOffset(const NGLogicalOffset& offset) {
@@ -59,7 +57,9 @@
   //  - Is within a fragmentation container and needs its fragmentation offset
   //    updated.
   //  - Has its size is determined by its parent layout (flex, abs-pos).
-  NGConstraintSpace* ToConstraintSpace();
+  //
+  // NGWritingMode specifies the writing mode of the generated space.
+  NGConstraintSpace* ToConstraintSpace(NGWritingMode);
 
   DEFINE_INLINE_TRACE() {}
 
@@ -71,7 +71,6 @@
   NGPhysicalSize initial_containing_block_size_;
   LayoutUnit fragmentainer_space_available_;
 
-  unsigned writing_mode_ : 2;
   unsigned parent_writing_mode_ : 2;
   unsigned is_fixed_size_inline_ : 1;
   unsigned is_fixed_size_block_ : 1;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder_test.cc
index 38ebd90e..1c85d75b 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_builder_test.cc
@@ -33,12 +33,12 @@
   horizontal_builder.SetPercentageResolutionSize(fixed_size);
 
   NGConstraintSpaceBuilder vertical_builder(
-      horizontal_builder.ToConstraintSpace());
+      horizontal_builder.ToConstraintSpace(kHorizontalTopBottom));
 
   vertical_builder.SetAvailableSize(indefinite_size);
   vertical_builder.SetPercentageResolutionSize(indefinite_size);
-  vertical_builder.SetWritingMode(kVerticalLeftRight);
-  NGConstraintSpace* space = vertical_builder.ToConstraintSpace();
+  NGConstraintSpace* space =
+      vertical_builder.ToConstraintSpace(kVerticalLeftRight);
 
   EXPECT_EQ(space->AvailableSize().inline_size, icb_size.height);
   EXPECT_EQ(space->PercentageResolutionSize().inline_size, icb_size.height);
@@ -57,12 +57,12 @@
   horizontal_builder.SetPercentageResolutionSize(fixed_size);
 
   NGConstraintSpaceBuilder vertical_builder(
-      horizontal_builder.ToConstraintSpace());
+      horizontal_builder.ToConstraintSpace(kVerticalLeftRight));
 
   vertical_builder.SetAvailableSize(indefinite_size);
   vertical_builder.SetPercentageResolutionSize(indefinite_size);
-  vertical_builder.SetWritingMode(kHorizontalTopBottom);
-  NGConstraintSpace* space = vertical_builder.ToConstraintSpace();
+  NGConstraintSpace* space =
+      vertical_builder.ToConstraintSpace(kHorizontalTopBottom);
 
   EXPECT_EQ(space->AvailableSize().inline_size, icb_size.width);
   EXPECT_EQ(space->PercentageResolutionSize().inline_size, icb_size.width);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_test.cc
index 0c36c54..6da8e9e 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_constraint_space_test.cc
@@ -23,7 +23,7 @@
       .SetIsFixedSizeInline(true)
       .SetIsInlineDirectionTriggersScrollbar(true)
       .SetFragmentationType(NGFragmentationType::kFragmentColumn)
-      .ToConstraintSpace();
+      .ToConstraintSpace(writing_mode);
 }
 
 static String OpportunityToString(const NGLayoutOpportunity& opportunity) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc
index 9ff5381..d7b15e1 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc
@@ -66,7 +66,8 @@
   void CreateLine(NGInlineNode* node,
                   Vector<RefPtr<const NGPhysicalTextFragment>>* fragments_out) {
     NGConstraintSpace* constraint_space =
-        NGConstraintSpaceBuilder(kHorizontalTopBottom).ToConstraintSpace();
+        NGConstraintSpaceBuilder(kHorizontalTopBottom)
+            .ToConstraintSpace(kHorizontalTopBottom);
     NGLineBuilder line_builder(node, constraint_space);
 
     NGTextLayoutAlgorithm algorithm(node, constraint_space);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
index e298674e6..525d9181 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_length_utils.cc
@@ -192,7 +192,7 @@
   NGConstraintSpaceBuilder builder(writing_mode);
   builder.SetInitialContainingBlockSize(
       NGPhysicalSize{LayoutUnit(), LayoutUnit()});
-  NGConstraintSpace* space = builder.ToConstraintSpace();
+  NGConstraintSpace* space = builder.ToConstraintSpace(writing_mode);
 
   MinAndMaxContentSizes computed_sizes;
   Length inline_size = style.logicalWidth();
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_length_utils_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_length_utils_test.cc
index 963669d8..880fa88 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_length_utils_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_length_utils_test.cc
@@ -35,7 +35,7 @@
             NGLogicalSize(LayoutUnit(inline_size), LayoutUnit(block_size)))
         .SetIsFixedSizeInline(fixed_inline)
         .SetIsFixedSizeBlock(fixed_block)
-        .ToConstraintSpace();
+        .ToConstraintSpace(kHorizontalTopBottom);
   }
 
   LayoutUnit ResolveInlineLength(
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
index 85d2fe9..edf7f11 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -27,8 +27,8 @@
   bool contains_absolute =
       container_style.canContainAbsolutePositionObjects() || contains_fixed;
 
-  return (contains_absolute && position == AbsolutePosition) ||
-         (contains_fixed && position == FixedPosition);
+  return (contains_absolute && position == EPosition::kAbsolute) ||
+         (contains_fixed && position == EPosition::kFixed);
 }
 
 }  // namespace
@@ -59,7 +59,7 @@
   space_builder.SetPercentageResolutionSize(space_size);
   space_builder.SetIsNewFormattingContext(true);
   space_builder.SetTextDirection(container_style_.direction());
-  container_space_ = space_builder.ToConstraintSpace();
+  container_space_ = space_builder.ToConstraintSpace(writing_mode);
 }
 
 void NGOutOfFlowLayoutPart::Run() {
@@ -178,7 +178,8 @@
     builder.SetIsFixedSizeBlock(true);
   builder.SetIsFixedSizeInline(true);
   builder.SetIsNewFormattingContext(true);
-  NGConstraintSpace* space = builder.ToConstraintSpace();
+  NGConstraintSpace* space =
+      builder.ToConstraintSpace(container_space_->WritingMode());
 
   return descendant.Layout(space);
 }
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
index f7f24a4..40065752 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
@@ -28,6 +28,7 @@
 #include "core/dom/StyleEngine.h"
 #include "core/editing/TextAffinity.h"
 #include "core/editing/VisiblePosition.h"
+#include "core/frame/FrameView.h"
 #include "core/layout/svg/LayoutSVGText.h"
 #include "core/layout/svg/SVGLayoutSupport.h"
 #include "core/layout/svg/line/SVGInlineTextBox.h"
@@ -111,12 +112,12 @@
   if (static_cast<unsigned>(caretOffset) < textBox->start() + textBox->len()) {
     LayoutRect rect = textBox->localSelectionRect(caretOffset, caretOffset + 1);
     LayoutUnit x = box->isLeftToRightDirection() ? rect.x() : rect.maxX();
-    return LayoutRect(x, rect.y(), caretWidth(), rect.height());
+    return LayoutRect(x, rect.y(), frameView()->caretWidth(), rect.height());
   }
 
   LayoutRect rect = textBox->localSelectionRect(caretOffset - 1, caretOffset);
   LayoutUnit x = box->isLeftToRightDirection() ? rect.maxX() : rect.x();
-  return LayoutRect(x, rect.y(), caretWidth(), rect.height());
+  return LayoutRect(x, rect.y(), frameView()->caretWidth(), rect.height());
 }
 
 FloatRect LayoutSVGInlineText::floatLinesBoundingBox() const {
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index ecfd49d7..23f5e99 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -500,6 +500,7 @@
   visitor->trace(m_scrollingCoordinator);
   visitor->trace(m_mainFrame);
   visitor->trace(m_validationMessageClient);
+  visitor->trace(m_useCounter);
   visitor->trace(m_frameHost);
   Supplementable<Page>::trace(visitor);
   PageVisibilityNotifier::trace(visitor);
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index 96fea43..181bc55 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -284,7 +284,7 @@
     const PaintLayer* layer) {
   DCHECK(layer->hasCompositedLayerMapping());
   do {
-    if (layer->layoutObject()->style()->position() == FixedPosition) {
+    if (layer->layoutObject()->style()->position() == EPosition::kFixed) {
       const LayoutObject* fixedPositionObject = layer->layoutObject();
       bool fixedToRight = !fixedPositionObject->style()->right().isAuto();
       bool fixedToBottom = !fixedPositionObject->style()->bottom().isAuto();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index b0755de..bf4faf4 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -330,8 +330,8 @@
 }
 
 bool PaintLayer::sticksToViewport() const {
-  if (layoutObject()->style()->position() != FixedPosition &&
-      layoutObject()->style()->position() != StickyPosition)
+  if (layoutObject()->style()->position() != EPosition::kFixed &&
+      layoutObject()->style()->position() != EPosition::kSticky)
     return false;
 
   // TODO(pdr): This approach of calculating the nearest scroll node is O(n).
@@ -340,7 +340,7 @@
   if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
     const auto* viewProperties = layoutObject()->view()->paintProperties();
     const ScrollPaintPropertyNode* ancestorTargetScrollNode;
-    if (layoutObject()->style()->position() == FixedPosition) {
+    if (layoutObject()->style()->position() == EPosition::kFixed) {
       ancestorTargetScrollNode = viewProperties->localBorderBoxProperties()
                                      ->transform()
                                      ->findEnclosingScrollNode();
@@ -355,10 +355,10 @@
     return transform->findEnclosingScrollNode() == ancestorTargetScrollNode;
   }
 
-  return (layoutObject()->style()->position() == FixedPosition &&
+  return (layoutObject()->style()->position() == EPosition::kFixed &&
           layoutObject()->containerForFixedPosition() ==
               layoutObject()->view()) ||
-         (layoutObject()->style()->position() == StickyPosition &&
+         (layoutObject()->style()->position() == EPosition::kSticky &&
           (!ancestorScrollingLayer() || ancestorScrollingLayer() == root()));
 }
 
@@ -2685,7 +2685,7 @@
   }
 
   return (transform() ||
-          layoutObject()->style()->position() == FixedPosition) &&
+          layoutObject()->style()->position() == EPosition::kFixed) &&
          ((globalPaintFlags & GlobalPaintFlattenCompositingLayers) ||
           compositingState() != PaintsIntoOwnBacking);
 }
@@ -2718,7 +2718,7 @@
     return false;
 
   if (!RuntimeEnabledFeatures::compositeOpaqueFixedPositionEnabled() &&
-      layoutObject()->style()->position() == FixedPosition &&
+      layoutObject()->style()->position() == EPosition::kFixed &&
       compositingState() != PaintsIntoOwnBacking)
     return false;
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
index 5b8575c..d205e04 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -58,13 +58,13 @@
   // A fixed object is essentially the root of its containing block hierarchy,
   // so when we encounter such an object, we reset our clip rects to the
   // fixedClipRect.
-  if (position == FixedPosition) {
+  if (position == EPosition::kFixed) {
     clipRects.setPosClipRect(clipRects.fixedClipRect());
     clipRects.setOverflowClipRect(clipRects.fixedClipRect());
     clipRects.setFixed(true);
-  } else if (position == RelativePosition) {
+  } else if (position == EPosition::kRelative) {
     clipRects.setPosClipRect(clipRects.overflowClipRect());
-  } else if (position == AbsolutePosition) {
+  } else if (position == EPosition::kAbsolute) {
     clipRects.setOverflowClipRect(clipRects.posClipRect());
   }
 }
@@ -423,10 +423,10 @@
 
 static ClipRect backgroundClipRectForPosition(const ClipRects& parentRects,
                                               EPosition position) {
-  if (position == FixedPosition)
+  if (position == EPosition::kFixed)
     return parentRects.fixedClipRect();
 
-  if (position == AbsolutePosition)
+  if (position == EPosition::kAbsolute)
     return parentRects.posClipRect();
 
   return parentRects.overflowClipRect();
@@ -438,6 +438,9 @@
   DCHECK(m_geometryMapper);
   LayoutRect source(LayoutRect::infiniteIntRect());
   const auto* properties = m_layer.layoutObject()->paintProperties();
+  // TODO(chrishtr): fix the underlying bug that causes this situation.
+  if (!properties)
+    return ClipRect(source);
   DCHECK(properties && properties->localBorderBoxProperties());
 
   PropertyTreeState propertyTreeState = *properties->localBorderBoxProperties();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
index a496cf2..74fefefb 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerPainter.cpp
@@ -641,7 +641,7 @@
 inline bool PaintLayerPainter::isFixedPositionObjectInPagedMedia() {
   LayoutObject* object = m_paintLayer.layoutObject();
   LayoutView* view = object->view();
-  return object->styleRef().position() == FixedPosition &&
+  return object->styleRef().position() == EPosition::kFixed &&
          object->container() == view && view->pageLogicalHeight() &&
          // TODO(crbug.com/619094): Figure out the correct behaviour for fixed
          // position objects in paged media with vertical writing modes.
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index bd32373..8f1d9ac 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -1513,7 +1513,8 @@
 void PaintLayerScrollableArea::invalidateAllStickyConstraints() {
   if (PaintLayerScrollableAreaRareData* d = rareData()) {
     for (PaintLayer* stickyLayer : d->m_stickyConstraintsMap.keys()) {
-      if (stickyLayer->layoutObject()->style()->position() == StickyPosition)
+      if (stickyLayer->layoutObject()->style()->position() ==
+          EPosition::kSticky)
         stickyLayer->setNeedsCompositingInputsUpdate();
     }
     d->m_stickyConstraintsMap.clear();
@@ -1526,7 +1527,7 @@
   if (PaintLayerScrollableAreaRareData* d = rareData()) {
     d->m_stickyConstraintsMap.remove(layer);
     if (needsCompositingUpdate &&
-        layer->layoutObject()->style()->position() == StickyPosition)
+        layer->layoutObject()->style()->position() == EPosition::kSticky)
       layer->setNeedsCompositingInputsUpdate();
   }
 }
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 445c595..34b7942e 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -880,12 +880,12 @@
     context.current.paintOffset = boxModelObject.container()->paintOffset();
 
   switch (object.styleRef().position()) {
-    case StaticPosition:
+    case EPosition::kStatic:
       break;
-    case RelativePosition:
+    case EPosition::kRelative:
       context.current.paintOffset += boxModelObject.offsetForInFlowPosition();
       break;
-    case AbsolutePosition: {
+    case EPosition::kAbsolute: {
       DCHECK(context.containerForAbsolutePosition ==
              boxModelObject.container());
       context.current = context.absolutePosition;
@@ -902,10 +902,10 @@
       }
       break;
     }
-    case StickyPosition:
+    case EPosition::kSticky:
       context.current.paintOffset += boxModelObject.offsetForInFlowPosition();
       break;
-    case FixedPosition:
+    case EPosition::kFixed:
       context.current = context.fixedPosition;
       break;
     default:
diff --git a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
index b2eb801..969a6c3c 100644
--- a/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
+++ b/third_party/WebKit/Source/core/paint/PrePaintTreeWalk.cpp
@@ -82,7 +82,7 @@
   PaintLayer* paintLayer = object.enclosingLayer();
   paintLayer->updateAncestorOverflowLayer(context.ancestorOverflowPaintLayer);
 
-  if (object.styleRef().position() == StickyPosition) {
+  if (object.styleRef().position() == EPosition::kSticky) {
     paintLayer->layoutObject()->updateStickyPositionConstraints();
 
     // Sticky position constraints and ancestor overflow scroller affect the
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index c4b93f2..3fc7b74 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -371,9 +371,6 @@
   m_nonInheritedData.m_position = other.m_nonInheritedData.m_position;
   m_nonInheritedData.m_hasViewportUnits =
       other.m_nonInheritedData.m_hasViewportUnits;
-  m_nonInheritedData.m_breakBefore = other.m_nonInheritedData.m_breakBefore;
-  m_nonInheritedData.m_breakAfter = other.m_nonInheritedData.m_breakAfter;
-  m_nonInheritedData.m_breakInside = other.m_nonInheritedData.m_breakInside;
   m_nonInheritedData.m_hasRemUnits = other.m_nonInheritedData.m_hasRemUnits;
 
   // Correctly set during selector matching:
@@ -384,7 +381,7 @@
   // m_nonInheritedData.m_explicitInheritance
 
   // unique() styles are not cacheable.
-  DCHECK(!other.m_nonInheritedData.m_unique);
+  DCHECK(!other.unique());
 
   // styles with non inherited properties that reference variables are not
   // cacheable.
@@ -562,7 +559,7 @@
       diff.setNeedsFullLayout();
   }
 
-  if (!diff.needsFullLayout() && position() != StaticPosition &&
+  if (!diff.needsFullLayout() && position() != EPosition::kStatic &&
       m_surround->offset != other.m_surround->offset) {
     // Optimize for the case where a positioned layer is moving but not changing
     // size.
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 55a3a1a1..f9943f6 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -233,11 +233,9 @@
       return m_effectiveDisplay == other.m_effectiveDisplay &&
              m_originalDisplay == other.m_originalDisplay &&
              m_verticalAlign == other.m_verticalAlign &&
-             m_position == other.m_position &&
-             // hasViewportUnits
-             m_breakBefore == other.m_breakBefore &&
-             m_breakAfter == other.m_breakAfter &&
-             m_breakInside == other.m_breakInside;
+             m_position == other.m_position;
+      // Differences in the following fields do not cause inequality:
+      // hasViewportUnits
       // styleType
       // pseudoBits
       // explicitInheritance
@@ -267,10 +265,6 @@
 
     // 32 bits
 
-    unsigned m_breakBefore : 4;  // EBreakBetween
-    unsigned m_breakAfter : 4;   // EBreakBetween
-    unsigned m_breakInside : 2;  // EBreakInside
-
     unsigned m_styleType : 6;  // PseudoId
     unsigned m_pseudoBits : 8;
     unsigned m_explicitInheritance : 1;  // Explicitly inherits a non-inherited
@@ -311,13 +305,7 @@
             static_cast<unsigned>(initialDisplay());
     m_nonInheritedData.m_verticalAlign =
         static_cast<unsigned>(initialVerticalAlign());
-    m_nonInheritedData.m_position = initialPosition();
-    m_nonInheritedData.m_breakBefore =
-        static_cast<unsigned>(initialBreakBefore());
-    m_nonInheritedData.m_breakAfter =
-        static_cast<unsigned>(initialBreakAfter());
-    m_nonInheritedData.m_breakInside =
-        static_cast<unsigned>(initialBreakInside());
+    m_nonInheritedData.m_position = static_cast<unsigned>(initialPosition());
     m_nonInheritedData.m_styleType = PseudoIdNone;
     m_nonInheritedData.m_pseudoBits = 0;
     m_nonInheritedData.m_explicitInheritance = false;
@@ -766,36 +754,6 @@
     SET_VAR(m_box, m_boxSizing, static_cast<unsigned>(s));
   }
 
-  // Page break properties.
-  // break-after (shorthand for page-break-after and -webkit-column-break-after)
-  static EBreakBetween initialBreakAfter() { return EBreakBetween::kAuto; }
-  EBreakBetween breakAfter() const {
-    return static_cast<EBreakBetween>(m_nonInheritedData.m_breakAfter);
-  }
-  void setBreakAfter(EBreakBetween b) {
-    m_nonInheritedData.m_breakAfter = static_cast<unsigned>(b);
-  }
-
-  // break-before (shorthand for page-break-before and
-  // -webkit-column-break-before)
-  static EBreakBetween initialBreakBefore() { return EBreakBetween::kAuto; }
-  EBreakBetween breakBefore() const {
-    return static_cast<EBreakBetween>(m_nonInheritedData.m_breakBefore);
-  }
-  void setBreakBefore(EBreakBetween b) {
-    m_nonInheritedData.m_breakBefore = static_cast<unsigned>(b);
-  }
-
-  // break-inside (shorthand for page-break-inside and
-  // -webkit-column-break-inside)
-  static EBreakInside initialBreakInside() { return EBreakInside::kAuto; }
-  EBreakInside breakInside() const {
-    return static_cast<EBreakInside>(m_nonInheritedData.m_breakInside);
-  }
-  void setBreakInside(EBreakInside b) {
-    m_nonInheritedData.m_breakInside = static_cast<unsigned>(b);
-  }
-
   // clip
   static LengthBox initialClip() { return LengthBox(); }
   const LengthBox& clip() const { return m_visual->clip; }
@@ -1525,11 +1483,13 @@
   }
 
   // position
-  static EPosition initialPosition() { return StaticPosition; }
+  static EPosition initialPosition() { return EPosition::kStatic; }
   EPosition position() const {
     return static_cast<EPosition>(m_nonInheritedData.m_position);
   }
-  void setPosition(EPosition v) { m_nonInheritedData.m_position = v; }
+  void setPosition(EPosition v) {
+    m_nonInheritedData.m_position = static_cast<unsigned>(v);
+  }
 
   // resize
   static EResize initialResize() { return RESIZE_NONE; }
@@ -2595,11 +2555,6 @@
     SET_VAR(m_rareNonInheritedData, m_isStackingContext, b);
   }
 
-  // A unique style is one that has matches something that makes it impossible
-  // to share.
-  bool unique() const { return m_nonInheritedData.m_unique; }
-  void setUnique() { m_nonInheritedData.m_unique = true; }
-
   float textAutosizingMultiplier() const {
     return m_styleInheritedData->textAutosizingMultiplier;
   }
@@ -3242,13 +3197,15 @@
 
   // Position utility functions.
   bool hasOutOfFlowPosition() const {
-    return position() == AbsolutePosition || position() == FixedPosition;
+    return position() == EPosition::kAbsolute ||
+           position() == EPosition::kFixed;
   }
   bool hasInFlowPosition() const {
-    return position() == RelativePosition || position() == StickyPosition;
+    return position() == EPosition::kRelative ||
+           position() == EPosition::kSticky;
   }
   bool hasViewportConstrainedPosition() const {
-    return position() == FixedPosition || position() == StickyPosition;
+    return position() == EPosition::kFixed || position() == EPosition::kSticky;
   }
 
   // Clip utility functions.
@@ -3490,7 +3447,7 @@
   // but not managed in stacks. See ObjectPainter::paintAllPhasesAtomically().)
   void updateIsStackingContext(bool isDocumentElement, bool isInTopLayer);
   bool isStacked() const {
-    return isStackingContext() || position() != StaticPosition;
+    return isStackingContext() || position() != EPosition::kStatic;
   }
 
   // Pseudo-styles
@@ -3504,7 +3461,7 @@
   // canContainFixedPositionObjects.  We currently never use this value
   // directly, always OR'ing it with canContainFixedPositionObjects.
   bool canContainAbsolutePositionObjects() const {
-    return position() != StaticPosition;
+    return position() != EPosition::kStatic;
   }
   bool canContainFixedPositionObjects() const {
     return hasTransformRelatedProperty() || containsPaint();
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index 8fb40f22..2692e2e1 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -121,12 +121,12 @@
 
 enum OutlineIsAuto { OutlineIsAutoOff = 0, OutlineIsAutoOn };
 
-enum EPosition {
-  StaticPosition,
-  RelativePosition,
-  AbsolutePosition,
-  StickyPosition,
-  FixedPosition
+enum class EPosition : unsigned {
+  kStatic,
+  kRelative,
+  kAbsolute,
+  kSticky,
+  kFixed
 };
 
 enum EMarginCollapse {
@@ -306,23 +306,6 @@
   TextUnderlinePositionUnder
 };
 
-// Values applicable to the break-before, break-after properties.
-enum class EBreakBetween : unsigned {
-  kAuto,
-  kAvoid,
-  kAvoidColumn,
-  kAvoidPage,
-  kColumn,
-  kLeft,
-  kPage,
-  kRecto,
-  kRight,
-  kVerso
-};
-
-// Values applicable to the break-inside property.
-enum class EBreakInside : unsigned { kAuto, kAvoid, kAvoidColumn, kAvoidPage };
-
 enum class ECursor : unsigned {
   kAuto,
   kCrosshair,
diff --git a/third_party/WebKit/Source/core/style/OWNERS b/third_party/WebKit/Source/core/style/OWNERS
new file mode 100644
index 0000000..64176816
--- /dev/null
+++ b/third_party/WebKit/Source/core/style/OWNERS
@@ -0,0 +1,2 @@
+meade@chromium.org
+suzyh@chromium.org
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 0b5b0862..3b798ec 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -157,6 +157,35 @@
 
 namespace blink {
 
+namespace {
+
+class UseCounterObserverImpl final : public UseCounter::Observer {
+  WTF_MAKE_NONCOPYABLE(UseCounterObserverImpl);
+
+ public:
+  UseCounterObserverImpl(ScriptPromiseResolver* resolver,
+                         UseCounter::Feature feature)
+      : m_resolver(resolver), m_feature(feature) {}
+
+  bool onCountFeature(UseCounter::Feature feature) final {
+    if (m_feature != feature)
+      return false;
+    m_resolver->resolve(feature);
+    return true;
+  }
+
+  DEFINE_INLINE_VIRTUAL_TRACE() {
+    UseCounter::Observer::trace(visitor);
+    visitor->trace(m_resolver);
+  }
+
+ private:
+  Member<ScriptPromiseResolver> m_resolver;
+  UseCounter::Feature m_feature;
+};
+
+}  // namespace
+
 static WTF::Optional<DocumentMarker::MarkerType> markerTypeFrom(
     const String& markerType) {
   if (equalIgnoringCase(markerType, "Spelling"))
@@ -2986,6 +3015,34 @@
   return UseCounter::isCounted(*document, propertyName);
 }
 
+ScriptPromise Internals::observeUseCounter(ScriptState* scriptState,
+                                           Document* document,
+                                           uint32_t feature) {
+  ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
+  ScriptPromise promise = resolver->promise();
+  if (feature >= UseCounter::NumberOfFeatures) {
+    resolver->reject();
+    return promise;
+  }
+
+  UseCounter::Feature useCounterFeature =
+      static_cast<UseCounter::Feature>(feature);
+  if (UseCounter::isCounted(*document, useCounterFeature)) {
+    resolver->resolve();
+    return promise;
+  }
+
+  Frame* frame = document->frame();
+  if (!frame || !frame->host()) {
+    resolver->reject();
+    return promise;
+  }
+
+  frame->host()->useCounter().addObserver(
+      new UseCounterObserverImpl(resolver, useCounterFeature));
+  return promise;
+}
+
 String Internals::unscopableAttribute() {
   return "unscopableAttribute";
 }
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index 71751dd..48849dc 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -493,6 +493,11 @@
   bool isUseCounted(Document*, uint32_t feature);
   bool isCSSPropertyUseCounted(Document*, const String&);
 
+  // Observes changes on Document's UseCounter. Returns a promise that is
+  // resolved when |feature| is counted. When |feature| was already counted,
+  // it's immediately resolved.
+  ScriptPromise observeUseCounter(ScriptState*, Document*, uint32_t feature);
+
   // Used by the iterable<>.
   unsigned length() const { return 5; }
   int anonymousIndexedGetter(uint32_t index) const { return index * index; }
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index 372f2ab..33563cf 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -331,6 +331,11 @@
     boolean isUseCounted(Document document, unsigned long feature);
     boolean isCSSPropertyUseCounted(Document document, DOMString propertyName);
 
+    // Returns a promise that is resolved when |feature| is counted on
+    // |document|'s UseCounter. When |feature| was already counted, it's
+    // immediately resolved.
+    [CallWith=ScriptState] Promise<bool> observeUseCounter(Document document, unsigned long feature);
+
     readonly attribute unsigned long length;
     getter long (unsigned long index);
     iterable<long>;
diff --git a/third_party/WebKit/Source/core/timing/Performance.cpp b/third_party/WebKit/Source/core/timing/Performance.cpp
index b5a7447c..20e24d2 100644
--- a/third_party/WebKit/Source/core/timing/Performance.cpp
+++ b/third_party/WebKit/Source/core/timing/Performance.cpp
@@ -142,8 +142,7 @@
 
 void Performance::updateLongTaskInstrumentation() {
   DCHECK(frame());
-  if (!frame()->document() ||
-      !OriginTrials::longTaskObserverEnabled(frame()->document()))
+  if (!frame()->document())
     return;
 
   if (hasObserverFor(PerformanceEntry::LongTask)) {
diff --git a/third_party/WebKit/Source/core/timing/PerformanceLongTaskTiming.idl b/third_party/WebKit/Source/core/timing/PerformanceLongTaskTiming.idl
index 39c7ef5..9f7c9dc 100644
--- a/third_party/WebKit/Source/core/timing/PerformanceLongTaskTiming.idl
+++ b/third_party/WebKit/Source/core/timing/PerformanceLongTaskTiming.idl
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://github.com/wicg/longtasks
-[
-    OriginTrialEnabled=LongTaskObserver,
-] interface PerformanceLongTaskTiming : PerformanceEntry {
-    readonly attribute FrozenArray<TaskAttributionTiming> attribution;
+// https://wicg.github.io/longtasks/#sec-PerformanceLongTaskTiming
+interface PerformanceLongTaskTiming : PerformanceEntry {
+    [SameObject, SaveSameObject] readonly attribute FrozenArray<TaskAttributionTiming> attribution;
 };
diff --git a/third_party/WebKit/Source/core/timing/TaskAttributionTiming.idl b/third_party/WebKit/Source/core/timing/TaskAttributionTiming.idl
index f90ae835..326b084b 100644
--- a/third_party/WebKit/Source/core/timing/TaskAttributionTiming.idl
+++ b/third_party/WebKit/Source/core/timing/TaskAttributionTiming.idl
@@ -3,9 +3,7 @@
 // found in the LICENSE file.
 
 // https://github.com/wicg/longtasks
-[
-    OriginTrialEnabled=LongTaskObserver,
-] interface TaskAttributionTiming : PerformanceEntry {
+interface TaskAttributionTiming : PerformanceEntry {
     readonly attribute DOMString containerType;
     readonly attribute DOMString containerSrc;
     readonly attribute DOMString containerId;
diff --git a/third_party/WebKit/Source/devtools/front_end/.editorconfig b/third_party/WebKit/Source/devtools/front_end/.editorconfig
index 3c44241..c6c8b36 100644
--- a/third_party/WebKit/Source/devtools/front_end/.editorconfig
+++ b/third_party/WebKit/Source/devtools/front_end/.editorconfig
@@ -2,7 +2,7 @@
 
 [*]
 indent_style = space
-indent_size = 4
+indent_size = 2
 end_of_line = lf
 charset = utf-8
 trim_trailing_whitespace = true
diff --git a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
index 0da03669..6e63d2ba 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
@@ -35,8 +35,11 @@
     this._protocolService.registerStatusCallback(msg => this._updateStatus(Common.UIString(msg)));
 
     this._pwaSetting = Common.settings.createSetting('audits2_pwa', true);
+    this._pwaSetting.setTitle(Common.UIString('Progressive web app audits'));
     this._perfSetting = Common.settings.createSetting('audits2_perf', true);
+    this._perfSetting.setTitle(Common.UIString('Performance metrics and diagnostics'));
     this._practicesSetting = Common.settings.createSetting('audits2_best_practices', true);
+    this._practicesSetting.setTitle(Common.UIString('Modern web development best practices'));
 
     var auditsViewElement = this.contentElement.createChild('div', 'hbox audits-view');
     this._resultsView = this.contentElement.createChild('div', 'vbox results-view');
@@ -49,16 +52,6 @@
     this._resultsView.removeChildren();
   }
 
-  /**
-   * @param {string} name
-   * @param {!Common.Setting} setting
-   * @return {!UI.ToolbarItem}
-   */
-  _createSettingCheckbox(name, setting) {
-    const checkboxItem = new UI.ToolbarCheckbox(name, undefined, setting);
-    return checkboxItem;
-  }
-
   _createLauncherUI() {
     var uiElement = createElement('div');
     var headerElement = uiElement.createChild('header');
@@ -68,11 +61,9 @@
 
     var auditSelectorForm = uiElement.createChild('form', 'audits2-form');
 
-    var perfCheckbox =
-        this._createSettingCheckbox(Common.UIString('Performance metrics and diagnostics'), this._perfSetting);
-    var pwaCheckbox = this._createSettingCheckbox(Common.UIString('Progressive web app audits'), this._pwaSetting);
-    var practicesCheckbox =
-        this._createSettingCheckbox(Common.UIString('Modern web development best practices'), this._practicesSetting);
+    var perfCheckbox = new UI.ToolbarSettingCheckbox(this._perfSetting);
+    var pwaCheckbox = new UI.ToolbarSettingCheckbox(this._pwaSetting);
+    var practicesCheckbox = new UI.ToolbarSettingCheckbox(this._practicesSetting);
     [perfCheckbox, practicesCheckbox, pwaCheckbox].forEach(checkbox => auditSelectorForm.appendChild(checkbox.element));
 
     this._startButton = UI.createTextButton(
diff --git a/third_party/WebKit/Source/devtools/front_end/common/Settings.js b/third_party/WebKit/Source/devtools/front_end/common/Settings.js
index ffa709e9..0c5f8d8 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/Settings.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/Settings.js
@@ -59,6 +59,8 @@
     var isLocal = !!descriptor['local'];
     var setting = settingType === 'regex' ? this.createRegExpSetting(settingName, defaultValue, undefined, isLocal) :
                                             this.createSetting(settingName, defaultValue, isLocal);
+    if (descriptor['title'])
+      setting.setTitle(descriptor['title']);
     this._moduleSettings.set(settingName, setting);
   }
 
@@ -231,6 +233,8 @@
     this._defaultValue = defaultValue;
     this._eventSupport = eventSupport;
     this._storage = storage;
+    /** @type {string} */
+    this._title = '';
   }
 
   /**
@@ -254,6 +258,20 @@
   }
 
   /**
+   * @return {string}
+   */
+  title() {
+    return this._title;
+  }
+
+  /**
+   * @param {string} title
+   */
+  setTitle(title) {
+    this._title = title;
+  }
+
+  /**
    * @return {V}
    */
   get() {
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
index c39376af..c8e5bb0 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
@@ -80,12 +80,12 @@
     toolbar.appendSeparator();
     toolbar.appendToolbarItem(this._showSettingsPaneButton);
 
-    this._preserveLogCheckbox = new UI.ToolbarCheckbox(
-        Common.UIString('Preserve log'), Common.UIString('Do not clear log on page reload / navigation'),
-        Common.moduleSetting('preserveConsoleLog'));
-    this._hideNetworkMessagesCheckbox = new UI.ToolbarCheckbox(
-        Common.UIString('Hide network'), Common.UIString('Hide network messages'),
-        this._filter._hideNetworkMessagesSetting);
+    this._preserveLogCheckbox = new UI.ToolbarSettingCheckbox(
+        Common.moduleSetting('preserveConsoleLog'), Common.UIString('Do not clear log on page reload / navigation'),
+        Common.UIString('Preserve log'));
+    this._hideNetworkMessagesCheckbox = new UI.ToolbarSettingCheckbox(
+        this._filter._hideNetworkMessagesSetting, this._filter._hideNetworkMessagesSetting.title(),
+        Common.UIString('Hide network'));
 
     var settingsToolbar = new UI.Toolbar('', this._contentsElement);
     settingsToolbar.appendToolbarItem(this._hideNetworkMessagesCheckbox);
@@ -1039,7 +1039,7 @@
    */
   constructor(filterChangedCallback) {
     this._showTargetMessagesCheckbox =
-        new UI.ToolbarCheckbox(Common.UIString('Selected context only'), undefined, undefined, filterChangedCallback);
+        new UI.ToolbarCheckbox(Common.UIString('Selected context only'), undefined, filterChangedCallback);
     this._filterChanged = filterChangedCallback;
 
     this._messageURLFiltersSetting = Common.settings.createSetting('messageURLFilters', {});
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ComputedStyleWidget.js b/third_party/WebKit/Source/devtools/front_end/elements/ComputedStyleWidget.js
index dfa4ba7..473a5f6 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ComputedStyleWidget.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ComputedStyleWidget.js
@@ -55,8 +55,8 @@
     filterContainerElement.appendChild(filterInput);
 
     var toolbar = new UI.Toolbar('styles-pane-toolbar', hbox);
-    toolbar.appendToolbarItem(new UI.ToolbarCheckbox(
-        Common.UIString('Show all'), undefined, this._showInheritedComputedStylePropertiesSetting));
+    toolbar.appendToolbarItem(new UI.ToolbarSettingCheckbox(
+        this._showInheritedComputedStylePropertiesSetting, undefined, Common.UIString('Show all')));
 
     this._propertiesOutline = new UI.TreeOutlineInShadow();
     this._propertiesOutline.hideOverflow();
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
index fab103e3..124e5b44 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -445,7 +445,7 @@
    * @override
    */
   searchCanceled() {
-    delete this._searchQuery;
+    delete this._searchConfig;
     this._hideSearchHighlights();
 
     this._searchableView.updateSearchMatchesCount(0);
@@ -464,14 +464,17 @@
    */
   performSearch(searchConfig, shouldJump, jumpBackwards) {
     var query = searchConfig.query;
-    // Call searchCanceled since it will reset everything we need before doing a new search.
-    this.searchCanceled();
 
     const whitespaceTrimmedQuery = query.trim();
     if (!whitespaceTrimmedQuery.length)
       return;
 
-    this._searchQuery = query;
+    if (!this._searchConfig || this._searchConfig.query !== query)
+      this.searchCanceled();
+    else
+      this._hideSearchHighlights();
+
+    this._searchConfig = searchConfig;
 
     var promises = [];
     var domModels = SDK.DOMModel.instances();
@@ -498,10 +501,18 @@
       this._searchableView.updateSearchMatchesCount(this._searchResults.length);
       if (!this._searchResults.length)
         return;
-      this._currentSearchResultIndex = -1;
+      if (this._currentSearchResultIndex >= this._searchResults.length)
+        this._currentSearchResultIndex = undefined;
 
-      if (shouldJump)
-        this._jumpToSearchResult(jumpBackwards ? -1 : 0);
+      var index = this._currentSearchResultIndex;
+
+      if (shouldJump) {
+        if (this._currentSearchResultIndex === undefined)
+          index = jumpBackwards ? -1 : 0;
+        else
+          index = jumpBackwards ? index - 1 : index + 1;
+        this._jumpToSearchResult(index);
+      }
     }
   }
 
@@ -553,7 +564,6 @@
   }
 
   _jumpToSearchResult(index) {
-    this._hideSearchHighlights();
     this._currentSearchResultIndex = (index + this._searchResults.length) % this._searchResults.length;
     this._highlightCurrentSearchResult();
   }
@@ -564,7 +574,7 @@
   jumpToNextSearchResult() {
     if (!this._searchResults)
       return;
-    this._jumpToSearchResult(this._currentSearchResultIndex + 1);
+    this.performSearch(this._searchConfig, true);
   }
 
   /**
@@ -573,7 +583,7 @@
   jumpToPreviousSearchResult() {
     if (!this._searchResults)
       return;
-    this._jumpToSearchResult(this._currentSearchResultIndex - 1);
+    this.performSearch(this._searchConfig, true, true);
   }
 
   /**
@@ -621,7 +631,7 @@
 
     var treeElement = this._treeElementForNode(searchResult.node);
     if (treeElement) {
-      treeElement.highlightSearchResults(this._searchQuery);
+      treeElement.highlightSearchResults(this._searchConfig.query);
       treeElement.reveal();
       var matches = treeElement.listItemElement.getElementsByClassName(UI.highlightedSearchResultClassName);
       if (matches.length)
@@ -630,7 +640,7 @@
   }
 
   _hideSearchHighlights() {
-    if (!this._searchResults || !this._searchResults.length || this._currentSearchResultIndex < 0)
+    if (!this._searchResults || !this._searchResults.length || this._currentSearchResultIndex === undefined)
       return;
     var searchResult = this._searchResults[this._currentSearchResultIndex];
     if (!searchResult.node)
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/EventListenersWidget.js b/third_party/WebKit/Source/devtools/front_end/elements/EventListenersWidget.js
index 4e20c8d..606bf913 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/EventListenersWidget.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/EventListenersWidget.js
@@ -44,15 +44,16 @@
     this._dispatchFilterBySetting.addChangeListener(this.update.bind(this));
 
     this._showFrameworkListenersSetting = Common.settings.createSetting('showFrameowkrListeners', true);
+    this._showFrameworkListenersSetting.setTitle(Common.UIString('Framework listeners'));
     this._showFrameworkListenersSetting.addChangeListener(this._showFrameworkListenersChanged.bind(this));
     this._eventListenersView = new EventListeners.EventListenersView(this.element, this.update.bind(this));
 
     var refreshButton = new UI.ToolbarButton(Common.UIString('Refresh'), 'largeicon-refresh');
     refreshButton.addEventListener(UI.ToolbarButton.Events.Click, this.update.bind(this));
     this._toolbarItems.push(refreshButton);
-    this._toolbarItems.push(new UI.ToolbarCheckbox(
-        Common.UIString('Ancestors'), Common.UIString('Show listeners on the ancestors'),
-        this._showForAncestorsSetting));
+    this._toolbarItems.push(new UI.ToolbarSettingCheckbox(
+        this._showForAncestorsSetting, Common.UIString('Show listeners on the ancestors'),
+        Common.UIString('Ancestors')));
     var dispatchFilter = new UI.ToolbarComboBox(this._onDispatchFilterTypeChanged.bind(this));
 
     /**
@@ -72,9 +73,8 @@
         this, Common.UIString('Blocking'), Elements.EventListenersWidget.DispatchFilterBy.Blocking);
     dispatchFilter.setMaxWidth(200);
     this._toolbarItems.push(dispatchFilter);
-    this._toolbarItems.push(new UI.ToolbarCheckbox(
-        Common.UIString('Framework listeners'), Common.UIString('Resolve event listeners bound with framework'),
-        this._showFrameworkListenersSetting));
+    this._toolbarItems.push(new UI.ToolbarSettingCheckbox(
+        this._showFrameworkListenersSetting, Common.UIString('Resolve event listeners bound with framework')));
 
     UI.context.addFlavorChangeListener(SDK.DOMNode, this.update, this);
     this.update();
diff --git a/third_party/WebKit/Source/devtools/front_end/event_listeners/EventListenersUtils.js b/third_party/WebKit/Source/devtools/front_end/event_listeners/EventListenersUtils.js
index 0ef1e74..ba611df 100644
--- a/third_party/WebKit/Source/devtools/front_end/event_listeners/EventListenersUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/event_listeners/EventListenersUtils.js
@@ -178,7 +178,7 @@
           throw new Error('Empty event listener\'s location');
         return new SDK.EventListener(
             handler._target, object, type, useCapture, passive, once, handler, originalHandler, location,
-            removeFunctionObject, 'frameworkUser');
+            removeFunctionObject, SDK.EventListener.Origin.FrameworkUser);
       }
     }
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/event_listeners/EventListenersView.js b/third_party/WebKit/Source/devtools/front_end/event_listeners/EventListenersView.js
index 80befa8..55dde0c 100644
--- a/third_party/WebKit/Source/devtools/front_end/event_listeners/EventListenersView.js
+++ b/third_party/WebKit/Source/devtools/front_end/event_listeners/EventListenersView.js
@@ -111,7 +111,7 @@
       function setIsInternal(isInternal) {
         for (var i = 0; i < eventListeners.length; ++i) {
           if (isInternal[i])
-            eventListeners[i].setListenerType('frameworkInternal');
+            eventListeners[i].markAsFramework();
         }
       }
     }
@@ -148,11 +148,11 @@
     for (var eventType of eventTypes) {
       var hiddenEventType = true;
       for (var listenerElement of eventType.children()) {
-        var listenerType = listenerElement.eventListener().listenerType();
+        var listenerOrigin = listenerElement.eventListener().origin();
         var hidden = false;
-        if (listenerType === 'frameworkUser' && !showFramework)
+        if (listenerOrigin === SDK.EventListener.Origin.FrameworkUser && !showFramework)
           hidden = true;
-        if (listenerType === 'frameworkInternal' && showFramework)
+        if (listenerOrigin === SDK.EventListener.Origin.Framework && showFramework)
           hidden = true;
         if (!showPassive && listenerElement.eventListener().passive())
           hidden = true;
@@ -288,7 +288,7 @@
     title.appendChild(
         Components.ObjectPropertiesSection.createValueElement(object, false /* wasThrown */, false /* showPreview */));
 
-    if (this._eventListener.removeFunction()) {
+    if (this._eventListener.canRemove()) {
       var deleteButton = title.createChild('span', 'event-listener-button');
       deleteButton.textContent = Common.UIString('Remove');
       deleteButton.title = Common.UIString('Delete event listener');
@@ -296,7 +296,7 @@
       title.appendChild(deleteButton);
     }
 
-    if (this._eventListener.isScrollBlockingType() && this._eventListener.isNormalListenerType()) {
+    if (this._eventListener.isScrollBlockingType() && this._eventListener.canTogglePassive()) {
       var passiveButton = title.createChild('span', 'event-listener-button');
       passiveButton.textContent = Common.UIString('Toggle Passive');
       passiveButton.title = Common.UIString('Toggle whether event listener is passive or blocking');
diff --git a/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js b/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js
index 52f1fe9..949a6fb 100644
--- a/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js
+++ b/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js
@@ -666,11 +666,10 @@
    * @return {!Common.Setting}
    */
   _createVisibilitySetting(caption, name, value, toolbar) {
-    var checkbox = new UI.ToolbarCheckbox(Common.UIString(caption));
-    toolbar.appendToolbarItem(checkbox);
     var setting = Common.settings.createSetting(name, value);
-    UI.SettingsUI.bindCheckbox(checkbox.inputElement, setting);
+    setting.setTitle(Common.UIString(caption));
     setting.addChangeListener(this._update, this);
+    toolbar.appendToolbarItem(new UI.ToolbarSettingCheckbox(setting));
     return setting;
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index 28e0ec6b..22e209dc 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -755,7 +755,7 @@
       return;
     var manager = SDK.multitargetNetworkManager;
     manager.addEventListener(SDK.MultitargetNetworkManager.Events.ConditionsChanged, updateVisibility);
-    var blockedURLsSetting = Common.moduleSetting('blockedURLs');
+    var blockedURLsSetting = Common.moduleSetting('networkBlockedURLs');
     blockedURLsSetting.addChangeListener(updateVisibility);
     updateVisibility();
 
diff --git a/third_party/WebKit/Source/devtools/front_end/network/BlockedURLsPane.js b/third_party/WebKit/Source/devtools/front_end/network/BlockedURLsPane.js
index 1b7d1069..e38c045 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/BlockedURLsPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/BlockedURLsPane.js
@@ -12,7 +12,7 @@
 
     Network.BlockedURLsPane._instance = this;
 
-    this._blockedURLsSetting = Common.moduleSetting('blockedURLs');
+    this._blockedURLsSetting = Common.moduleSetting('networkBlockedURLs');
     this._blockedURLsSetting.addChangeListener(this._update, this);
 
     this._toolbar = new UI.Toolbar('', this.contentElement);
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
index e4b4722..aecd203 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
@@ -1101,24 +1101,50 @@
     contextMenu.appendItem(Common.UIString.capitalize('Clear ^browser ^cache'), this._clearBrowserCache.bind(this));
     contextMenu.appendItem(Common.UIString.capitalize('Clear ^browser ^cookies'), this._clearBrowserCookies.bind(this));
 
-    var blockedSetting = Common.moduleSetting('blockedURLs');
     if (request && Runtime.experiments.isEnabled('requestBlocking')) {  // Disabled until ready.
       contextMenu.appendSeparator();
 
+      var blockedSetting = Common.moduleSetting('networkBlockedURLs');
+      var blockedSettingData = blockedSetting.get();
+
+      const maxBlockedURLLength = 20;
       var urlWithoutScheme = request.parsedURL.urlWithoutScheme();
-      if (urlWithoutScheme && blockedSetting.get().indexOf(urlWithoutScheme) === -1) {
+      var blockedURLIndex = blockedSettingData.indexOf(urlWithoutScheme);
+      if (urlWithoutScheme && blockedURLIndex === -1) {
         contextMenu.appendItem(
             Common.UIString.capitalize('Block ^request URL'), addBlockedURL.bind(null, urlWithoutScheme));
+      } else if (urlWithoutScheme) {
+        const croppedURL = urlWithoutScheme.trimMiddle(maxBlockedURLLength);
+        contextMenu.appendItem(
+            Common.UIString.capitalize('Unblock ' + croppedURL), removeBlockedURLIndex.bind(null, blockedURLIndex));
       }
 
       var domain = request.parsedURL.domain();
-      if (domain && blockedSetting.get().indexOf(domain) === -1)
+      var blockedDomainIndex = blockedSettingData.indexOf(domain);
+      if (domain && blockedDomainIndex === -1) {
         contextMenu.appendItem(Common.UIString.capitalize('Block ^request ^domain'), addBlockedURL.bind(null, domain));
+      } else if (domain) {
+        const croppedDomain = domain.trimMiddle(maxBlockedURLLength);
+        contextMenu.appendItem(
+            Common.UIString.capitalize('Unblock ' + croppedDomain),
+            removeBlockedURLIndex.bind(null, blockedDomainIndex));
+      }
 
+      /**
+       * @param {string} url
+       */
       function addBlockedURL(url) {
-        var list = blockedSetting.get();
-        list.push(url);
-        blockedSetting.set(list);
+        blockedSettingData.push(url);
+        blockedSetting.set(blockedSettingData);
+        UI.viewManager.showView('network.blocked-urls');
+      }
+
+      /**
+       * @param {number} index
+       */
+      function removeBlockedURLIndex(index) {
+        blockedSettingData.splice(index, 1);
+        blockedSetting.set(blockedSettingData);
         UI.viewManager.showView('network.blocked-urls');
       }
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
index 26747b3..c145cd9 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkPanel.js
@@ -170,9 +170,9 @@
         'change', this._onPreserveLogCheckboxChanged.bind(this), false);
     this._panelToolbar.appendToolbarItem(this._preserveLogCheckbox);
 
-    this._disableCacheCheckbox = new UI.ToolbarCheckbox(
-        Common.UIString('Disable cache'), Common.UIString('Disable cache (while DevTools is open)'),
-        Common.moduleSetting('cacheDisabled'));
+    this._disableCacheCheckbox = new UI.ToolbarSettingCheckbox(
+        Common.moduleSetting('cacheDisabled'), Common.UIString('Disable cache (while DevTools is open)'),
+        Common.UIString('Disable cache'));
     this._panelToolbar.appendToolbarItem(this._disableCacheCheckbox);
 
     this._panelToolbar.appendSeparator();
@@ -186,7 +186,7 @@
    * @return {!UI.ToolbarItem}
    */
   _createBlockedURLsButton() {
-    var setting = Common.moduleSetting('blockedURLs');
+    var setting = Common.moduleSetting('networkBlockedURLs');
     setting.addChangeListener(updateAction);
     var action = /** @type {!UI.Action }*/ (UI.actionRegistry.action('network.blocked-urls.show'));
     var button = UI.Toolbar.createActionButton(action);
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestTimingView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestTimingView.js
index c7783e87..f7e137f 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/RequestTimingView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/RequestTimingView.js
@@ -287,8 +287,11 @@
       var metric = tr.createChild('td', 'network-timing-metric');
       metric.createTextChild(serverTiming.description || serverTiming.metric);
       var row = tr.createChild('td').createChild('div', 'network-timing-row');
-      var left = scale * (endTime - startTime - serverTiming.value);
-      if (serverTiming.value && left >= 0) {  // don't chart values too big or too small
+
+      if (serverTiming.value === null)
+        return;
+      var left = scale * (endTime - startTime - (serverTiming.value / 1000));
+      if (left >= 0) {  // don't chart values too big or too small
         var bar = row.createChild('span', 'network-timing-bar server-timing');
         bar.style.left = left + '%';
         bar.style.right = right + '%';
@@ -297,8 +300,7 @@
           bar.style.backgroundColor = colorGenerator.colorForID(serverTiming.metric);
       }
       var label = tr.createChild('td').createChild('div', 'network-timing-bar-title');
-      if (typeof serverTiming.value === 'number')  // a metric timing value is optional
-        label.textContent = Number.secondsToString(serverTiming.value, true);
+      label.textContent = Number.millisToString(serverTiming.value, true);
     }
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js b/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js
index 4afdb61e..82f6a33 100644
--- a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js
+++ b/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js
@@ -171,7 +171,7 @@
    */
   static createOfflineToolbarCheckbox() {
     var checkbox = new UI.ToolbarCheckbox(
-        Common.UIString('Offline'), Common.UIString('Force disconnected from network'), undefined, forceOffline);
+        Common.UIString('Offline'), Common.UIString('Force disconnected from network'), forceOffline);
     SDK.multitargetNetworkManager.addEventListener(
         SDK.MultitargetNetworkManager.Events.ConditionsChanged, networkConditionsChanged);
     checkbox.setChecked(SDK.multitargetNetworkManager.networkConditions() === SDK.NetworkManager.OfflineConditions);
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/AppManifestView.js b/third_party/WebKit/Source/devtools/front_end/resources/AppManifestView.js
index a8ae577c..ceab686 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/AppManifestView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/AppManifestView.js
@@ -28,6 +28,14 @@
     addToHomeScreen.addEventListener(UI.ToolbarButton.Events.Click, this._addToHomescreen, this);
     toolbar.appendToolbarItem(addToHomeScreen);
 
+    this._manifestlessSection = this._reportView.appendSection(Common.UIString('No manifest detected'));
+    var p = createElement('p');
+    p.textContent = 'A web manifest allows you to control how your app behaves when launched and displayed to the user. ';
+    p.appendChild(UI.createExternalLink('https://developers.google.com/web/progressive-web-apps/?utm_source=devtools',
+        Common.UIString('Read more on developers.google.com')));
+    this._manifestlessSection.element.appendChild(p);
+    this._manifestlessSection.element.classList.add('hidden');
+
     this._presentationSection = this._reportView.appendSection(Common.UIString('Presentation'));
     this._iconsSection = this._reportView.appendSection(Common.UIString('Icons'));
 
@@ -103,8 +111,12 @@
           UI.createLabel(error.message, error.critical ? 'smallicon-error' : 'smallicon-warning'));
     }
 
-    if (!data)
-      data = '{}';
+    var manifestDataFound = !!data;
+    this._manifestlessSection.element.classList.toggle('hidden', manifestDataFound);
+    this._presentationSection.element.classList.toggle('hidden', !manifestDataFound);
+    this._iconsSection.element.classList.toggle('hidden', !manifestDataFound);
+    this._identitySection.element.classList.toggle('hidden', !manifestDataFound);
+    if (!data) return;
 
     var parsedManifest = JSON.parse(data);
     this._nameField.textContent = stringProperty('name');
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
index bebb91a..af55aa88 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkersView.js
@@ -18,14 +18,15 @@
     this._sections = new Map();
 
     this._toolbar.appendToolbarItem(NetworkConditions.NetworkConditionsSelector.createOfflineToolbarCheckbox());
-    var forceUpdate = new UI.ToolbarCheckbox(
-        Common.UIString('Update on reload'), Common.UIString('Force update Service Worker on page reload'),
-        Common.settings.createSetting('serviceWorkerUpdateOnReload', false));
+    var updateOnReloadSetting = Common.settings.createSetting('serviceWorkerUpdateOnReload', false);
+    updateOnReloadSetting.setTitle(Common.UIString('Update on reload'));
+    var forceUpdate = new UI.ToolbarSettingCheckbox(
+        updateOnReloadSetting, Common.UIString('Force update Service Worker on page reload'));
     this._toolbar.appendToolbarItem(forceUpdate);
-    var fallbackToNetwork = new UI.ToolbarCheckbox(
-        Common.UIString('Bypass for network'),
-        Common.UIString('Bypass Service Worker and load resources from the network'),
-        Common.settings.createSetting('bypassServiceWorker', false));
+    var bypassServiceWorkerSetting = Common.settings.createSetting('bypassServiceWorker', false);
+    bypassServiceWorkerSetting.setTitle(Common.UIString('Bypass for network'));
+    var fallbackToNetwork = new UI.ToolbarSettingCheckbox(
+        bypassServiceWorkerSetting, Common.UIString('Bypass Service Worker and load resources from the network'));
     this._toolbar.appendToolbarItem(fallbackToNetwork);
     this._toolbar.appendSpacer();
     this._showAllCheckbox = new UI.ToolbarCheckbox(
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
index 4d30f28a..2a0ae0a 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/NetworkManager.js
@@ -687,7 +687,7 @@
 
     /** @type {!Set<string>} */
     this._blockedURLs = new Set();
-    this._blockedSetting = Common.moduleSetting('blockedURLs');
+    this._blockedSetting = Common.moduleSetting('networkBlockedURLs');
     this._blockedSetting.addChangeListener(this._updateBlockedURLs, this);
     this._blockedSetting.set([]);
     this._updateBlockedURLs();
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js b/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
index f04e101..e10b37b 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
@@ -586,7 +586,7 @@
             payload.originalHandler ? this.target().runtimeModel.createRemoteObject(payload.originalHandler) : null,
             /** @type {!SDK.DebuggerModel.Location} */ (this._debuggerModel.createRawLocationByScriptId(
                 payload.scriptId, payload.lineNumber, payload.columnNumber)),
-            payload.removeFunction ? this.target().runtimeModel.createRemoteObject(payload.removeFunction) : null);
+            null);
       }
     }
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/RuntimeModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/RuntimeModel.js
index 8d9464a..d4c9f1a 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/RuntimeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/RuntimeModel.js
@@ -603,8 +603,8 @@
    * @param {?SDK.RemoteObject} handler
    * @param {?SDK.RemoteObject} originalHandler
    * @param {!SDK.DebuggerModel.Location} location
-   * @param {?SDK.RemoteObject} removeFunction
-   * @param {string=} listenerType
+   * @param {?SDK.RemoteObject} customRemoveFunction
+   * @param {!SDK.EventListener.Origin=} origin
    */
   constructor(
       target,
@@ -616,8 +616,8 @@
       handler,
       originalHandler,
       location,
-      removeFunction,
-      listenerType) {
+      customRemoveFunction,
+      origin) {
     super(target);
     this._eventTarget = eventTarget;
     this._type = type;
@@ -629,8 +629,8 @@
     this._location = location;
     var script = location.script();
     this._sourceURL = script ? script.contentURL() : '';
-    this._removeFunction = removeFunction;
-    this._listenerType = listenerType || 'normal';
+    this._customRemoveFunction = customRemoveFunction;
+    this._origin = origin || SDK.EventListener.Origin.Raw;
   }
 
   /**
@@ -690,19 +690,40 @@
   }
 
   /**
-   * @return {?SDK.RemoteObject}
+   * @return {boolean}
    */
-  removeFunction() {
-    return this._removeFunction;
+  canRemove() {
+    return !!this._customRemoveFunction || this._origin !== SDK.EventListener.Origin.FrameworkUser;
   }
 
   /**
    * @return {!Promise<undefined>}
    */
   remove() {
-    if (!this._removeFunction)
+    if (!this.canRemove())
       return Promise.resolve();
-    return this._removeFunction
+
+    if (this._origin !== SDK.EventListener.Origin.FrameworkUser) {
+      /**
+       * @param {string} type
+       * @param {function()} listener
+       * @param {boolean} useCapture
+       * @this {Object}
+       * @suppressReceiverCheck
+       */
+      function removeListener(type, listener, useCapture) {
+        this.removeEventListener(type, listener, useCapture);
+        if (this['on' + type])
+          this['on' + type] = undefined;
+      }
+
+      return /** @type {!Promise<undefined>} */ (this._eventTarget.callFunctionPromise(removeListener, [
+        SDK.RemoteObject.toCallArgument(this._type), SDK.RemoteObject.toCallArgument(this._originalHandler),
+        SDK.RemoteObject.toCallArgument(this._useCapture)
+      ]));
+    }
+
+    return this._customRemoveFunction
         .callFunctionPromise(
             callCustomRemove,
             [
@@ -727,54 +748,46 @@
   }
 
   /**
+   * @return {boolean}
+   */
+  canTogglePassive() {
+    return this._origin !== SDK.EventListener.Origin.FrameworkUser;
+  }
+
+  /**
    * @return {!Promise<undefined>}
    */
   togglePassive() {
-    return new Promise(promiseConstructor.bind(this));
+    return /** @type {!Promise<undefined>} */ (this._eventTarget.callFunctionPromise(callTogglePassive, [
+      SDK.RemoteObject.toCallArgument(this._type),
+      SDK.RemoteObject.toCallArgument(this._originalHandler),
+      SDK.RemoteObject.toCallArgument(this._useCapture),
+      SDK.RemoteObject.toCallArgument(this._passive),
+    ]));
 
     /**
-     * @param {function()} success
-     * @this {SDK.EventListener}
+     * @param {string} type
+     * @param {function()} listener
+     * @param {boolean} useCapture
+     * @param {boolean} passive
+     * @this {Object}
+     * @suppressReceiverCheck
      */
-    function promiseConstructor(success) {
-      this._eventTarget
-          .callFunctionPromise(
-              callTogglePassive,
-              [
-                SDK.RemoteObject.toCallArgument(this._type),
-                SDK.RemoteObject.toCallArgument(this._originalHandler),
-                SDK.RemoteObject.toCallArgument(this._useCapture),
-                SDK.RemoteObject.toCallArgument(this._passive),
-              ])
-          .then(success);
-
-      /**
-       * @param {string} type
-       * @param {function()} listener
-       * @param {boolean} useCapture
-       * @param {boolean} passive
-       * @this {Object}
-       * @suppressReceiverCheck
-       */
-      function callTogglePassive(type, listener, useCapture, passive) {
-        this.removeEventListener(type, listener, {capture: useCapture});
-        this.addEventListener(type, listener, {capture: useCapture, passive: !passive});
-      }
+    function callTogglePassive(type, listener, useCapture, passive) {
+      this.removeEventListener(type, listener, {capture: useCapture});
+      this.addEventListener(type, listener, {capture: useCapture, passive: !passive});
     }
   }
 
   /**
-   * @return {string}
+   * @return {!SDK.EventListener.Origin}
    */
-  listenerType() {
-    return this._listenerType;
+  origin() {
+    return this._origin;
   }
 
-  /**
-   * @param {string} listenerType
-   */
-  setListenerType(listenerType) {
-    this._listenerType = listenerType;
+  markAsFramework() {
+    this._origin = SDK.EventListener.Origin.Framework;
   }
 
   /**
@@ -784,11 +797,11 @@
     return this._type === 'touchstart' || this._type === 'touchmove' || this._type === 'mousewheel' ||
         this._type === 'wheel';
   }
+};
 
-  /**
-   * @return {boolean}
-   */
-  isNormalListenerType() {
-    return this._listenerType === 'normal';
-  }
+/** @enum {string} */
+SDK.EventListener.Origin = {
+  Raw: 'Raw',
+  Framework: 'Framework',
+  FrameworkUser: 'FrameworkUser'
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ServerTiming.js b/third_party/WebKit/Source/devtools/front_end/sdk/ServerTiming.js
index 04a3296..186f0fd9 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ServerTiming.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ServerTiming.js
@@ -7,8 +7,8 @@
 SDK.ServerTiming = class {
   /**
    * @param {string} metric
-   * @param {number} value
-   * @param {string} description
+   * @param {?number} value
+   * @param {?string} description
    */
   constructor(metric, value, description) {
     this.metric = metric;
@@ -39,9 +39,11 @@
         var metric = metricMatch[1];
         var value = metricMatch[2];
         var description = metricMatch[3] || metricMatch[4];
-        if (value !== null)
+        if (value !== undefined)
           value = Math.abs(parseFloat(metricMatch[2]));
         valueString = metricMatch[5];  // comma delimited headers
+        if (value === undefined || isNaN(value))
+          value = null;
         result.push(new SDK.ServerTiming(metric, value, description));
       }
       return result;
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/module.json b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
index 5e4ea05..f84271f9 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
@@ -8,7 +8,7 @@
     "extensions": [
         {
             "type": "setting",
-            "settingName": "blockedURLs",
+            "settingName": "networkBlockedURLs",
             "settingType": "array",
             "defaultValue": []
         },
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
index b39685ff..5589753e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
@@ -37,6 +37,7 @@
       'DOMNodeInsertedIntoDocument', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument', 'DOMSubtreeModified',
       'DOMContentLoaded'
     ]);
+    this._createCategory(Common.UIString('Geolocation'), ['navigator.geolocation.getCurrentPosition', 'navigator.geolocation.watchPosition'], true);
     this._createCategory(Common.UIString('Drag / drop'), ['dragenter', 'dragover', 'dragleave', 'drop']);
     this._createCategory(Common.UIString('Keyboard'), ['keydown', 'keyup', 'keypress', 'input']);
     this._createCategory(
@@ -54,6 +55,7 @@
       'auxclick', 'click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mousemove', 'mouseout', 'mouseenter',
       'mouseleave', 'mousewheel', 'wheel', 'contextmenu'
     ]);
+    this._createCategory(Common.UIString('Notification'), ['Notification.requestPermission'], true);
     this._createCategory(Common.UIString('Parse'), ['setInnerHTML', 'document.write'], true);
     this._createCategory(Common.UIString('Pointer'), [
       'pointerover', 'pointerout', 'pointerenter', 'pointerleave', 'pointerdown', 'pointerup', 'pointermove',
@@ -94,6 +96,9 @@
         'instrumentation:webglWarningFired': Common.UIString('WebGL Warning Fired'),
         'instrumentation:setInnerHTML': Common.UIString('Set innerHTML'),
         'instrumentation:canvasContextCreated': Common.UIString('Create canvas context'),
+        'instrumentation:navigator.geolocation.getCurrentPosition': 'getCurrentPosition',
+        'instrumentation:navigator.geolocation.watchPosition': 'watchPosition',
+        'instrumentation:Notification.requestPermission': 'requestPermission',
       };
     }
     if (auxData) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
index 3be12c0..6b477d6 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -692,9 +692,9 @@
     debugToolbar.appendToolbarItem(this._pauseOnExceptionButton);
 
     debugToolbar.appendSeparator();
-    debugToolbar.appendToolbarItem(new UI.ToolbarCheckbox(
-        Common.UIString('Async'), Common.UIString('Capture async stack traces'),
-        Common.moduleSetting('enableAsyncStackTraces')));
+    debugToolbar.appendToolbarItem(new UI.ToolbarSettingCheckbox(
+        Common.moduleSetting('enableAsyncStackTraces'), Common.UIString('Capture async stack traces'),
+        Common.UIString('Async')));
 
     return debugToolbar;
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js b/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js
index 3cf42ff..1654e79 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js
@@ -379,7 +379,8 @@
     var container = countersPane._infoWidget.element.createChild('div', 'memory-counter-selector-info');
 
     this._setting = Common.settings.createSetting('timelineCountersGraph-' + title, true);
-    this._filter = new UI.ToolbarCheckbox(title, title, this._setting);
+    this._setting.setTitle(title);
+    this._filter = new UI.ToolbarSettingCheckbox(this._setting, title);
     this._filter.inputElement.classList.add('-theme-preserve');
     var color = Common.Color.parse(graphColor).setAlpha(0.5).asString(Common.Color.Format.RGBA);
     if (color) {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/EventsTimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/EventsTimelineTreeView.js
index 692e451..951b5e0 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/EventsTimelineTreeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/EventsTimelineTreeView.js
@@ -161,8 +161,8 @@
     for (var durationMs of Timeline.EventsTimelineTreeView.Filters._durationFilterPresetsMs) {
       durationFilterUI.addOption(durationFilterUI.createOption(
           durationMs ? Common.UIString('\u2265 %d\u2009ms', durationMs) : Common.UIString('All'),
-          durationMs ? Common.UIString('Hide records shorter than %d\u2009ms', durationMs)
-                     : Common.UIString('Show all records'),
+          durationMs ? Common.UIString('Hide records shorter than %d\u2009ms', durationMs) :
+                       Common.UIString('Show all records'),
           String(durationMs)));
     }
     toolbar.appendToolbarItem(durationFilterUI);
@@ -173,8 +173,8 @@
       var category = categories[categoryName];
       if (!category.visible)
         continue;
-      var checkbox = new UI.ToolbarCheckbox(
-          category.title, undefined, undefined, categoriesFilterChanged.bind(this, categoryName));
+      var checkbox =
+          new UI.ToolbarCheckbox(category.title, undefined, categoriesFilterChanged.bind(this, categoryName));
       checkbox.setChecked(true);
       checkbox.inputElement.style.backgroundColor = category.color;
       categoryFiltersUI[category.name] = checkbox;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/ExtensionTracingSession.js b/third_party/WebKit/Source/devtools/front_end/timeline/ExtensionTracingSession.js
index 64375d7..22aa0a8 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/ExtensionTracingSession.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/ExtensionTracingSession.js
@@ -26,6 +26,10 @@
   loadingStarted() {
   }
 
+  /** @override */
+  processingStarted() {
+  }
+
   /**
    * @override
    * @param {number=} progress
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js
index 6dae0d95..e97ba72b 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js
@@ -216,6 +216,11 @@
   }
 
   _allSourcesFinished() {
+    this._client.processingStarted();
+    setTimeout(() => this._finalizeTrace(), 0);
+  }
+
+  _finalizeTrace() {
     this._injectCpuProfileEvents();
     this._tracingModel.tracingComplete();
     this._client.loadingComplete(this._tracingModel, this._tracingModelBackingStorage);
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLoader.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLoader.js
index 0dfc8e0..39565442 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLoader.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLoader.js
@@ -177,6 +177,11 @@
   close() {
     if (!this._client)
       return;
+    this._client.processingStarted();
+    setTimeout(() => this._finalizeTrace(), 0);
+  }
+
+  _finalizeTrace() {
     this._tracingModel.tracingComplete();
     this._client.loadingComplete(this._tracingModel, this._backingStorage);
   }
@@ -238,6 +243,8 @@
    */
   loadingProgress(progress) {},
 
+  processingStarted() {},
+
   /**
    * @param {?SDK.TracingModel} tracingModel
    * @param {?Bindings.TempFileBackingStorage} backingStorage
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
index acdbcf2..ce9d0a91 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -74,11 +74,15 @@
         Common.settings.createSetting('timelineViewMode', Timeline.TimelinePanel.ViewMode.FlameChart);
 
     this._disableCaptureJSProfileSetting = Common.settings.createSetting('timelineDisableJSSampling', false);
+    this._disableCaptureJSProfileSetting.setTitle(Common.UIString('Disable JavaScript Samples'));
     this._captureLayersAndPicturesSetting = Common.settings.createSetting('timelineCaptureLayersAndPictures', false);
+    this._captureLayersAndPicturesSetting.setTitle(Common.UIString('Enable advanced paint instrumentation (slow)'));
 
     this._showScreenshotsSetting = Common.settings.createLocalSetting('timelineShowScreenshots', true);
+    this._showScreenshotsSetting.setTitle(Common.UIString('Screenshots'));
     this._showScreenshotsSetting.addChangeListener(this._onModeChanged, this);
     this._showMemorySetting = Common.settings.createLocalSetting('timelineShowMemory', false);
+    this._showMemorySetting.setTitle(Common.UIString('Memory'));
     this._showMemorySetting.addChangeListener(this._onModeChanged, this);
 
     this._panelToolbar = new UI.Toolbar('', this.element);
@@ -245,13 +249,12 @@
   }
 
   /**
-   * @param {string} name
    * @param {!Common.Setting} setting
    * @param {string} tooltip
    * @return {!UI.ToolbarItem}
    */
-  _createSettingCheckbox(name, setting, tooltip) {
-    const checkboxItem = new UI.ToolbarCheckbox(name, tooltip, setting);
+  _createSettingCheckbox(setting, tooltip) {
+    const checkboxItem = new UI.ToolbarSettingCheckbox(setting, tooltip);
     this._recordingOptionUIControls.push(checkboxItem);
     return checkboxItem;
   }
@@ -267,12 +270,12 @@
 
     // View
     this._panelToolbar.appendSeparator();
-    this._showScreenshotsToolbarCheckbox = this._createSettingCheckbox(
-        Common.UIString('Screenshots'), this._showScreenshotsSetting, Common.UIString('Capture screenshots'));
+    this._showScreenshotsToolbarCheckbox =
+        this._createSettingCheckbox(this._showScreenshotsSetting, Common.UIString('Capture screenshots'));
     this._panelToolbar.appendToolbarItem(this._showScreenshotsToolbarCheckbox);
 
-    this._showMemoryToolbarCheckbox = this._createSettingCheckbox(
-        Common.UIString('Memory'), this._showMemorySetting, Common.UIString('Show memory timeline.'));
+    this._showMemoryToolbarCheckbox =
+        this._createSettingCheckbox(this._showMemorySetting, Common.UIString('Show memory timeline'));
     this._panelToolbar.appendToolbarItem(this._showMemoryToolbarCheckbox);
 
     // GC
@@ -304,10 +307,10 @@
     captureToolbar.element.classList.add('flex-auto');
     captureToolbar.makeVertical();
     captureToolbar.appendToolbarItem(this._createSettingCheckbox(
-        Common.UIString('Disable JavaScript Samples'), this._disableCaptureJSProfileSetting,
+        this._disableCaptureJSProfileSetting,
         Common.UIString('Disables JavaScript sampling, reduces overhead when running against mobile devices')));
     captureToolbar.appendToolbarItem(this._createSettingCheckbox(
-        Common.UIString('Enable advanced paint instrumentation (slow)'), this._captureLayersAndPicturesSetting,
+        this._captureLayersAndPicturesSetting,
         Common.UIString('Captures advanced paint instrumentation, introduces significant performance overhead')));
 
     var throttlingPane = new UI.VBox();
@@ -331,7 +334,7 @@
   _appendExtensionsToToolbar(event) {
     var provider = /** @type {!Extensions.ExtensionTraceProvider} */ (event.data);
     const setting = Timeline.TimelinePanel._settingForTraceProvider(provider);
-    const checkbox = this._createSettingCheckbox(provider.shortDisplayName(), setting, provider.longDisplayName());
+    const checkbox = this._createSettingCheckbox(setting, provider.longDisplayName());
     this._panelToolbar.appendToolbarItem(checkbox);
   }
 
@@ -344,6 +347,7 @@
     if (!setting) {
       var providerId = traceProvider.persistentIdentifier();
       setting = Common.settings.createSetting(providerId, false);
+      setting.setTitle(traceProvider.shortDisplayName());
       traceProvider[Timeline.TimelinePanel._traceProviderSettingSymbol] = setting;
     }
     return setting;
@@ -681,24 +685,27 @@
     }
 
     var learnMoreNode = UI.createExternalLink(
-        'https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/', Common.UIString('Learn more'));
-    var recordNode =
+        'https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/', Common.UIString('Learn\xa0more'));
+    var recordKey =
         encloseWithTag('b', UI.shortcutRegistry.shortcutDescriptorsForAction('timeline.toggle-recording')[0].name);
-    var reloadNode = encloseWithTag('b', UI.shortcutRegistry.shortcutDescriptorsForAction('main.reload')[0].name);
+    var reloadKey = encloseWithTag('b', UI.shortcutRegistry.shortcutDescriptorsForAction('main.reload')[0].name);
     var navigateNode = encloseWithTag('b', Common.UIString('WASD'));
 
     this._landingPage = new UI.VBox();
     this._landingPage.contentElement.classList.add('timeline-landing-page', 'fill');
     var centered = this._landingPage.contentElement.createChild('div');
 
-    centered.createChild('p').appendChild(UI.formatLocalized(
-        'To capture a new recording, click the record button or hit %s.%s' +
-            'To evaluate the page load, click the reload button or hit %s to record the reload.',
-        [recordNode, createElement('br'), reloadNode]));
+    var recordButton = UI.Toolbar.createActionButton(this._toggleRecordAction).element;
+    var reloadButton = UI.Toolbar.createActionButtonForId('main.reload').element;
 
     centered.createChild('p').appendChild(UI.formatLocalized(
-        'After recording, select an area of interest in the overview by dragging. ' +
-            'Then, zoom and pan the timeline with the mousewheel or %s keys. %s',
+        'Click the record button %s or hit %s to capture a new recording.\n' +
+        'Click the reload button %s or hit %s to record and evaluate the page load.',
+        [recordButton, recordKey, reloadButton, reloadKey]));
+
+    centered.createChild('p').appendChild(UI.formatLocalized(
+        'After recording, select an area of interest in the overview by dragging.\n' +
+        'Then, zoom and pan the timeline with the mousewheel or %s keys.\n%s',
         [navigateNode, learnMoreNode]));
 
     var cpuProfilerHintSetting = Common.settings.createSetting('timelineShowProfilerHint', true);
@@ -752,6 +759,13 @@
 
   /**
    * @override
+   */
+  processingStarted() {
+    this._statusPane.updateStatus(Common.UIString('Processing profile\u2026'));
+  }
+
+  /**
+   * @override
    * @param {?SDK.TracingModel} tracingModel
    * @param {?Bindings.TempFileBackingStorage} backingStorage
    */
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
index 71df758..24ed2206 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -248,12 +248,27 @@
     var url = TimelineModel.TimelineData.forEvent(traceEvent).url;
     if (url)
       tokens.push(url);
-    for (var argName in traceEvent.args) {
-      var argValue = traceEvent.args[argName];
-      for (var key in argValue)
-        tokens.push(argValue[key]);
-    }
+    appendObjectProperties(traceEvent.args, 2);
     return regExp.test(tokens.join('|'));
+
+    /**
+     * @param {!Object} object
+     * @param {number} depth
+     */
+    function appendObjectProperties(object, depth) {
+      if (!depth)
+        return;
+      for (var key in object) {
+        var value = object[key];
+        var type = typeof value;
+        if (type === 'string')
+          tokens.push(value);
+        else if (type === 'number')
+          tokens.push(String(value));
+        else if (type === 'object')
+          appendObjectProperties(value, depth - 1);
+      }
+    }
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
index 588da282..5def207 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -658,12 +658,29 @@
 }
 
 .timeline-landing-page > div {
-    max-width: 430px;
+    max-width: 450px;
     margin: 10px;
 }
 
 .timeline-landing-page > div > p {
     flex: none;
+    white-space: pre-line;
+}
+
+.timeline-landing-page button {
+    padding: 0;
+    vertical-align: sub;
+    border: 1px solid #ddd;
+    margin-top: 4px;
+    background-color: #f3f3f3;
+}
+
+.timeline-landing-page button > span {
+    margin: -1px 2px -3px -2px;
+}
+
+.timeline-landing-page button > span:hover {
+    background-color: #333;
 }
 
 .timeline-landing-warning {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
index e984f35..e0dfe62 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -1005,18 +1005,15 @@
 UI.ToolbarCheckbox = class extends UI.ToolbarItem {
   /**
    * @param {string} text
-   * @param {string=} title
-   * @param {!Common.Setting=} setting
+   * @param {string=} tooltip
    * @param {function()=} listener
    */
-  constructor(text, title, setting, listener) {
+  constructor(text, tooltip, listener) {
     super(UI.createCheckboxLabel(text));
     this.element.classList.add('checkbox');
     this.inputElement = this.element.checkboxElement;
-    if (title)
-      this.element.title = title;
-    if (setting)
-      UI.SettingsUI.bindCheckbox(this.inputElement, setting);
+    if (tooltip)
+      this.element.title = tooltip;
     if (listener)
       this.inputElement.addEventListener('click', listener, false);
   }
@@ -1044,3 +1041,15 @@
     this.inputElement.disabled = !enabled;
   }
 };
+
+UI.ToolbarSettingCheckbox = class extends UI.ToolbarCheckbox {
+  /**
+   * @param {!Common.Setting} setting
+   * @param {string=} tooltip
+   * @param {string=} alternateTitle
+   */
+  constructor(setting, tooltip, alternateTitle) {
+    super(alternateTitle || setting.title() || '', tooltip);
+    UI.SettingsUI.bindCheckbox(this.inputElement, setting);
+  }
+};
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/reportView.css b/third_party/WebKit/Source/devtools/front_end/ui/reportView.css
index 4ee8696b..3b07cd3 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/reportView.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/reportView.css
@@ -14,6 +14,11 @@
     overflow: auto;
 }
 
+.report-content-box p {
+    white-space: initial;
+    line-height: 18px;
+}
+
 .report-header {
     border-bottom: 1px solid rgb(230, 230, 230);
     padding: 12px 24px;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
index f044821..e962836 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js
@@ -1213,3 +1213,12 @@
 
 /** @const */
 UI.TreeElement._ArrowToggleWidth = 10;
+
+(function() {
+  var img = new Image();
+  if (window.devicePixelRatio > 1)
+    img.src = 'Images/treeoutlineTriangles_2x.png';
+  else
+    img.src = 'Images/treeoutlineTriangles.png';
+  UI.TreeElement._imagePreload = img;
+})();
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.idl
index 915939f..e40dd84d 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.idl
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTCharacteristic.idl
@@ -10,14 +10,14 @@
     DependentLifetime,
     RuntimeEnabled=WebBluetooth,
 ] interface BluetoothRemoteGATTCharacteristic : EventTarget {//: CharacteristicEventHandlers {
-    readonly attribute BluetoothRemoteGATTService        service;
-    readonly attribute UUID                              uuid;
+    [SameObject] readonly attribute BluetoothRemoteGATTService service;
+    readonly attribute UUID uuid;
     readonly attribute BluetoothCharacteristicProperties properties;
-    readonly attribute DataView?                         value;
-    [RaisesException, CallWith=ScriptState] Promise<BluetoothRemoteGATTDescriptor>           getDescriptor(BluetoothDescriptorUUID descriptor);
+    readonly attribute DataView? value;
+    [RaisesException, CallWith=ScriptState] Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor);
     [RaisesException, CallWith=ScriptState] Promise<sequence<BluetoothRemoteGATTDescriptor>> getDescriptors(optional BluetoothDescriptorUUID descriptor);
-    [CallWith=ScriptState] Promise<DataView>                          readValue();
-    [CallWith=ScriptState] Promise<void>                              writeValue(BufferSource value);
+    [CallWith=ScriptState] Promise<DataView> readValue();
+    [CallWith=ScriptState] Promise<void> writeValue(BufferSource value);
     [CallWith=ScriptState] Promise<BluetoothRemoteGATTCharacteristic> startNotifications();
     [CallWith=ScriptState] Promise<BluetoothRemoteGATTCharacteristic> stopNotifications();
 
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.idl
index 070b7db..1372cc0 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.idl
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTDescriptor.idl
@@ -9,10 +9,9 @@
 [
     RuntimeEnabled=WebBluetooth,
 ] interface BluetoothRemoteGATTDescriptor  {
-
-    readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
-    readonly attribute UUID                              uuid;
-    readonly attribute DataView?                         value;
-    [CallWith=ScriptState] Promise<DataView>             readValue();
-    [CallWith=ScriptState] Promise<void>                 writeValue(BufferSource value);
+    [SameObject] readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
+    readonly attribute UUID uuid;
+    readonly attribute DataView? value;
+    [CallWith=ScriptState] Promise<DataView> readValue();
+    [CallWith=ScriptState] Promise<void> writeValue(BufferSource value);
 };
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.idl
index be0e8fb..1499961 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.idl
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTServer.idl
@@ -10,10 +10,10 @@
     RuntimeEnabled=WebBluetooth,
 ] interface BluetoothRemoteGATTServer
 {
-    readonly attribute BluetoothDevice                   device;
-    readonly attribute boolean                           connected;
-    [CallWith=ScriptState] Promise<BluetoothRemoteGATTServer>             connect();
-    [CallWith=ScriptState] void                                           disconnect();
+    [SameObject] readonly attribute BluetoothDevice device;
+    readonly attribute boolean connected;
+    [CallWith=ScriptState] Promise<BluetoothRemoteGATTServer> connect();
+    [CallWith=ScriptState] void disconnect();
     [CallWith=ScriptState, RaisesException] Promise<BluetoothRemoteGATTService> getPrimaryService (BluetoothServiceUUID service);
     [CallWith=ScriptState, RaisesException] Promise<sequence<BluetoothRemoteGATTService>> getPrimaryServices (optional BluetoothServiceUUID service);
 };
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.idl
index d0e2a531..6e75a47 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.idl
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothRemoteGATTService.idl
@@ -9,11 +9,11 @@
 [
     RuntimeEnabled=WebBluetooth,
 ] interface BluetoothRemoteGATTService { // : ServiceEventHandlers {
-    readonly attribute UUID            uuid;
-    readonly attribute boolean         isPrimary;
-    readonly attribute BluetoothDevice device;
-    [RaisesException, CallWith=ScriptState] Promise<BluetoothRemoteGATTCharacteristic>           getCharacteristic(BluetoothCharacteristicUUID characteristic);
+    [SameObject] readonly attribute BluetoothDevice device;
+    readonly attribute UUID uuid;
+    readonly attribute boolean isPrimary;
+    [RaisesException, CallWith=ScriptState] Promise<BluetoothRemoteGATTCharacteristic> getCharacteristic(BluetoothCharacteristicUUID characteristic);
     [RaisesException, CallWith=ScriptState] Promise<sequence<BluetoothRemoteGATTCharacteristic>> getCharacteristics(optional BluetoothCharacteristicUUID characteristic);
-    // Promise<BluetoothRemoteGATTService>                  getIncludedService(BluetoothServiceUUID service);
-    // Promise<sequence<BluetoothRemoteGATTService>>        getIncludedServices(optional BluetoothServiceUUID service);
+    // Promise<BluetoothRemoteGATTService> getIncludedService(BluetoothServiceUUID service);
+    // Promise<sequence<BluetoothRemoteGATTService>> getIncludedServices(optional BluetoothServiceUUID service);
 };
diff --git a/third_party/WebKit/Source/modules/encryptedmedia/OWNERS b/third_party/WebKit/Source/modules/encryptedmedia/OWNERS
index 2cb8fc0..e2bfd8b 100644
--- a/third_party/WebKit/Source/modules/encryptedmedia/OWNERS
+++ b/third_party/WebKit/Source/modules/encryptedmedia/OWNERS
@@ -1,2 +1,4 @@
 ddorwin@chromium.org
 jrummell@chromium.org
+
+# COMPONENT: Internals>Media>Encrypted
diff --git a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
index 88d57545..970e2c1 100644
--- a/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
+++ b/third_party/WebKit/Source/modules/geolocation/Geolocation.cpp
@@ -31,6 +31,7 @@
 #include "core/frame/Deprecation.h"
 #include "core/frame/HostsUsingFeatures.h"
 #include "core/frame/Settings.h"
+#include "core/inspector/InspectorInstrumentation.h"
 #include "modules/geolocation/Coordinates.h"
 #include "modules/geolocation/GeolocationError.h"
 #include "modules/permissions/PermissionUtils.h"
@@ -167,6 +168,9 @@
   if (!frame())
     return;
 
+  InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
+      document(), "navigator.geolocation.getCurrentPosition", true, true);
+
   GeoNotifier* notifier =
       GeoNotifier::create(this, successCallback, errorCallback, options);
   startRequest(notifier);
@@ -180,6 +184,9 @@
   if (!frame())
     return 0;
 
+  InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
+      document(), "navigator.geolocation.watchPosition", true, true);
+
   GeoNotifier* notifier =
       GeoNotifier::create(this, successCallback, errorCallback, options);
   startRequest(notifier);
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValue.cpp b/third_party/WebKit/Source/modules/indexeddb/IDBValue.cpp
index 279a4eb..981c5d9a 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValue.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValue.cpp
@@ -4,6 +4,9 @@
 
 #include "modules/indexeddb/IDBValue.h"
 
+#include <v8.h>
+
+#include "bindings/core/v8/SerializedScriptValue.h"
 #include "platform/blob/BlobData.h"
 #include "public/platform/WebBlobInfo.h"
 #include "public/platform/modules/indexeddb/WebIDBValue.h"
@@ -15,6 +18,11 @@
 
 IDBValue::IDBValue(const WebIDBValue& value)
     : IDBValue(value.data, value.webBlobInfo, value.primaryKey, value.keyPath) {
+  m_externalAllocatedSize = m_data ? static_cast<int64_t>(m_data->size()) : 0l;
+  if (m_externalAllocatedSize) {
+    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
+        m_externalAllocatedSize);
+  }
 }
 
 IDBValue::IDBValue(PassRefPtr<SharedBuffer> data,
@@ -49,7 +57,12 @@
   }
 }
 
-IDBValue::~IDBValue() {}
+IDBValue::~IDBValue() {
+  if (m_externalAllocatedSize) {
+    v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(
+        -m_externalAllocatedSize);
+  }
+}
 
 PassRefPtr<IDBValue> IDBValue::create() {
   return adoptRef(new IDBValue());
@@ -73,8 +86,8 @@
   return uuids;
 }
 
-const SharedBuffer* IDBValue::data() const {
-  return m_data.get();
+RefPtr<SerializedScriptValue> IDBValue::createSerializedValue() const {
+  return SerializedScriptValue::create(m_data->data(), m_data->size());
 }
 
 bool IDBValue::isNull() const {
diff --git a/third_party/WebKit/Source/modules/indexeddb/IDBValue.h b/third_party/WebKit/Source/modules/indexeddb/IDBValue.h
index 7fccf56..e536cc8 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IDBValue.h
+++ b/third_party/WebKit/Source/modules/indexeddb/IDBValue.h
@@ -16,6 +16,7 @@
 namespace blink {
 
 class BlobDataHandle;
+class SerializedScriptValue;
 class WebBlobInfo;
 struct WebIDBValue;
 
@@ -30,7 +31,7 @@
 
   bool isNull() const;
   Vector<String> getUUIDs() const;
-  const SharedBuffer* data() const;
+  RefPtr<SerializedScriptValue> createSerializedValue() const;
   Vector<WebBlobInfo>* blobInfo() const { return m_blobInfo.get(); }
   const IDBKey* primaryKey() const { return m_primaryKey; }
   const IDBKeyPath& keyPath() const { return m_keyPath; }
@@ -44,11 +45,14 @@
            const IDBKeyPath&);
   IDBValue(const IDBValue*, IDBKey*, const IDBKeyPath&);
 
+  // Keep this private to prevent new refs because we manually bookkeep the
+  // memory to V8.
   const RefPtr<SharedBuffer> m_data;
   const std::unique_ptr<Vector<RefPtr<BlobDataHandle>>> m_blobData;
   const std::unique_ptr<Vector<WebBlobInfo>> m_blobInfo;
   const Persistent<IDBKey> m_primaryKey;
   const IDBKeyPath m_keyPath;
+  int64_t m_externalAllocatedSize = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/mediasource/OWNERS b/third_party/WebKit/Source/modules/mediasource/OWNERS
index 90a1e19..c881c58 100644
--- a/third_party/WebKit/Source/modules/mediasource/OWNERS
+++ b/third_party/WebKit/Source/modules/mediasource/OWNERS
@@ -1,2 +1,4 @@
 chcunningham@chromium.org
 wolenetz@chromium.org
+
+# COMPONENT: Internals>Media>Source
diff --git a/third_party/WebKit/Source/modules/notifications/Notification.cpp b/third_party/WebKit/Source/modules/notifications/Notification.cpp
index 41227ea..597041c3 100644
--- a/third_party/WebKit/Source/modules/notifications/Notification.cpp
+++ b/third_party/WebKit/Source/modules/notifications/Notification.cpp
@@ -43,6 +43,7 @@
 #include "core/events/Event.h"
 #include "core/frame/Deprecation.h"
 #include "core/frame/UseCounter.h"
+#include "core/inspector/InspectorInstrumentation.h"
 #include "modules/notifications/NotificationAction.h"
 #include "modules/notifications/NotificationData.h"
 #include "modules/notifications/NotificationManager.h"
@@ -365,6 +366,8 @@
     Deprecation::countDeprecation(
         context, UseCounter::NotificationPermissionRequestedInsecureOrigin);
   }
+  InspectorInstrumentation::NativeBreakpoint nativeBreakpoint(
+      context, "Notification.requestPermission", true, true);
   return NotificationManager::from(context)->requestPermission(
       scriptState, deprecatedCallback);
 }
diff --git a/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.cpp b/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.cpp
index 73160f0..ea09389 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.cpp
@@ -26,14 +26,16 @@
   if (!supplement) {
     supplement = new NavigatorServiceWorker(navigator);
     provideTo(navigator, supplementName(), supplement);
-    if (navigator.frame() &&
-        navigator.frame()
-            ->securityContext()
-            ->getSecurityOrigin()
-            ->canAccessServiceWorkers()) {
-      // Initialize ServiceWorkerContainer too.
-      supplement->serviceWorker(navigator.frame(), ASSERT_NO_EXCEPTION);
-    }
+  }
+  if (navigator.frame() &&
+      navigator.frame()
+          ->securityContext()
+          ->getSecurityOrigin()
+          ->canAccessServiceWorkers()) {
+    // Ensure ServiceWorkerContainer. It can be cleared regardless of
+    // |supplement|. See comments in NavigatorServiceWorker::serviceWorker() for
+    // details.
+    supplement->serviceWorker(navigator.frame(), ASSERT_NO_EXCEPTION);
   }
   return *supplement;
 }
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
index fc59875..0e35aeb 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.cpp
@@ -29,6 +29,8 @@
  */
 #include "modules/serviceworkers/ServiceWorkerContainer.h"
 
+#include <memory>
+#include <utility>
 #include "bindings/core/v8/CallbackPromiseAdapter.h"
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
@@ -42,6 +44,7 @@
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/MessagePort.h"
 #include "core/events/MessageEvent.h"
+#include "core/frame/Deprecation.h"
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/UseCounter.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
@@ -59,8 +62,6 @@
 #include "public/platform/modules/serviceworker/WebServiceWorkerProvider.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerRegistration.h"
 #include "wtf/PtrUtil.h"
-#include <memory>
-#include <utility>
 
 namespace blink {
 
@@ -458,6 +459,17 @@
       String() /* lastEventId */, source, String() /* suborigin */));
 }
 
+void ServiceWorkerContainer::countFeature(uint32_t feature) {
+  if (!getExecutionContext())
+    return;
+  UseCounter::Feature useCounterFeature =
+      static_cast<UseCounter::Feature>(feature);
+  if (Deprecation::deprecationMessage(useCounterFeature).isEmpty())
+    UseCounter::count(getExecutionContext(), useCounterFeature);
+  else
+    Deprecation::countDeprecation(getExecutionContext(), useCounterFeature);
+}
+
 const AtomicString& ServiceWorkerContainer::interfaceName() const {
   return EventTargetNames::ServiceWorkerContainer;
 }
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.h
index a6d39080..a99198a 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerContainer.h
@@ -93,6 +93,7 @@
   void dispatchMessageEvent(std::unique_ptr<WebServiceWorker::Handle>,
                             const WebString& message,
                             const WebMessagePortChannelArray&) override;
+  void countFeature(uint32_t feature) override;
 
   // EventTarget overrides.
   ExecutionContext* getExecutionContext() const override {
diff --git a/third_party/WebKit/Source/modules/vibration/VibrationController.h b/third_party/WebKit/Source/modules/vibration/VibrationController.h
index 462f64f..58b69c739 100644
--- a/third_party/WebKit/Source/modules/vibration/VibrationController.h
+++ b/third_party/WebKit/Source/modules/vibration/VibrationController.h
@@ -76,7 +76,7 @@
 
   // The VibrationManager mojo service. This is reset in |contextDestroyed|
   // and must not be called or recreated after it is reset.
-  device::blink::VibrationManagerPtr m_service;
+  device::mojom::blink::VibrationManagerPtr m_service;
 
   // Timer for calling |doVibrate| after a delay. It is safe to call
   // |startOneshot| when the timer is already running: it may affect the time
diff --git a/third_party/WebKit/Source/modules/webusb/USB.cpp b/third_party/WebKit/Source/modules/webusb/USB.cpp
index 005f929b..e497d4b 100644
--- a/third_party/WebKit/Source/modules/webusb/USB.cpp
+++ b/third_party/WebKit/Source/modules/webusb/USB.cpp
@@ -9,7 +9,6 @@
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
-#include "core/frame/UseCounter.h"
 #include "device/usb/public/interfaces/device.mojom-blink.h"
 #include "modules/EventTargetModules.h"
 #include "modules/webusb/USBConnectionEvent.h"
@@ -76,16 +75,13 @@
 }
 
 ScriptPromise USB::getDevices(ScriptState* scriptState) {
-  ExecutionContext* executionContext = scriptState->getExecutionContext();
-  UseCounter::count(executionContext, UseCounter::UsbGetDevices);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (!m_deviceManager) {
     resolver->reject(DOMException::create(NotSupportedError));
   } else {
     String errorMessage;
-    if (!executionContext->isSecureContext(errorMessage)) {
+    if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
       resolver->reject(DOMException::create(SecurityError, errorMessage));
     } else {
       m_deviceManagerRequests.insert(resolver);
@@ -101,7 +97,6 @@
 ScriptPromise USB::requestDevice(ScriptState* scriptState,
                                  const USBDeviceRequestOptions& options) {
   ExecutionContext* executionContext = scriptState->getExecutionContext();
-  UseCounter::count(executionContext, UseCounter::UsbRequestDevice);
 
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
diff --git a/third_party/WebKit/Source/modules/webusb/USB.idl b/third_party/WebKit/Source/modules/webusb/USB.idl
index 335a44d0..f4b5c35 100644
--- a/third_party/WebKit/Source/modules/webusb/USB.idl
+++ b/third_party/WebKit/Source/modules/webusb/USB.idl
@@ -10,6 +10,6 @@
 ] interface USB : EventTarget {
     attribute EventHandler onconnect;
     attribute EventHandler ondisconnect;
-    [CallWith=ScriptState] Promise<sequence<USBDevice>> getDevices();
-    [CallWith=ScriptState] Promise<sequence<USBDevice>> requestDevice(USBDeviceRequestOptions options);
+    [CallWith=ScriptState, MeasureAs=UsbGetDevices] Promise<sequence<USBDevice>> getDevices();
+    [CallWith=ScriptState, MeasureAs=UsbRequestDevice] Promise<sequence<USBDevice>> requestDevice(USBDeviceRequestOptions options);
 };
diff --git a/third_party/WebKit/Source/modules/webusb/USBDevice.cpp b/third_party/WebKit/Source/modules/webusb/USBDevice.cpp
index 7ae24bf..912390db 100644
--- a/third_party/WebKit/Source/modules/webusb/USBDevice.cpp
+++ b/third_party/WebKit/Source/modules/webusb/USBDevice.cpp
@@ -11,7 +11,6 @@
 #include "core/dom/DOMArrayBufferView.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/ExceptionCode.h"
-#include "core/frame/UseCounter.h"
 #include "modules/webusb/USBConfiguration.h"
 #include "modules/webusb/USBControlTransferParameters.h"
 #include "modules/webusb/USBInTransferResult.h"
@@ -144,9 +143,6 @@
 }
 
 ScriptPromise USBDevice::open(ScriptState* scriptState) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceOpen);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureNoDeviceOrInterfaceChangeInProgress(resolver)) {
@@ -164,9 +160,6 @@
 }
 
 ScriptPromise USBDevice::close(ScriptState* scriptState) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceClose);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureNoDeviceOrInterfaceChangeInProgress(resolver)) {
@@ -185,9 +178,6 @@
 
 ScriptPromise USBDevice::selectConfiguration(ScriptState* scriptState,
                                              uint8_t configurationValue) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceSelectConfiguration);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureNoDeviceOrInterfaceChangeInProgress(resolver)) {
@@ -218,9 +208,6 @@
 
 ScriptPromise USBDevice::claimInterface(ScriptState* scriptState,
                                         uint8_t interfaceNumber) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceClaimInterface);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureDeviceConfigured(resolver)) {
@@ -247,9 +234,6 @@
 
 ScriptPromise USBDevice::releaseInterface(ScriptState* scriptState,
                                           uint8_t interfaceNumber) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceReleaseInterface);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureDeviceConfigured(resolver)) {
@@ -283,9 +267,6 @@
 ScriptPromise USBDevice::selectAlternateInterface(ScriptState* scriptState,
                                                   uint8_t interfaceNumber,
                                                   uint8_t alternateSetting) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceSelectAlternateInterface);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureInterfaceClaimed(interfaceNumber, resolver)) {
@@ -318,9 +299,6 @@
     ScriptState* scriptState,
     const USBControlTransferParameters& setup,
     unsigned length) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceControlTransferIn);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureDeviceConfigured(resolver)) {
@@ -340,9 +318,6 @@
 ScriptPromise USBDevice::controlTransferOut(
     ScriptState* scriptState,
     const USBControlTransferParameters& setup) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceControlTransferOut);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureDeviceConfigured(resolver)) {
@@ -363,9 +338,6 @@
     ScriptState* scriptState,
     const USBControlTransferParameters& setup,
     const ArrayBufferOrArrayBufferView& data) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceControlTransferOut);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureDeviceConfigured(resolver)) {
@@ -387,9 +359,6 @@
 ScriptPromise USBDevice::clearHalt(ScriptState* scriptState,
                                    String direction,
                                    uint8_t endpointNumber) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceClearHalt);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureEndpointAvailable(direction == "in", endpointNumber, resolver)) {
@@ -405,9 +374,6 @@
 ScriptPromise USBDevice::transferIn(ScriptState* scriptState,
                                     uint8_t endpointNumber,
                                     unsigned length) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceTransferIn);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureEndpointAvailable(true /* in */, endpointNumber, resolver)) {
@@ -424,9 +390,6 @@
 ScriptPromise USBDevice::transferOut(ScriptState* scriptState,
                                      uint8_t endpointNumber,
                                      const ArrayBufferOrArrayBufferView& data) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceTransferOut);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureEndpointAvailable(false /* out */, endpointNumber, resolver)) {
@@ -445,9 +408,6 @@
 ScriptPromise USBDevice::isochronousTransferIn(ScriptState* scriptState,
                                                uint8_t endpointNumber,
                                                Vector<unsigned> packetLengths) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceIsochronousTransferIn);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureEndpointAvailable(true /* in */, endpointNumber, resolver)) {
@@ -466,9 +426,6 @@
     uint8_t endpointNumber,
     const ArrayBufferOrArrayBufferView& data,
     Vector<unsigned> packetLengths) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceIsochronousTransferOut);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureEndpointAvailable(false /* out */, endpointNumber, resolver)) {
@@ -483,9 +440,6 @@
 }
 
 ScriptPromise USBDevice::reset(ScriptState* scriptState) {
-  UseCounter::count(scriptState->getExecutionContext(),
-                    UseCounter::UsbDeviceReset);
-
   ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
   ScriptPromise promise = resolver->promise();
   if (ensureNoDeviceOrInterfaceChangeInProgress(resolver)) {
diff --git a/third_party/WebKit/Source/modules/webusb/USBDevice.idl b/third_party/WebKit/Source/modules/webusb/USBDevice.idl
index c689fad..a233bc0 100644
--- a/third_party/WebKit/Source/modules/webusb/USBDevice.idl
+++ b/third_party/WebKit/Source/modules/webusb/USBDevice.idl
@@ -33,18 +33,18 @@
     readonly attribute sequence<USBConfiguration> configurations;
     readonly attribute boolean opened;
 
-    [CallWith=ScriptState] Promise<void> open();
-    [CallWith=ScriptState] Promise<void> close();
-    [CallWith=ScriptState] Promise<void> selectConfiguration(octet configurationValue);
-    [CallWith=ScriptState] Promise<void> claimInterface(octet interfaceNumber);
-    [CallWith=ScriptState] Promise<void> releaseInterface(octet interfaceNumber);
-    [CallWith=ScriptState] Promise<void> selectAlternateInterface(octet interfaceNumber, octet alternateSetting);
-    [CallWith=ScriptState] Promise<USBInTransferResult> controlTransferIn(USBControlTransferParameters setup, unsigned short length);
-    [CallWith=ScriptState] Promise<USBOutTransferResult> controlTransferOut(USBControlTransferParameters setup, optional BufferSource data);
-    [CallWith=ScriptState] Promise<void> clearHalt(USBDirection direction, octet endpointNumber);
-    [CallWith=ScriptState] Promise<USBInTransferResult> transferIn(octet endpointNumber, unsigned long length);
-    [CallWith=ScriptState] Promise<USBOutTransferResult> transferOut(octet endpointNumber, BufferSource data);
-    [CallWith=ScriptState] Promise<USBIsochronousInTransferResult>  isochronousTransferIn(octet endpointNumber, sequence<unsigned long> packetLengths);
-    [CallWith=ScriptState] Promise<UsbIsochronousOutTransferResult> isochronousTransferOut(octet endpointNumber, BufferSource data, sequence<unsigned long> packetLengths);
-    [CallWith=ScriptState] Promise<void> reset();
+    [CallWith=ScriptState, MeasureAs=UsbDeviceOpen] Promise<void> open();
+    [CallWith=ScriptState, MeasureAs=UsbDeviceClose] Promise<void> close();
+    [CallWith=ScriptState, MeasureAs=UsbDeviceSelectConfiguration] Promise<void> selectConfiguration(octet configurationValue);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceClaimInterface] Promise<void> claimInterface(octet interfaceNumber);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceReleaseInterface] Promise<void> releaseInterface(octet interfaceNumber);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceSelectAlternateInterface] Promise<void> selectAlternateInterface(octet interfaceNumber, octet alternateSetting);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceControlTransferIn] Promise<USBInTransferResult> controlTransferIn(USBControlTransferParameters setup, unsigned short length);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceControlTransferOut] Promise<USBOutTransferResult> controlTransferOut(USBControlTransferParameters setup, optional BufferSource data);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceClearHalt] Promise<void> clearHalt(USBDirection direction, octet endpointNumber);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceTransferIn] Promise<USBInTransferResult> transferIn(octet endpointNumber, unsigned long length);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceTransferOut] Promise<USBOutTransferResult> transferOut(octet endpointNumber, BufferSource data);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceIsochronousTransferIn] Promise<USBIsochronousInTransferResult>  isochronousTransferIn(octet endpointNumber, sequence<unsigned long> packetLengths);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceIsochronousTransferOut] Promise<UsbIsochronousOutTransferResult> isochronousTransferOut(octet endpointNumber, BufferSource data, sequence<unsigned long> packetLengths);
+    [CallWith=ScriptState, MeasureAs=UsbDeviceReset] Promise<void> reset();
 };
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5 b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
index 46ae30a..5a0b9a2b 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.json5
@@ -498,8 +498,7 @@
     },
     {
       name: "LongTaskObserver",
-      origin_trial_feature_name: "LongTaskObserver",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "FractionalScrollOffsets",
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index d30ff02..eabefe4a 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -391,6 +391,11 @@
     state->postGC(gcType);
 }
 
+void ThreadHeap::preSweep(BlinkGC::GCType gcType) {
+  for (ThreadState* state : m_threads)
+    state->preSweep(gcType);
+}
+
 void ThreadHeap::processMarkingStack(Visitor* visitor) {
   // Ephemeron fixed point loop.
   do {
diff --git a/third_party/WebKit/Source/platform/heap/Heap.h b/third_party/WebKit/Source/platform/heap/Heap.h
index fde83bf8..3e0c6322 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.h
+++ b/third_party/WebKit/Source/platform/heap/Heap.h
@@ -425,6 +425,7 @@
 
   void preGC();
   void postGC(BlinkGC::GCType);
+  void preSweep(BlinkGC::GCType);
 
   // Conservatively checks whether an address is a pointer in any of the
   // thread heaps.  If so marks the object pointed to as live.
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index be23bc3d..7b08f91 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -283,7 +283,10 @@
     m_state->heap().preGC();
   }
 
-  ~TestGCScope() { m_state->heap().postGC(BlinkGC::GCWithSweep); }
+  ~TestGCScope() {
+    m_state->heap().postGC(BlinkGC::GCWithSweep);
+    m_state->heap().preSweep(BlinkGC::GCWithSweep);
+  }
 
  private:
   ThreadState* m_state;
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 27bb5d5..6b2c93f 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -953,7 +953,11 @@
   ASSERT(checkThread());
 
   threadLocalWeakProcessing();
+}
 
+void ThreadState::preSweep(BlinkGC::GCType gcType) {
+  if (gcState() == NoGCScheduled)
+    return;
   // We have to set the GCState to Sweeping before calling pre-finalizers
   // to disallow a GC during the pre-finalizers.
   setGCState(Sweeping);
@@ -1515,115 +1519,116 @@
   RELEASE_ASSERT(!isGCForbidden());
   completeSweep();
 
-  // Access to the CrossThreadPersistentRegion has to be prevented while
-  // in the stop-the-world phase. If not, threads not attached to Oilpan
-  // and participating in this GC are able to allocate & free PersistentNodes,
-  // something the marking phase isn't capable of handling.
-  CrossThreadPersistentRegion::LockScope persistentLock(
-      ProcessHeap::crossThreadPersistentRegion());
-
   GCForbiddenScope gcForbiddenScope(this);
 
   {
-    SafePointScope safePointScope(stackState, this);
-
-    std::unique_ptr<Visitor> visitor;
-    if (gcType == BlinkGC::TakeSnapshot) {
-      visitor = Visitor::create(this, Visitor::SnapshotMarking);
-    } else {
-      DCHECK(gcType == BlinkGC::GCWithSweep ||
-             gcType == BlinkGC::GCWithoutSweep);
-      if (heap().compaction()->shouldCompact(this, gcType, reason)) {
-        heap().compaction()->initialize(this);
-        visitor = Visitor::create(this, Visitor::GlobalMarkingWithCompaction);
-      } else {
-        visitor = Visitor::create(this, Visitor::GlobalMarking);
-      }
-    }
-
-    ScriptForbiddenIfMainThreadScope scriptForbidden;
-
-    TRACE_EVENT2("blink_gc,devtools.timeline", "BlinkGCMarking", "lazySweeping",
-                 gcType == BlinkGC::GCWithoutSweep, "gcReason",
-                 gcReasonString(reason));
-    double startTime = WTF::currentTimeMS();
-
-    if (gcType == BlinkGC::TakeSnapshot)
-      BlinkGCMemoryDumpProvider::instance()->clearProcessDumpForCurrentGC();
-
-    // Disallow allocation during garbage collection (but not during the
-    // finalization that happens when the visitorScope is torn down).
-    NoAllocationScope noAllocationScope(this);
-
-    heap().commitCallbackStacks();
-    heap().preGC();
-
-    StackFrameDepthScope stackDepthScope(&heap().stackFrameDepth());
-
-    size_t totalObjectSize = heap().heapStats().allocatedObjectSize() +
-                             heap().heapStats().markedObjectSize();
-    if (gcType != BlinkGC::TakeSnapshot)
-      heap().resetHeapCounters();
-
+    // Access to the CrossThreadPersistentRegion has to be prevented while in
+    // the marking phase because otherwise other threads may allocate or free
+    // PersistentNodes and we can't handle that.
+    CrossThreadPersistentRegion::LockScope persistentLock(
+        ProcessHeap::crossThreadPersistentRegion());
     {
-      // 1. Trace persistent roots.
-      heap().visitPersistentRoots(visitor.get());
+      SafePointScope safePointScope(stackState, this);
 
-      // 2. Trace objects reachable from the stack.  We do this independent of
-      // the
-      // given stackState since other threads might have a different stack
-      // state.
-      heap().visitStackRoots(visitor.get());
+      std::unique_ptr<Visitor> visitor;
+      if (gcType == BlinkGC::TakeSnapshot) {
+        visitor = Visitor::create(this, Visitor::SnapshotMarking);
+      } else {
+        DCHECK(gcType == BlinkGC::GCWithSweep ||
+               gcType == BlinkGC::GCWithoutSweep);
+        if (heap().compaction()->shouldCompact(this, gcType, reason)) {
+          heap().compaction()->initialize(this);
+          visitor = Visitor::create(this, Visitor::GlobalMarkingWithCompaction);
+        } else {
+          visitor = Visitor::create(this, Visitor::GlobalMarking);
+        }
+      }
 
-      // 3. Transitive closure to trace objects including ephemerons.
-      heap().processMarkingStack(visitor.get());
+      ScriptForbiddenIfMainThreadScope scriptForbidden;
 
-      heap().postMarkingProcessing(visitor.get());
-      heap().globalWeakProcessing(visitor.get());
-    }
+      TRACE_EVENT2("blink_gc,devtools.timeline", "BlinkGCMarking",
+                   "lazySweeping", gcType == BlinkGC::GCWithoutSweep,
+                   "gcReason", gcReasonString(reason));
+      double startTime = WTF::currentTimeMS();
 
-    double markingTimeInMilliseconds = WTF::currentTimeMS() - startTime;
-    heap().heapStats().setEstimatedMarkingTimePerByte(
-        totalObjectSize ? (markingTimeInMilliseconds / 1000 / totalObjectSize)
-                        : 0);
+      if (gcType == BlinkGC::TakeSnapshot)
+        BlinkGCMemoryDumpProvider::instance()->clearProcessDumpForCurrentGC();
+
+      // Disallow allocation during garbage collection (but not during the
+      // finalization that happens when the visitorScope is torn down).
+      NoAllocationScope noAllocationScope(this);
+
+      heap().commitCallbackStacks();
+      heap().preGC();
+
+      StackFrameDepthScope stackDepthScope(&heap().stackFrameDepth());
+
+      size_t totalObjectSize = heap().heapStats().allocatedObjectSize() +
+                               heap().heapStats().markedObjectSize();
+      if (gcType != BlinkGC::TakeSnapshot)
+        heap().resetHeapCounters();
+
+      {
+        // 1. Trace persistent roots.
+        heap().visitPersistentRoots(visitor.get());
+
+        // 2. Trace objects reachable from the stack.  We do this independent of
+        // the
+        // given stackState since other threads might have a different stack
+        // state.
+        heap().visitStackRoots(visitor.get());
+
+        // 3. Transitive closure to trace objects including ephemerons.
+        heap().processMarkingStack(visitor.get());
+
+        heap().postMarkingProcessing(visitor.get());
+        heap().globalWeakProcessing(visitor.get());
+      }
+
+      double markingTimeInMilliseconds = WTF::currentTimeMS() - startTime;
+      heap().heapStats().setEstimatedMarkingTimePerByte(
+          totalObjectSize ? (markingTimeInMilliseconds / 1000 / totalObjectSize)
+                          : 0);
 
 #if PRINT_HEAP_STATS
-    dataLogF(
-        "ThreadHeap::collectGarbage (gcReason=%s, lazySweeping=%d, "
-        "time=%.1lfms)\n",
-        gcReasonString(reason), gcType == BlinkGC::GCWithoutSweep,
-        markingTimeInMilliseconds);
+      dataLogF(
+          "ThreadHeap::collectGarbage (gcReason=%s, lazySweeping=%d, "
+          "time=%.1lfms)\n",
+          gcReasonString(reason), gcType == BlinkGC::GCWithoutSweep,
+          markingTimeInMilliseconds);
 #endif
 
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, markingTimeHistogram,
-        new CustomCountHistogram("BlinkGC.CollectGarbage", 0, 10 * 1000, 50));
-    markingTimeHistogram.count(markingTimeInMilliseconds);
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, totalObjectSpaceHistogram,
-        new CustomCountHistogram("BlinkGC.TotalObjectSpace", 0, 4 * 1024 * 1024,
-                                 50));
-    totalObjectSpaceHistogram.count(ProcessHeap::totalAllocatedObjectSize() /
-                                    1024);
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, totalAllocatedSpaceHistogram,
-        new CustomCountHistogram("BlinkGC.TotalAllocatedSpace", 0,
-                                 4 * 1024 * 1024, 50));
-    totalAllocatedSpaceHistogram.count(ProcessHeap::totalAllocatedSpace() /
-                                       1024);
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        EnumerationHistogram, gcReasonHistogram,
-        new EnumerationHistogram("BlinkGC.GCReason",
-                                 BlinkGC::LastGCReason + 1));
-    gcReasonHistogram.count(reason);
+      DEFINE_THREAD_SAFE_STATIC_LOCAL(
+          CustomCountHistogram, markingTimeHistogram,
+          new CustomCountHistogram("BlinkGC.CollectGarbage", 0, 10 * 1000, 50));
+      markingTimeHistogram.count(markingTimeInMilliseconds);
+      DEFINE_THREAD_SAFE_STATIC_LOCAL(
+          CustomCountHistogram, totalObjectSpaceHistogram,
+          new CustomCountHistogram("BlinkGC.TotalObjectSpace", 0,
+                                   4 * 1024 * 1024, 50));
+      totalObjectSpaceHistogram.count(ProcessHeap::totalAllocatedObjectSize() /
+                                      1024);
+      DEFINE_THREAD_SAFE_STATIC_LOCAL(
+          CustomCountHistogram, totalAllocatedSpaceHistogram,
+          new CustomCountHistogram("BlinkGC.TotalAllocatedSpace", 0,
+                                   4 * 1024 * 1024, 50));
+      totalAllocatedSpaceHistogram.count(ProcessHeap::totalAllocatedSpace() /
+                                         1024);
+      DEFINE_THREAD_SAFE_STATIC_LOCAL(
+          EnumerationHistogram, gcReasonHistogram,
+          new EnumerationHistogram("BlinkGC.GCReason",
+                                   BlinkGC::LastGCReason + 1));
+      gcReasonHistogram.count(reason);
 
-    heap().m_lastGCReason = reason;
+      heap().m_lastGCReason = reason;
 
-    ThreadHeap::reportMemoryUsageHistogram();
-    WTF::Partitions::reportMemoryUsageHistogram();
+      ThreadHeap::reportMemoryUsageHistogram();
+      WTF::Partitions::reportMemoryUsageHistogram();
+    }
+    heap().postGC(gcType);
   }
 
-  heap().postGC(gcType);
+  heap().preSweep(gcType);
   heap().decommitCallbackStacks();
 }
 
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index 74edd20a..d131fcf 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -226,8 +226,9 @@
   //
   // 1) preGC() is called.
   // 2) ThreadHeap::collectGarbage() is called. This marks live objects.
-  // 3) postGC() is called. This does thread-local weak processing,
-  //    pre-finalization, eager sweeping and heap compaction.
+  // 3) postGC() is called. This does thread-local weak processing.
+  // 4) preSweep() is called. This does pre-finalization, eager sweeping and
+  //    heap compaction.
   // 4) Lazy sweeping sweeps heaps incrementally. completeSweep() may be called
   //    to complete the sweeping.
   // 5) postSweep() is called.
@@ -241,6 +242,7 @@
   void preGC();
   void postGC(BlinkGC::GCType);
   void completeSweep();
+  void preSweep(BlinkGC::GCType);
   void postSweep();
   // makeConsistentForMutator() drops marks from marked objects and rebuild
   // free lists. This is called after taking a snapshot and before resuming
diff --git a/third_party/WebKit/Source/platform/image-decoders/OWNERS b/third_party/WebKit/Source/platform/image-decoders/OWNERS
index e67d035..9cf2710 100644
--- a/third_party/WebKit/Source/platform/image-decoders/OWNERS
+++ b/third_party/WebKit/Source/platform/image-decoders/OWNERS
@@ -2,3 +2,5 @@
 pkasting@chromium.org
 noel@chromium.org
 scroggo@chromium.org
+
+# COMPONENT: Internals>Images>Codecs
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index 5faa5e1..1e7b4e5c 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -14,6 +14,7 @@
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/output/begin_frame_args.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "platform/scheduler/base/real_time_domain.h"
 #include "platform/scheduler/base/task_queue_impl.h"
 #include "platform/scheduler/base/task_queue_selector.h"
@@ -49,6 +50,9 @@
     base::TimeDelta::FromSeconds(5);
 
 void ReportForegroundRendererTaskLoad(base::TimeTicks time, double load) {
+  if (!blink::RuntimeEnabledFeatures::timerThrottlingForBackgroundTabsEnabled())
+    return;
+
   int load_percentage = static_cast<int>(load * 100);
   UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.ForegroundRendererMainThreadLoad",
                            load_percentage);
@@ -57,6 +61,9 @@
 }
 
 void ReportBackgroundRendererTaskLoad(base::TimeTicks time, double load) {
+  if (!blink::RuntimeEnabledFeatures::timerThrottlingForBackgroundTabsEnabled())
+    return;
+
   int load_percentage = static_cast<int>(load * 100);
   UMA_HISTOGRAM_PERCENTAGE("RendererScheduler.BackgroundRendererMainThreadLoad",
                            load_percentage);
diff --git a/third_party/WebKit/Source/web/ExternalPopupMenu.cpp b/third_party/WebKit/Source/web/ExternalPopupMenu.cpp
index 3b1a991e..014ef226 100644
--- a/third_party/WebKit/Source/web/ExternalPopupMenu.cpp
+++ b/third_party/WebKit/Source/web/ExternalPopupMenu.cpp
@@ -30,7 +30,6 @@
 
 #include "web/ExternalPopupMenu.h"
 
-#include "core/dom/ExecutionContextTask.h"
 #include "core/dom/NodeComputedStyle.h"
 #include "core/dom/TaskRunnerHelper.h"
 #include "core/frame/FrameHost.h"
@@ -147,10 +146,10 @@
       if (m_needsUpdate)
         return;
       m_needsUpdate = true;
-      m_ownerElement->document().postTask(
-          TaskType::UserInteraction, BLINK_FROM_HERE,
-          createSameThreadTask(&ExternalPopupMenu::update,
-                               wrapPersistent(this)));
+      TaskRunnerHelper::get(TaskType::UserInteraction,
+                            &m_ownerElement->document())
+          ->postTask(BLINK_FROM_HERE, WTF::bind(&ExternalPopupMenu::update,
+                                                wrapPersistent(this)));
       break;
 
     case ByStyleChange:
diff --git a/third_party/WebKit/Source/web/FindInPageCoordinates.cpp b/third_party/WebKit/Source/web/FindInPageCoordinates.cpp
index 44421f9..c3e592e 100644
--- a/third_party/WebKit/Source/web/FindInPageCoordinates.cpp
+++ b/third_party/WebKit/Source/web/FindInPageCoordinates.cpp
@@ -95,7 +95,7 @@
   // Fixed positions do not make sense in this coordinate system, but need to
   // leave consistent tickmarks.  So, use their position when the view is not
   // scrolled, like an absolute position.
-  if (layoutObject->style()->position() == FixedPosition &&
+  if (layoutObject->style()->position() == EPosition::kFixed &&
       container->isLayoutView()) {
     normalizedRect.move(
         -toLayoutView(container)->frameView()->getScrollOffset());
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.cpp b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
index 97bf482..9d4a06a0 100644
--- a/third_party/WebKit/Source/web/PopupMenuImpl.cpp
+++ b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
@@ -7,7 +7,6 @@
 #include "core/HTMLNames.h"
 #include "core/css/CSSFontSelector.h"
 #include "core/dom/ElementTraversal.h"
-#include "core/dom/ExecutionContextTask.h"
 #include "core/dom/NodeComputedStyle.h"
 #include "core/dom/StyleEngine.h"
 #include "core/dom/TaskRunnerHelper.h"
@@ -503,9 +502,9 @@
   if (m_needsUpdate)
     return;
   m_needsUpdate = true;
-  ownerElement().document().postTask(
-      TaskType::UserInteraction, BLINK_FROM_HERE,
-      createSameThreadTask(&PopupMenuImpl::update, wrapPersistent(this)));
+  TaskRunnerHelper::get(TaskType::UserInteraction, &ownerElement().document())
+      ->postTask(BLINK_FROM_HERE,
+                 WTF::bind(&PopupMenuImpl::update, wrapPersistent(this)));
 }
 
 void PopupMenuImpl::update() {
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
index e22ac3b..3c2ac91d 100644
--- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
@@ -356,16 +356,16 @@
   return m_workerGlobalScope->hasEventListeners(EventTypeNames::fetch);
 }
 
-void ServiceWorkerGlobalScopeProxy::countFeature(UseCounter::Feature) {
-  // TODO(nhiroki): Support UseCounter for ServiceWorker. Send an IPC message to
-  // the browser process and ask each controlled document to record API use in
-  // its UseCoutner (https://crbug.com/376039).
+void ServiceWorkerGlobalScopeProxy::countFeature(UseCounter::Feature feature) {
+  client().countFeature(static_cast<uint32_t>(feature));
 }
 
-void ServiceWorkerGlobalScopeProxy::countDeprecation(UseCounter::Feature) {
-  // TODO(nhiroki): Support UseCounter for ServiceWorker. Send an IPC message to
-  // the browser process and ask each controlled document to record API use in
-  // its UseCoutner (https://crbug.com/376039).
+void ServiceWorkerGlobalScopeProxy::countDeprecation(
+    UseCounter::Feature feature) {
+  // Go through the same code path with countFeature() because a deprecation
+  // message is already shown on the worker console and a remaining work is just
+  // to record an API use.
+  countFeature(feature);
 }
 
 void ServiceWorkerGlobalScopeProxy::reportException(
diff --git a/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp b/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
index f2803c4..5cb230f 100644
--- a/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
+++ b/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
@@ -26,7 +26,8 @@
         .SetAvailableSize(NGLogicalSize(LayoutUnit(), LayoutUnit()))
         .SetPercentageResolutionSize(NGLogicalSize(LayoutUnit(), LayoutUnit()))
         .SetTextDirection(blockFlow->style()->direction())
-        .ToConstraintSpace();
+        .ToConstraintSpace(
+            FromPlatformWritingMode(blockFlow->style()->getWritingMode()));
   }
 };
 
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
index 3963284..87d0d515 100644
--- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -4292,4 +4292,53 @@
   EXPECT_EQ(800, vwElement->offsetWidth());
 }
 
+TEST_P(WebViewTest, DeviceEmulationResetScrollbars) {
+  WebViewImpl* webView = m_webViewHelper.initialize();
+  webView->resize(WebSize(800, 600));
+
+  WebURL baseURL = URLTestHelpers::toKURL("http://example.com/");
+  FrameTestHelpers::loadHTMLString(webView->mainFrame(),
+                                   "<!doctype html>"
+                                   "<meta name='viewport'"
+                                   "    content='width=device-width'>"
+                                   "<style>"
+                                   "  body {margin: 0px; height:3000px;}"
+                                   "</style>",
+                                   baseURL);
+
+  WebLocalFrameImpl* frame = webView->mainFrameImpl();
+  auto* frameView = frame->frameView();
+  EXPECT_FALSE(frameView->visualViewportSuppliesScrollbars());
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
+    EXPECT_NE(nullptr,
+              frameView->layoutViewportScrollableArea()->verticalScrollbar());
+  } else {
+    EXPECT_NE(nullptr, frameView->verticalScrollbar());
+  }
+
+  WebDeviceEmulationParams params;
+  params.screenPosition = WebDeviceEmulationParams::Mobile;
+  params.deviceScaleFactor = 0;
+  params.fitToView = false;
+  params.offset = WebFloatPoint();
+  params.scale = 1;
+
+  webView->enableDeviceEmulation(params);
+
+  // The visual viewport should now proivde the scrollbars instead of the view.
+  EXPECT_TRUE(frameView->visualViewportSuppliesScrollbars());
+  EXPECT_EQ(nullptr, frameView->verticalScrollbar());
+
+  webView->disableDeviceEmulation();
+
+  // The view should once again provide the scrollbars.
+  EXPECT_FALSE(frameView->visualViewportSuppliesScrollbars());
+  if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
+    EXPECT_NE(nullptr,
+              frameView->layoutViewportScrollableArea()->verticalScrollbar());
+  } else {
+    EXPECT_NE(nullptr, frameView->verticalScrollbar());
+  }
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/builder_list.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/builder_list.py
index 615768d..e7ecd10 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/builder_list.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/builder_list.py
@@ -40,9 +40,10 @@
     def __init__(self, builders_dict):
         """The given dictionary maps builder names to dicts with the keys:
             "port_name": A fully qualified port name.
-            "specifiers": TestExpectations specifiers for that config. Valid values are found in
-                  TestExpectationsParser._configuration_tokens_list. specifiers is a list whose
-                  first item is the version string and second item is the build type.
+            "specifiers": A two-item list: [version specifier, build type specifier].
+                Valid values for the version specifier can be found in
+                TestExpectationsParser._configuration_tokens_list, and valid
+                values for the build type specifier include "Release" and "Debug".
 
         Possible refactoring note: Potentially, it might make sense to use
         webkitpy.common.buildbot.Builder and add port_name and specifiers
@@ -63,20 +64,20 @@
         return sorted({b["port_name"] for b in self._builders.values()})
 
     def port_name_for_builder_name(self, builder_name):
-        return self._builders[builder_name]["port_name"]
+        return self._builders[builder_name]['port_name']
 
     def specifiers_for_builder(self, builder_name):
-        return self._builders[builder_name]["specifiers"]
+        return self._builders[builder_name]['specifiers']
 
     def builder_name_for_port_name(self, target_port_name):
         """Returns a builder name for the given port name.
 
         Multiple builders can have the same port name; this function only
         returns builder names for non-try-bot builders, and it gives preference
-        to non-debug builders.
+        to non-debug builders. If no builder is found, None is returned.
         """
         debug_builder_name = None
-        for builder_name, builder_info in self._builders.items():
+        for builder_name, builder_info in self._builders.iteritems():
             if builder_info.get('is_try_builder'):
                 continue
             if builder_info['port_name'] == target_port_name:
@@ -86,16 +87,30 @@
                     return builder_name
         return debug_builder_name
 
+    def version_specifier_for_port_name(self, target_port_name):
+        """Returns the OS version specifier for a given port name.
+
+        This just uses information in the builder list, and it returns
+        the version specifier for the first builder that matches, even
+        if it's a try bot builder.
+        """
+        for _, builder_info in sorted(self._builders.iteritems()):
+            if builder_info['port_name'] == target_port_name:
+                return builder_info['specifiers'][0]
+        return None
+
     def builder_name_for_specifiers(self, version, build_type):
         """Returns the builder name for a give version and build type.
 
         Args:
-            version: A string with the OS version specifier. e.g. "win7", "precise", "mac10.10".
-            build_type: A string with the build type. e.g. "debug" or "release".
+            version: A string with the OS version specifier. e.g. "Trusty", "Win10".
+            build_type: A string with the build type. e.g. "Debug" or "Release".
+
+        Returns:
+            The builder name if found, or an empty string if no match was found.
         """
         for builder_name, info in sorted(self._builders.items()):
             specifiers = info['specifiers']
             if specifiers[0].lower() == version.lower() and specifiers[1].lower() == build_type.lower():
                 return builder_name
-
         return ''
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/builder_list_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/builder_list_unittest.py
index c68a7fd..e704bde 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/builder_list_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/builder_list_unittest.py
@@ -45,47 +45,53 @@
         })
 
     def test_all_builder_names(self):
-        b = self.sample_builder_list()
-        self.assertEqual(['Blink A', 'Blink B', 'Blink B (dbg)', 'Blink C (dbg)', 'Try A', 'Try B'], b.all_builder_names())
+        builders = self.sample_builder_list()
+        self.assertEqual(['Blink A', 'Blink B', 'Blink B (dbg)', 'Blink C (dbg)', 'Try A', 'Try B'], builders.all_builder_names())
 
     def test_all_continuous_builder_names(self):
-        b = self.sample_builder_list()
-        self.assertEqual(['Blink A', 'Blink B', 'Blink B (dbg)', 'Blink C (dbg)'], b.all_continuous_builder_names())
+        builders = self.sample_builder_list()
+        self.assertEqual(['Blink A', 'Blink B', 'Blink B (dbg)', 'Blink C (dbg)'], builders.all_continuous_builder_names())
 
     def test_all_try_builder_names(self):
-        b = self.sample_builder_list()
-        self.assertEqual(['Try A', 'Try B'], b.all_try_builder_names())
+        builders = self.sample_builder_list()
+        self.assertEqual(['Try A', 'Try B'], builders.all_try_builder_names())
 
     def test_all_port_names(self):
-        b = self.sample_builder_list()
-        self.assertEqual(['port-a', 'port-b', 'port-c'], b.all_port_names())
+        builders = self.sample_builder_list()
+        self.assertEqual(['port-a', 'port-b', 'port-c'], builders.all_port_names())
 
     def test_port_name_for_builder_name(self):
-        b = self.sample_builder_list()
-        self.assertEqual('port-b', b.port_name_for_builder_name('Blink B'))
+        builders = self.sample_builder_list()
+        self.assertEqual('port-b', builders.port_name_for_builder_name('Blink B'))
 
     def test_specifiers_for_builder(self):
-        b = self.sample_builder_list()
-        self.assertEqual(['B', 'Release'], b.specifiers_for_builder('Blink B'))
+        builders = self.sample_builder_list()
+        self.assertEqual(['B', 'Release'], builders.specifiers_for_builder('Blink B'))
 
     def test_port_name_for_builder_name_with_missing_builder(self):
-        b = self.sample_builder_list()
+        builders = self.sample_builder_list()
         with self.assertRaises(KeyError):
-            b.port_name_for_builder_name('Blink_B')
+            builders.port_name_for_builder_name('Blink_B')
 
     def test_specifiers_for_builder_with_missing_builder(self):
-        b = self.sample_builder_list()
+        builders = self.sample_builder_list()
         with self.assertRaises(KeyError):
-            b.specifiers_for_builder('Blink_B')
+            builders.specifiers_for_builder('Blink_B')
 
     def test_builder_name_for_port_name_with_no_debug_builder(self):
-        b = self.sample_builder_list()
-        self.assertEqual('Blink A', b.builder_name_for_port_name('port-a'))
+        builders = self.sample_builder_list()
+        self.assertEqual('Blink A', builders.builder_name_for_port_name('port-a'))
 
     def test_builder_name_for_port_name_with_debug_builder(self):
-        b = self.sample_builder_list()
-        self.assertEqual('Blink B', b.builder_name_for_port_name('port-b'))
+        builders = self.sample_builder_list()
+        self.assertEqual('Blink B', builders.builder_name_for_port_name('port-b'))
 
     def test_builder_name_for_port_name_with_only_debug_builder(self):
-        b = self.sample_builder_list()
-        self.assertEqual('Blink C (dbg)', b.builder_name_for_port_name('port-c'))
+        builders = self.sample_builder_list()
+        self.assertEqual('Blink C (dbg)', builders.builder_name_for_port_name('port-c'))
+
+    def test_version_specifier_for_port_name(self):
+        builders = self.sample_builder_list()
+        self.assertEqual('A', builders.version_specifier_for_port_name('port-a'))
+        self.assertEqual('B', builders.version_specifier_for_port_name('port-b'))
+        self.assertIsNone(builders.version_specifier_for_port_name('port-x'))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/layout_test_finder.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/layout_test_finder.py
index c3802e7..963e857 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/layout_test_finder.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/layout_test_finder.py
@@ -29,6 +29,7 @@
 import errno
 import json
 import logging
+import math
 import re
 
 from webkitpy.layout_tests.layout_package.json_results_generator import convert_times_trie_to_flat_paths
@@ -176,60 +177,30 @@
         return tests_to_skip
 
     def split_into_chunks(self, test_names):
-        """split into a list to run and a set to skip, based on --run-chunk and --run-part."""
-        if not self._options.run_chunk and not self._options.run_part:
+        """split into a list to run and a set to skip, based on --shard_index and --total_shards."""
+        if self._options.shard_index is None and self._options.total_shards is None:
             return test_names, set()
 
-        # If the user specifies they just want to run a subset of the tests,
-        # just grab a subset of the non-skipped tests.
-        chunk_value = self._options.run_chunk or self._options.run_part
-        try:
-            (chunk_num, chunk_len) = chunk_value.split(":")
-            chunk_num = int(chunk_num)
-            assert chunk_num >= 0
-            test_size = int(chunk_len)
-            assert test_size > 0
-        except AssertionError:
-            _log.critical("invalid chunk '%s'", chunk_value)
-            return (None, None)
+        if self._options.shard_index is None:
+            raise ValueError('Must provide --shard-index or GTEST_SHARD_INDEX when sharding.')
+        if self._options.total_shards is None:
+            raise ValueError('Must provide --total-shards or GTEST_TOTAL_SHARDS when sharding.')
+        if self._options.shard_index >= self._options.total_shards:
+            raise ValueError('Shard index (%d) should be less than total shards (%d)!' % (
+                self._options.shard_index, self._options.total_shards))
 
-        # Get the number of tests
-        num_tests = len(test_names)
+        return self._split_into_chunks(test_names, self._options.shard_index, self._options.total_shards)
 
-        # Get the start offset of the slice.
-        if self._options.run_chunk:
-            chunk_len = test_size
-            # In this case chunk_num can be really large. We need
-            # to make the slave fit in the current number of tests.
-            slice_start = (chunk_num * chunk_len) % num_tests
-        else:
-            # Validate the data.
-            assert test_size <= num_tests
-            assert chunk_num <= test_size
+    @staticmethod
+    def _split_into_chunks(test_names, index, count):
+        chunk_size = int(math.ceil(len(test_names) * 1.0 / count))
 
-            # To count the chunk_len, and make sure we don't skip
-            # some tests, we round to the next value that fits exactly
-            # all the parts.
-            rounded_tests = num_tests
-            if rounded_tests % test_size != 0:
-                rounded_tests = (num_tests + test_size - (num_tests % test_size))
+        chunk_start = index * chunk_size
+        chunk_end = (index + 1) * chunk_size
 
-            chunk_len = rounded_tests / test_size
-            slice_start = chunk_len * (chunk_num - 1)
-            # It does not mind if we go over test_size.
+        tests_to_run = test_names[chunk_start:chunk_end]
+        other_tests = test_names[:chunk_start] + test_names[chunk_end:]
 
-        # Get the end offset of the slice.
-        slice_end = min(num_tests, slice_start + chunk_len)
+        _log.debug('chunk slice [%d:%d] of %d is %d tests', chunk_start, chunk_end, len(test_names), len(tests_to_run))
 
-        tests_to_run = test_names[slice_start:slice_end]
-
-        _log.debug('chunk slice [%d:%d] of %d is %d tests', slice_start, slice_end, num_tests, (slice_end - slice_start))
-
-        # If we reached the end and we don't have enough tests, we run some
-        # from the beginning.
-        if slice_end - slice_start < chunk_len:
-            extra = chunk_len - (slice_end - slice_start)
-            _log.debug('   last chunk is partial, appending [0:%d]', extra)
-            tests_to_run.extend(test_names[0:extra])
-
-        return (tests_to_run, set(test_names) - set(tests_to_run))
+        return tests_to_run, other_tests
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/layout_test_finder_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/layout_test_finder_unittest.py
index 25a37cd..85564d3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/layout_test_finder_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/layout_test_finder_unittest.py
@@ -85,3 +85,36 @@
 
         tests = finder.find_tests(fastest_percentile=90, args=[])
         self.assertEqual(set(tests[1]), set(['fast/css/1.html']))
+
+    def test_split_chunks(self):
+        split = layout_test_finder.LayoutTestFinder._split_into_chunks  # pylint: disable=protected-access
+
+        tests = [1, 2, 3, 4]
+        self.assertEqual(([1, 2, 3, 4], []), split(tests, 0, 1))
+
+        self.assertEqual(([1, 2], [3, 4]), split(tests, 0, 2))
+        self.assertEqual(([3, 4], [1, 2]), split(tests, 1, 2))
+
+        self.assertEqual(([1, 2], [3, 4]), split(tests, 0, 3))
+        self.assertEqual(([3, 4], [1, 2]), split(tests, 1, 3))
+        self.assertEqual(([], [1, 2, 3, 4]), split(tests, 2, 3))
+
+        tests = [1, 2, 3, 4, 5]
+        self.assertEqual(([1, 2, 3, 4, 5], []), split(tests, 0, 1))
+
+        self.assertEqual(([1, 2, 3], [4, 5]), split(tests, 0, 2))
+        self.assertEqual(([4, 5], [1, 2, 3]), split(tests, 1, 2))
+
+        self.assertEqual(([1, 2], [3, 4, 5]), split(tests, 0, 3))
+        self.assertEqual(([3, 4], [1, 2, 5]), split(tests, 1, 3))
+        self.assertEqual(([5], [1, 2, 3, 4]), split(tests, 2, 3))
+
+        tests = [1, 2, 3, 4, 5, 6]
+        self.assertEqual(([1, 2, 3, 4, 5, 6], []), split(tests, 0, 1))
+
+        self.assertEqual(([1, 2, 3], [4, 5, 6]), split(tests, 0, 2))
+        self.assertEqual(([4, 5, 6], [1, 2, 3]), split(tests, 1, 2))
+
+        self.assertEqual(([1, 2], [3, 4, 5, 6]), split(tests, 0, 3))
+        self.assertEqual(([3, 4], [1, 2, 5, 6]), split(tests, 1, 3))
+        self.assertEqual(([5, 6], [1, 2, 3, 4]), split(tests, 2, 3))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
index f27baddf..cfb9b06 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -931,6 +931,7 @@
         return tests_to_skip
 
     def _expectations_from_skipped_files(self, skipped_file_paths):
+        # TODO(qyearsley): Remove this if there are no more "Skipped" files.
         tests_to_skip = []
         for search_path in skipped_file_paths:
             filename = self._filesystem.join(self._absolute_baseline_path(search_path), "Skipped")
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
index 7298eac..b7e3197 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -36,6 +36,13 @@
 from webkitpy.layout_tests.port.driver import DeviceFailure, Driver, DriverOutput
 
 
+# Here we use a non-standard location for the layout tests, to ensure that
+# this works. The path contains a '.' in the name because we've seen bugs
+# related to this before.
+LAYOUT_TEST_DIR = '/test.checkout/LayoutTests'
+PERF_TEST_DIR = '/test.checkout/PerformanceTests'
+
+
 # This sets basic expectations for a test. Each individual expectation
 # can be overridden by a keyword argument in TestList.add().
 class TestInstance(object):
@@ -259,22 +266,14 @@
     return tests
 
 
-# Here we use a non-standard location for the layout tests, to ensure that
-# this works. The path contains a '.' in the name because we've seen bugs
-# related to this before.
-
-LAYOUT_TEST_DIR = '/test.checkout/LayoutTests'
-PERF_TEST_DIR = '/test.checkout/PerformanceTests'
-
-
 # Here we synthesize an in-memory filesystem from the test list
 # in order to fully control the test output and to demonstrate that
 # we don't need a real filesystem to run the tests.
 def add_unit_tests_to_mock_filesystem(filesystem):
     # Add the test_expectations file.
-    filesystem.maybe_make_directory('/mock-checkout/LayoutTests')
-    if not filesystem.exists('/mock-checkout/LayoutTests/TestExpectations'):
-        filesystem.write_text_file('/mock-checkout/LayoutTests/TestExpectations', """
+    filesystem.maybe_make_directory(LAYOUT_TEST_DIR)
+    if not filesystem.exists(LAYOUT_TEST_DIR + '/TestExpectations'):
+        filesystem.write_text_file(LAYOUT_TEST_DIR + '/TestExpectations', """
 Bug(test) failures/expected/crash.html [ Crash ]
 Bug(test) failures/expected/crash_then_text.html [ Failure ]
 Bug(test) failures/expected/image.html [ Failure ]
@@ -380,7 +379,7 @@
         # test ports. rebaseline_unittest.py needs to not mix both "real" ports
         # and "test" ports
 
-        self._generic_expectations_path = '/mock-checkout/LayoutTests/TestExpectations'
+        self._generic_expectations_path = LAYOUT_TEST_DIR + '/TestExpectations'
         self._results_directory = None
 
         self._operating_system = 'mac'
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
index fde33712..7e7bd00 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -362,12 +362,6 @@
                 help=("Number of times to retry failures, default is 3. Only relevant when "
                       "failure retries are enabled.")),
             optparse.make_option(
-                "--run-chunk",
-                help="Run a specified chunk (n:l), the nth of len l, of the layout tests"),
-            optparse.make_option(
-                "--run-part",
-                help="Run a specified part (n:m), the nth of m parts, of the layout tests"),
-            optparse.make_option(
                 "--total-shards",
                 type=int,
                 help=('Total number of shards being used for this test run. '
@@ -545,14 +539,10 @@
     if not options.skipped:
         options.skipped = 'default'
 
-    if not options.run_part:
-        if not options.total_shards and 'GTEST_TOTAL_SHARDS' in port.host.environ:
-            options.total_shards = int(port.host.environ['GTEST_TOTAL_SHARDS']) + 1
-        if not options.shard_index and 'GTEST_SHARD_INDEX' in port.host.environ:
-            options.shard_index = int(port.host.environ['GTEST_SHARD_INDEX'])
-        if options.shard_index is not None and options.total_shards is not None:
-            options.run_part = '%d:%d' % (int(options.shard_index) + 1,
-                                          int(options.total_shards))
+    if not options.total_shards and 'GTEST_TOTAL_SHARDS' in port.host.environ:
+        options.total_shards = int(port.host.environ['GTEST_TOTAL_SHARDS'])
+    if not options.shard_index and 'GTEST_SHARD_INDEX' in port.host.environ:
+        options.shard_index = int(port.host.environ['GTEST_SHARD_INDEX'])
 
     if not options.seed:
         options.seed = port.host.time()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
index 14ced71..c77218b 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -308,7 +308,7 @@
         self.assertContains(err, 'No tests to run.\n')
 
     def test_no_tests_found_3(self):
-        details, err, _ = logging_run(['--run-chunk', '5:400', 'foo/bar.html'], tests_included=True)
+        details, err, _ = logging_run(['--shard-index', '4', '--total-shards', '400', 'foo/bar.html'], tests_included=True)
         self.assertEqual(details.exit_code, test_run_results.NO_TESTS_EXIT_STATUS)
         self.assertContains(err, 'No tests to run.\n')
 
@@ -446,35 +446,11 @@
             tests_included=True, host=host)
         self.assertContains(err, "All 16 tests ran as expected (8 passed, 8 didn't).\n")
 
-    def test_run_chunk(self):
-        # Test that we wrap around if the number of tests is not evenly divisible by the chunk size
-        tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html']
-        chunk_tests_run = get_tests_run(['--run-chunk', '1:3', '--order', 'natural'] + tests_to_run)
-        self.assertEqual(['passes/text.html', 'passes/error.html', 'passes/image.html'], chunk_tests_run)
-
-    def test_run_part(self):
-        # Test that we actually select the right part
-        tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html']
-        tests_run = get_tests_run(['--run-part', '1:2', '--order', 'natural'] + tests_to_run)
-        self.assertEqual(['passes/error.html', 'passes/image.html'], tests_run)
-
-        # Test that we wrap around if the number of tests is not evenly divisible by the chunk size
-        # (here we end up with 3 parts, each with 2 tests, and we only have 4 tests total, so the
-        # last part repeats the first two tests).
-        chunk_tests_run = get_tests_run(['--order', 'natural', '--run-part', '3:3'] + tests_to_run)
-        self.assertEqual(['passes/error.html', 'passes/image.html'], chunk_tests_run)
-
     def test_run_singly(self):
         batch_tests_run = get_test_batches(['--run-singly'])
         for batch in batch_tests_run:
             self.assertEqual(len(batch), 1, '%s had too many tests' % ', '.join(batch))
 
-    def test_sharding(self):
-        # Test that we actually select the right part
-        tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html']
-        tests_run = get_tests_run(['--shard-index', '0', '--total-shards', '2', '--order', 'natural'] + tests_to_run)
-        self.assertEqual(tests_run, ['passes/error.html', 'passes/image.html'])
-
     def test_skip_failing_tests(self):
         # This tests that we skip both known failing and known flaky tests. Because there are
         # no known flaky tests in the default test_expectations, we add additional expectations.
@@ -526,17 +502,45 @@
         tests_run = get_tests_run(['--test-list=%s' % filename], host=host)
         self.assertEqual(['passes/text.html'], tests_run)
 
-    def test_gtest_shard_index(self):
+    def test_sharding_even(self):
+        # Test that we actually select the right part
+        tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html']
+        # Shard 0 of 2
+        tests_run = get_tests_run(['--shard-index', '0', '--total-shards', '2', '--order', 'natural'] + tests_to_run)
+        self.assertEqual(tests_run, ['passes/error.html', 'passes/image.html'])
+        # Shard 1 of 2
+        tests_run = get_tests_run(['--shard-index', '1', '--total-shards', '2', '--order', 'natural'] + tests_to_run)
+        self.assertEqual(tests_run, ['passes/platform_image.html', 'passes/text.html'])
+
+    def test_sharding_uneven(self):
+        tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html',
+                        'perf/foo/test.html']
+        # Shard 0 of 3
+        tests_run = get_tests_run(['--shard-index', '0', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
+        self.assertEqual(tests_run, ['passes/error.html', 'passes/image.html'])
+        # Shard 1 of 3
+        tests_run = get_tests_run(['--shard-index', '1', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
+        self.assertEqual(tests_run, ['passes/platform_image.html', 'passes/text.html'])
+        # Shard 2 of 3
+        tests_run = get_tests_run(['--shard-index', '2', '--total-shards', '3', '--order', 'natural'] + tests_to_run)
+        self.assertEqual(tests_run, ['perf/foo/test.html'])
+
+    def test_sharding_incorrect_arguments(self):
+        self.assertRaises(ValueError, get_tests_run, ['--shard-index', '3'])
+        self.assertRaises(ValueError, get_tests_run, ['--total-shards', '3'])
+        self.assertRaises(ValueError, get_tests_run, ['--shard-index', '3', '--total-shards', '3'])
+
+    def test_sharding_environ(self):
         tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html']
         host = MockHost()
 
         host.environ['GTEST_SHARD_INDEX'] = '0'
-        host.environ['GTEST_TOTAL_SHARDS'] = '1'
+        host.environ['GTEST_TOTAL_SHARDS'] = '2'
         shard_0_tests_run = get_tests_run(['--order', 'natural'] + tests_to_run, host=host)
         self.assertEqual(shard_0_tests_run, ['passes/error.html', 'passes/image.html'])
 
         host.environ['GTEST_SHARD_INDEX'] = '1'
-        host.environ['GTEST_TOTAL_SHARDS'] = '1'
+        host.environ['GTEST_TOTAL_SHARDS'] = '2'
         shard_1_tests_run = get_tests_run(['--order', 'natural'] + tests_to_run, host=host)
         self.assertEqual(shard_1_tests_run, ['passes/platform_image.html', 'passes/text.html'])
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py
index d60a56e..49fab77 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py
@@ -104,7 +104,7 @@
 
     def test_paths(self):
         self.run_test([],
-                      ('/mock-checkout/LayoutTests/TestExpectations\n'
+                      ('LayoutTests/TestExpectations\n'
                        'LayoutTests/NeverFixTests\n'
                        'LayoutTests/StaleTestExpectations\n'
                        'LayoutTests/SlowTests\n'),
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
index 18489e1a..3622121a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
@@ -13,10 +13,11 @@
 import copy
 import logging
 
+from webkitpy.common.memoized import memoized
 from webkitpy.common.net.git_cl import GitCL
 from webkitpy.common.net.rietveld import Rietveld
 from webkitpy.common.webkit_finder import WebKitFinder
-from webkitpy.layout_tests.models.test_expectations import TestExpectationLine
+from webkitpy.layout_tests.models.test_expectations import TestExpectationLine, TestExpectations
 from webkitpy.w3c.test_parser import TestParser
 
 _log = logging.getLogger(__name__)
@@ -73,6 +74,8 @@
 
     def get_try_bots(self):
         """Returns try bot names. Can be replaced in unit tests."""
+        # TODO(qyearsley): This method is unnecessary; unit tests can set up
+        # a BuilderList with try builder names, instead of overriding this.
         return self.host.builders.all_try_builder_names()
 
     def get_failing_results_dict(self, build):
@@ -128,17 +131,6 @@
             }
         return test_dict
 
-    def _port_name_to_platform_specifier(self, port_name):
-        """Maps a port name to the platform specifier used in expectation lines.
-
-        For example:
-            linux-trusty -> Trusty
-            mac-mac10.11 -> Mac10.11.
-        """
-        builder_name = self.host.builders.builder_name_for_port_name(port_name)
-        specifiers = self.host.builders.specifiers_for_builder(builder_name)
-        return specifiers[0]
-
     def merge_dicts(self, target, source, path=None):
         """Recursively merges nested dictionaries.
 
@@ -261,25 +253,96 @@
 
         Returns:
             A list of test expectations lines with the format:
-            ['BUG_URL [PLATFORM(S)] TEST_MAME [EXPECTATION(S)]']
+            ['BUG_URL [PLATFORM(S)] TEST_NAME [EXPECTATION(S)]']
         """
         line_list = []
         for test_name, port_results in merged_results.iteritems():
-            for port_names in port_results:
+            for port_names in sorted(port_results):
                 if test_name.startswith('external'):
-                    bug_part = port_results[port_names]['bug']
-                    specifier_part = '[ %s ]' % ' '.join(self.to_list(port_names))
-                    expectations_part = '[ %s ]' % ' '.join(self.get_expectations(port_results[port_names]))
-                    line = ' '.join([bug_part, specifier_part, test_name, expectations_part])
-                    line_list.append(line)
+                    line_parts = [port_results[port_names]['bug']]
+                    specifier_part = self.specifier_part(self.to_list(port_names), test_name)
+                    if specifier_part:
+                        line_parts.append(specifier_part)
+                    line_parts.append(test_name)
+                    line_parts.append('[ %s ]' % ' '.join(self.get_expectations(port_results[port_names])))
+                    line_list.append(' '.join(line_parts))
         return line_list
 
+    def specifier_part(self, port_names, test_name):
+        """Returns the specifier part for a new test expectations line.
+
+        Args:
+            port_names: A list of full port names that the line should apply to.
+            test_name: The test name for the expectation line.
+
+        Returns:
+            The specifier part of the new expectation line, e.g. "[ Mac ]".
+            This will be an empty string if the line should apply to all platforms.
+        """
+        specifiers = []
+        for name in sorted(port_names):
+            specifiers.append(self.host.builders.version_specifier_for_port_name(name))
+        port = self.host.port_factory.get()
+        specifiers = self.simplify_specifiers(specifiers, port.configuration_specifier_macros())
+        specifiers.extend(self.skipped_specifiers(test_name))
+        if not specifiers:
+            return ''
+        return '[ %s ]' % ' '.join(specifiers)
+
     @staticmethod
     def to_list(tuple_or_value):
+        """Converts a tuple to a list, and a string value to a one-item list."""
         if isinstance(tuple_or_value, tuple):
             return list(tuple_or_value)
         return [tuple_or_value]
 
+    def skipped_specifiers(self, test_name):
+        """Returns a list of platform specifiers for which the test is skipped."""
+        # TODO(qyearsley): Change Port.skips_test so that this can be simplified.
+        specifiers = []
+        for port in self.all_try_builder_ports():
+            generic_expectations = TestExpectations(port, tests=[test_name], include_overrides=False)
+            full_expectations = TestExpectations(port, tests=[test_name], include_overrides=True)
+            if port.skips_test(test_name, generic_expectations, full_expectations):
+                specifiers.append(self.host.builders.version_specifier_for_port_name(port.name()))
+        return specifiers
+
+    @memoized
+    def all_try_builder_ports(self):
+        """Returns a list of Port objects for all try builders."""
+        return [self.host.port_factory.get_from_builder_name(name) for name in self.get_try_bots()]
+
+    @staticmethod
+    def simplify_specifiers(specifiers, configuration_specifier_macros):  # pylint: disable=unused-argument
+        """Converts some collection of specifiers to an equivalent and maybe shorter list.
+
+        The input strings are all case-insensitive, but the strings in the
+        return value will all be capitalized.
+
+        Args:
+            specifiers: A collection of lower-case specifiers.
+            configuration_specifier_macros: A dict mapping "macros" for
+                groups of specifiers to lists of specific specifiers. In
+                practice, this is a dict mapping operating systems to
+                supported versions, e.g. {"win": ["win7", "win10"]}.
+
+        Returns:
+            A shortened list of specifiers. For example, ["win7", "win10"]
+            would be converted to ["Win"]. If the given list covers all
+            supported platforms, then an empty list is returned.
+            This list will be sorted and have capitalized specifier strings.
+        """
+        specifiers = {specifier.lower() for specifier in specifiers}
+        for macro_specifier, version_specifiers in configuration_specifier_macros.iteritems():
+            macro_specifier = macro_specifier.lower()
+            version_specifiers = {specifier.lower() for specifier in version_specifiers}
+            if version_specifiers.issubset(specifiers):
+                specifiers -= version_specifiers
+                specifiers.add(macro_specifier)
+        if specifiers == set(configuration_specifier_macros):
+            return []
+        return sorted(specifier.capitalize() for specifier in specifiers)
+
     def write_to_test_expectations(self, line_list):
         """Writes to TestExpectations.
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
index f1b5d039..02b754e 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
@@ -21,18 +21,37 @@
         super(WPTExpectationsUpdaterTest, self).setUp()
         host = MockHost()
         host.builders = BuilderList({
-            'MOCK Mac10.10': {'port_name': 'test-mac-mac10.10', 'specifiers': ['Mac10.10', 'Release']},
-            'MOCK Mac10.11': {'port_name': 'test-mac-mac10.11', 'specifiers': ['Mac10.11', 'Release']},
-            'MOCK Trusty': {'port_name': 'test-linux-trusty', 'specifiers': ['Trusty', 'Release']},
-            'MOCK Win10': {'port_name': 'test-win-win10', 'specifiers': ['Win10', 'Release']},
-            'MOCK Win7': {'port_name': 'test-win-win7', 'specifiers': ['Win7', 'Release']},
-            'MOCK Android': {'port_name': 'test-android', 'specifiers': ['Android', 'Release']},
+            'MOCK Try Mac10.10': {
+                'port_name': 'test-mac-mac10.10',
+                'specifiers': ['Mac10.10', 'Release'],
+                'is_try_builder': True,
+            },
+            'MOCK Try Mac10.11': {
+                'port_name': 'test-mac-mac10.11',
+                'specifiers': ['Mac10.11', 'Release'],
+                'is_try_builder': True,
+            },
+            'MOCK Try Trusty': {
+                'port_name': 'test-linux-trusty',
+                'specifiers': ['Trusty', 'Release'],
+                'is_try_builder': True,
+            },
+            'MOCK Try Win10': {
+                'port_name': 'test-win-win10',
+                'specifiers': ['Win10', 'Release'],
+                'is_try_builder': True,
+            },
+            'MOCK Try Win7': {
+                'port_name': 'test-win-win7',
+                'specifiers': ['Win7', 'Release'],
+                'is_try_builder': True,
+            },
         })
         return host
 
     def test_get_failing_results_dict_only_passing_results(self):
         host = self.mock_host()
-        host.buildbot.set_results(Build('MOCK Mac10.10', 123), LayoutTestResults({
+        host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({
             'tests': {
                 'x': {
                     'passing-test.html': {
@@ -43,18 +62,18 @@
             },
         }))
         updater = WPTExpectationsUpdater(host)
-        self.assertEqual(updater.get_failing_results_dict(Build('MOCK Mac10.10', 123)), {})
+        self.assertEqual(updater.get_failing_results_dict(Build('MOCK Try Mac10.10', 123)), {})
 
     def test_get_failing_results_dict_no_results(self):
         host = self.mock_host()
         host.buildbot = MockBuildBot()
-        host.buildbot.set_results(Build('MOCK Mac10.10', 123), None)
+        host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), None)
         updater = WPTExpectationsUpdater(host)
-        self.assertEqual(updater.get_failing_results_dict(Build('MOCK Mac10.10', 123)), {})
+        self.assertEqual(updater.get_failing_results_dict(Build('MOCK Try Mac10.10', 123)), {})
 
     def test_get_failing_results_dict_some_failing_results(self):
         host = self.mock_host()
-        host.buildbot.set_results(Build('MOCK Mac10.10', 123), LayoutTestResults({
+        host.buildbot.set_results(Build('MOCK Try Mac10.10', 123), LayoutTestResults({
             'tests': {
                 'x': {
                     'failing-test.html': {
@@ -66,7 +85,7 @@
             },
         }))
         updater = WPTExpectationsUpdater(host)
-        results_dict = updater.get_failing_results_dict(Build('MOCK Mac10.10', 123))
+        results_dict = updater.get_failing_results_dict(Build('MOCK Try Mac10.10', 123))
         self.assertEqual(
             results_dict,
             {
@@ -135,19 +154,43 @@
         updater = WPTExpectationsUpdater(self.mock_host())
         results = {
             'external/fake/test/path.html': {
-                'one': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
-                'two': {'expected': 'FAIL', 'actual': 'TIMEOUT', 'bug': 'crbug.com/test'},
-                'three': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
+                'test-linux-trusty': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
+                'test-mac-mac10.10': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
+                'test-mac-mac10.11': {'expected': 'FAIL', 'actual': 'TIMEOUT', 'bug': 'crbug.com/test'},
             }
         }
         self.assertEqual(
             updater.create_line_list(results),
             [
-                'crbug.com/test [ three ] external/fake/test/path.html [ Pass ]',
-                'crbug.com/test [ two ] external/fake/test/path.html [ Timeout ]',
-                'crbug.com/test [ one ] external/fake/test/path.html [ Pass ]',
+                'crbug.com/test [ Linux ] external/fake/test/path.html [ Pass ]',
+                'crbug.com/test [ Mac10.10 ] external/fake/test/path.html [ Pass ]',
+                'crbug.com/test [ Mac10.11 ] external/fake/test/path.html [ Timeout ]',
             ])
 
+    def test_specifier_part(self):
+        updater = WPTExpectationsUpdater(self.mock_host())
+        self.assertEqual(updater.specifier_part(['test-mac-mac10.10'], 'x/y.html'), '[ Mac10.10 ]')
+
+    def test_skipped_specifiers_when_test_is_wontfix(self):
+        host = self.mock_host()
+        expectations_path = '/test.checkout/LayoutTests/NeverFixTests'
+        host.filesystem.files[expectations_path] = 'crbug.com/111 [ Trusty ] external/wpt/test.html [ WontFix ]\n'
+        host.filesystem.files['/test.checkout/LayoutTests/external/wpt/test.html'] = ''
+        updater = WPTExpectationsUpdater(host)
+        self.assertEqual(updater.skipped_specifiers('external/wpt/test.html'), ['Trusty'])
+
+    def test_simplify_specifiers(self):
+        macros = {
+            'mac': ['Mac10.10', 'mac10.11'],
+            'win': ['Win7', 'win10'],
+            'linux': ['Trusty'],
+        }
+        self.assertEqual(WPTExpectationsUpdater.simplify_specifiers(['mac10.10', 'mac10.11'], macros), ['Mac'])
+        self.assertEqual(WPTExpectationsUpdater.simplify_specifiers(['Mac10.10', 'Mac10.11', 'Trusty'], macros), ['Linux', 'Mac'])
+        self.assertEqual(
+            WPTExpectationsUpdater.simplify_specifiers(['Mac10.10', 'Mac10.11', 'Trusty', 'Win7', 'Win10'], macros), [])
+        self.assertEqual(WPTExpectationsUpdater.simplify_specifiers(['a', 'b', 'c'], {}), ['A', 'B', 'C'])
+
     def test_merge_dicts_with_conflict_raise_exception(self):
         updater = WPTExpectationsUpdater(self.mock_host())
         # Both dicts here have the key "one", and the value is not equal.
@@ -218,27 +261,27 @@
         expectations_path = '/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'
         host.filesystem.files[expectations_path] = MARKER_COMMENT + '\n'
         updater = WPTExpectationsUpdater(host)
-        line_list = ['crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]']
+        line_list = ['crbug.com/123 [ Trusty ] fake/file/path.html [ Pass ]']
         updater.write_to_test_expectations(line_list)
         value = updater.host.filesystem.read_text_file(expectations_path)
         self.assertMultiLineEqual(
             value,
             (MARKER_COMMENT + '\n'
-             'crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]\n'))
+             'crbug.com/123 [ Trusty ] fake/file/path.html [ Pass ]\n'))
 
     def test_write_to_test_expectations_with_no_marker_comment(self):
         host = self.mock_host()
         expectations_path = '/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'
-        host.filesystem.files[expectations_path] = 'crbug.com/111 [ FakePlatform ]\n'
+        host.filesystem.files[expectations_path] = 'crbug.com/111 [ Trusty ]\n'
         updater = WPTExpectationsUpdater(host)
-        line_list = ['crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]']
+        line_list = ['crbug.com/123 [ Trusty ] fake/file/path.html [ Pass ]']
         updater.write_to_test_expectations(line_list)
         value = host.filesystem.read_text_file(expectations_path)
         self.assertMultiLineEqual(
             value,
-            ('crbug.com/111 [ FakePlatform ]\n'
+            ('crbug.com/111 [ Trusty ]\n'
              '\n' + MARKER_COMMENT + '\n'
-             'crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]'))
+             'crbug.com/123 [ Trusty ] fake/file/path.html [ Pass ]'))
 
     def test_write_to_test_expectations_skips_existing_lines(self):
         host = self.mock_host()
@@ -262,14 +305,14 @@
         expectations_path = '/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'
         host.filesystem.files[expectations_path] = (
             MARKER_COMMENT + '\n'
-            'crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]\n')
+            'crbug.com/123 [ Trusty ] fake/file/path.html [ Pass ]\n')
         updater = WPTExpectationsUpdater(host)
         updater.write_to_test_expectations([])
         value = updater.host.filesystem.read_text_file(expectations_path)
         self.assertMultiLineEqual(
             value,
             (MARKER_COMMENT + '\n'
-             'crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]\n'))
+             'crbug.com/123 [ Trusty ] fake/file/path.html [ Pass ]\n'))
 
     def test_is_js_test_true(self):
         host = self.mock_host()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
index c5ab1ff..4412018 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
@@ -22,7 +22,7 @@
         assert self.user and self.token
 
     def auth_token(self):
-        return base64.encodestring('{}:{}'.format(self.user, self.token)).strip()
+        return base64.b64encode('{}:{}'.format(self.user, self.token))
 
     def request(self, path, method, body=None):
         assert path.startswith('/')
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index f47f59d..f82a3555 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -756,7 +756,6 @@
   visibility = [ ":*" ]
   sources = [
     "web/ConsoleMessageStructTraits.cpp",
-    "web/WindowFeaturesStructTraits.cpp",
   ]
   deps = [
     ":mojo_bindings_shared__generator",
diff --git a/third_party/WebKit/public/platform/WebCoalescedInputEvent.h b/third_party/WebKit/public/platform/WebCoalescedInputEvent.h
index 3234c2b..d0c9006f 100644
--- a/third_party/WebKit/public/platform/WebCoalescedInputEvent.h
+++ b/third_party/WebKit/public/platform/WebCoalescedInputEvent.h
@@ -29,7 +29,9 @@
   std::vector<const WebInputEvent*> getCoalescedEventsPointers() const;
 
  private:
-  struct WebInputEventDeleter {
+  // TODO(hans): Remove this once clang-cl knows to not inline dtors that
+  // call operator(), https://crbug.com/691714
+  struct BLINK_PLATFORM_EXPORT WebInputEventDeleter {
     void operator()(blink::WebInputEvent*) const;
   };
 
diff --git a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerProviderClient.h b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerProviderClient.h
index 28682cc..2b129cd 100644
--- a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerProviderClient.h
+++ b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerProviderClient.h
@@ -55,6 +55,8 @@
       std::unique_ptr<WebServiceWorker::Handle>,
       const WebString& message,
       const WebMessagePortChannelArray& channels) = 0;
+
+  virtual void countFeature(uint32_t feature) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/public_typemaps.gni b/third_party/WebKit/public/public_typemaps.gni
index 71de4f0..b727b1be 100644
--- a/third_party/WebKit/public/public_typemaps.gni
+++ b/third_party/WebKit/public/public_typemaps.gni
@@ -7,5 +7,4 @@
   "//third_party/WebKit/public/platform/referrer_policy.typemap",
   "//third_party/WebKit/public/platform/modules/screen_orientation/screen_orientation_lock_types.typemap",
   "//third_party/WebKit/public/web/console_message.typemap",
-  "//third_party/WebKit/public/web/window_features.typemap",
 ]
diff --git a/third_party/WebKit/public/web/WindowFeaturesStructTraits.cpp b/third_party/WebKit/public/web/WindowFeaturesStructTraits.cpp
deleted file mode 100644
index 69dce5b..0000000
--- a/third_party/WebKit/public/web/WindowFeaturesStructTraits.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/WebKit/public/web/WindowFeaturesStructTraits.h"
-
-namespace mojo {
-
-// static
-bool StructTraits<::blink::mojom::WindowFeaturesDataView,
-                  ::blink::WebWindowFeatures>::
-    Read(::blink::mojom::WindowFeaturesDataView data,
-         ::blink::WebWindowFeatures* out) {
-  out->x = data.x();
-  out->xSet = data.has_x();
-  out->y = data.y();
-  out->ySet = data.has_y();
-  out->width = data.width();
-  out->widthSet = data.has_width();
-  out->height = data.height();
-  out->heightSet = data.has_height();
-  out->menuBarVisible = data.menu_bar_visible();
-  out->statusBarVisible = data.status_bar_visible();
-  out->toolBarVisible = data.tool_bar_visible();
-  out->locationBarVisible = data.location_bar_visible();
-  out->scrollbarsVisible = data.scrollbars_visible();
-  out->resizable = data.resizable();
-  out->fullscreen = data.fullscreen();
-  out->dialog = data.dialog();
-  return true;
-}
-
-}  // namespace mojo
diff --git a/third_party/WebKit/public/web/WindowFeaturesStructTraits.h b/third_party/WebKit/public/web/WindowFeaturesStructTraits.h
deleted file mode 100644
index ca776ed..0000000
--- a/third_party/WebKit/public/web/WindowFeaturesStructTraits.h
+++ /dev/null
@@ -1,74 +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 WindowFeaturesStructTraits_h
-#define WindowFeaturesStructTraits_h
-
-#include "WebWindowFeatures.h"
-#include "mojo/public/cpp/bindings/struct_traits.h"
-#include "third_party/WebKit/public/web/window_features.mojom-shared.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<::blink::mojom::WindowFeaturesDataView,
-                    ::blink::WebWindowFeatures> {
-  static float x(const ::blink::WebWindowFeatures& features) {
-    return features.x;
-  }
-  static bool has_x(const ::blink::WebWindowFeatures& features) {
-    return features.xSet;
-  }
-  static float y(const ::blink::WebWindowFeatures& features) {
-    return features.y;
-  }
-  static bool has_y(const ::blink::WebWindowFeatures& features) {
-    return features.ySet;
-  }
-  static float width(const ::blink::WebWindowFeatures& features) {
-    return features.width;
-  }
-  static bool has_width(const ::blink::WebWindowFeatures& features) {
-    return features.widthSet;
-  }
-  static float height(const ::blink::WebWindowFeatures& features) {
-    return features.height;
-  }
-  static bool has_height(const ::blink::WebWindowFeatures& features) {
-    return features.heightSet;
-  }
-
-  static bool menu_bar_visible(const ::blink::WebWindowFeatures& features) {
-    return features.menuBarVisible;
-  }
-  static bool status_bar_visible(const ::blink::WebWindowFeatures& features) {
-    return features.statusBarVisible;
-  }
-  static bool tool_bar_visible(const ::blink::WebWindowFeatures& features) {
-    return features.toolBarVisible;
-  }
-  static bool location_bar_visible(const ::blink::WebWindowFeatures& features) {
-    return features.locationBarVisible;
-  }
-  static bool scrollbars_visible(const ::blink::WebWindowFeatures& features) {
-    return features.scrollbarsVisible;
-  }
-  static bool resizable(const ::blink::WebWindowFeatures& features) {
-    return features.resizable;
-  }
-
-  static bool fullscreen(const ::blink::WebWindowFeatures& features) {
-    return features.fullscreen;
-  }
-  static bool dialog(const ::blink::WebWindowFeatures& features) {
-    return features.dialog;
-  }
-
-  static bool Read(::blink::mojom::WindowFeaturesDataView,
-                   ::blink::WebWindowFeatures* out);
-};
-
-}  // namespace mojo
-
-#endif
diff --git a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
index 99ba37f..e06bd92 100644
--- a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
+++ b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
@@ -100,6 +100,10 @@
   // Called when the worker context is initialized.
   virtual void didInitializeWorkerContext(v8::Local<v8::Context> context) {}
 
+  // Called when some API to be recorded in UseCounter is called on the worker
+  // global scope.
+  virtual void countFeature(uint32_t feature) {}
+
   // Called when the WorkerGlobalScope had an error or an exception.
   virtual void reportException(const WebString& errorMessage,
                                int lineNumber,
diff --git a/third_party/WebKit/public/web/window_features.typemap b/third_party/WebKit/public/web/window_features.typemap
deleted file mode 100644
index 6bc6941..0000000
--- a/third_party/WebKit/public/web/window_features.typemap
+++ /dev/null
@@ -1,12 +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.
-
-mojom = "//third_party/WebKit/public/web/window_features.mojom"
-public_headers = [ "//third_party/WebKit/public/web/WebWindowFeatures.h" ]
-traits_headers =
-    [ "//third_party/WebKit/public/web/WindowFeaturesStructTraits.h" ]
-deps = [
-  "//third_party/WebKit/public:shared_typemap_traits",
-]
-type_mappings = [ "blink.mojom.WindowFeatures=::blink::WebWindowFeatures" ]
diff --git a/third_party/binutils/OWNERS b/third_party/binutils/OWNERS
index 41edd86..9ff8e32 100644
--- a/third_party/binutils/OWNERS
+++ b/third_party/binutils/OWNERS
@@ -1,3 +1,3 @@
 thakis@chromium.org
 thestig@chromium.org
-mithro@mithis.com
+tansell@chromium.org
diff --git a/third_party/libjingle_xmpp/xmllite/xmlbuilder.cc b/third_party/libjingle_xmpp/xmllite/xmlbuilder.cc
index 68ef3d5a..4ad5331 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlbuilder.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlbuilder.cc
@@ -14,7 +14,6 @@
 #include <vector>
 #include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-#include "third_party/webrtc/base/common.h"
 
 namespace buzz {
 
@@ -90,8 +89,6 @@
 
 void
 XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) {
-  RTC_UNUSED(pctx);
-  RTC_UNUSED(name);
   pelCurrent_ = pvParents_->back();
   pvParents_->pop_back();
 }
@@ -99,7 +96,6 @@
 void
 XmlBuilder::CharacterData(XmlParseContext * pctx,
                                const char * text, int len) {
-  RTC_UNUSED(pctx);
   if (pelCurrent_) {
     pelCurrent_->AddParsedText(text, len);
   }
@@ -107,8 +103,6 @@
 
 void
 XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) {
-  RTC_UNUSED(pctx);
-  RTC_UNUSED(err);
   pelRoot_.reset(NULL);
   pelCurrent_ = NULL;
   pvParents_->clear();
diff --git a/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc
index 0a6f606..2d5d0f2 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlbuilder_unittest.cc
@@ -14,7 +14,6 @@
 #include "third_party/libjingle_xmpp/xmllite/xmlbuilder.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
-#include "third_party/webrtc/base/common.h"
 #include "third_party/webrtc/base/gunit.h"
 
 using buzz::XmlBuilder;
@@ -174,4 +173,3 @@
       "</testing>");
   EXPECT_TRUE(NULL == builder.BuiltElement());
 }
-
diff --git a/third_party/libjingle_xmpp/xmllite/xmlelement.cc b/third_party/libjingle_xmpp/xmllite/xmlelement.cc
index 0ef5841..6cdb920e 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlelement.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlelement.cc
@@ -20,7 +20,7 @@
 #include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlprinter.h"
-#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/checks.h"
 
 namespace buzz {
 
@@ -358,7 +358,7 @@
 }
 
 void XmlElement::AddAttr(const QName& name, const std::string& value) {
-  ASSERT(!HasAttr(name));
+  RTC_DCHECK(!HasAttr(name));
 
   XmlAttr ** pprev = last_attr_ ? &(last_attr_->next_attr_) : &first_attr_;
   last_attr_ = (*pprev = new XmlAttr(name, value));
diff --git a/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc
index f54ae95..c74c236 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlelement_unittest.cc
@@ -12,7 +12,6 @@
 #include <sstream>
 #include <string>
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
-#include "third_party/webrtc/base/common.h"
 #include "third_party/webrtc/base/gunit.h"
 #include "third_party/webrtc/base/thread.h"
 
diff --git a/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc
index 19372a6..5a0e6a2a 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlnsstack_unittest.cc
@@ -15,7 +15,6 @@
 #include <string>
 
 #include "third_party/libjingle_xmpp/xmllite/xmlconstants.h"
-#include "third_party/webrtc/base/common.h"
 #include "third_party/webrtc/base/gunit.h"
 
 using buzz::NS_XML;
diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser.cc b/third_party/libjingle_xmpp/xmllite/xmlparser.cc
index 1f8153f..2f1d9ae 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlparser.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlparser.cc
@@ -17,7 +17,6 @@
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
-#include "third_party/webrtc/base/common.h"
 
 namespace buzz {
 
diff --git a/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc
index a0a6101..1d1e9ca4 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlparser_unittest.cc
@@ -13,7 +13,6 @@
 #include <string>
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlparser.h"
-#include "third_party/webrtc/base/common.h"
 #include "third_party/webrtc/base/gunit.h"
 
 using buzz::QName;
@@ -34,17 +33,13 @@
     ss_ << ") ";
   }
   virtual void EndElement(XmlParseContext * pctx, const char * name) {
-    RTC_UNUSED(pctx);
-    RTC_UNUSED(name);
     ss_ << "END ";
   }
   virtual void CharacterData(XmlParseContext * pctx,
                              const char * text, int len) {
-    RTC_UNUSED(pctx);
     ss_ << "TEXT (" << std::string(text, len) << ") ";
   }
   virtual void Error(XmlParseContext * pctx, XML_Error code) {
-    RTC_UNUSED(pctx);
     ss_ << "ERROR (" << static_cast<int>(code) << ") ";
   }
   virtual ~XmlParserTestHandler() {
diff --git a/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc b/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc
index f40491d0..5b52731c 100644
--- a/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc
+++ b/third_party/libjingle_xmpp/xmllite/xmlprinter_unittest.cc
@@ -16,7 +16,6 @@
 #include "third_party/libjingle_xmpp/xmllite/qname.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmllite/xmlnsstack.h"
-#include "third_party/webrtc/base/common.h"
 #include "third_party/webrtc/base/gunit.h"
 
 using buzz::QName;
diff --git a/third_party/libjingle_xmpp/xmpp/jid.cc b/third_party/libjingle_xmpp/xmpp/jid.cc
index 53f7f8a..032ce03 100644
--- a/third_party/libjingle_xmpp/xmpp/jid.cc
+++ b/third_party/libjingle_xmpp/xmpp/jid.cc
@@ -16,7 +16,7 @@
 #include <string>
 
 #include "third_party/libjingle_xmpp/xmpp/constants.h"
-#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/checks.h"
 #include "third_party/webrtc_overrides/webrtc/base/logging.h"
 
 namespace buzz {
@@ -85,7 +85,7 @@
   if (!node_name_.empty())
     ret = node_name_ + "@";
 
-  ASSERT(domain_name_ != STR_EMPTY);
+  RTC_DCHECK(domain_name_ != STR_EMPTY);
   ret += domain_name_;
 
   if (!resource_name_.empty())
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc
index 93c8189..5b9ff96 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmppengine_unittest.cc
@@ -19,7 +19,6 @@
 #include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
 #include "third_party/libjingle_xmpp/xmpp/util_unittest.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
-#include "third_party/webrtc/base/common.h"
 #include "third_party/webrtc/base/gunit.h"
 
 using buzz::Jid;
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengineimpl.cc b/third_party/libjingle_xmpp/xmpp/xmppengineimpl.cc
index 8ba57a64..882bf36 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppengineimpl.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmppengineimpl.cc
@@ -19,7 +19,7 @@
 #include "third_party/libjingle_xmpp/xmpp/constants.h"
 #include "third_party/libjingle_xmpp/xmpp/saslhandler.h"
 #include "third_party/libjingle_xmpp/xmpp/xmpplogintask.h"
-#include "third_party/webrtc/base/common.h"
+#include "third_party/webrtc/base/checks.h"
 
 namespace buzz {
 
@@ -347,7 +347,7 @@
   // It should really never be necessary to set a FROM attribute on a stanza.
   // It is implied by the bind on the stream and if you get it wrong
   // (by flipping from/to on a message?) the server will close the stream.
-  ASSERT(!element->HasAttr(QN_FROM));
+  RTC_DCHECK(!element->HasAttr(QN_FROM));
 
   XmlPrinter::PrintXml(output_.get(), element, &xmlns_stack_);
 }
diff --git a/third_party/libjingle_xmpp/xmpp/xmppengineimpl_iq.cc b/third_party/libjingle_xmpp/xmpp/xmppengineimpl_iq.cc
index a5b5714..e206678b 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppengineimpl_iq.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmppengineimpl_iq.cc
@@ -12,7 +12,6 @@
 #include <vector>
 #include "third_party/libjingle_xmpp/xmpp/constants.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengineimpl.h"
-#include "third_party/webrtc/base/common.h"
 
 namespace buzz {
 
diff --git a/third_party/libjingle_xmpp/xmpp/xmpplogintask.cc b/third_party/libjingle_xmpp/xmpp/xmpplogintask.cc
index 6936b77..ae19b99e 100644
--- a/third_party/libjingle_xmpp/xmpp/xmpplogintask.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmpplogintask.cc
@@ -19,7 +19,6 @@
 #include "third_party/libjingle_xmpp/xmpp/saslmechanism.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengineimpl.h"
 #include "third_party/webrtc/base/base64.h"
-#include "third_party/webrtc/base/common.h"
 
 using rtc::ConstantLabel;
 
diff --git a/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc
index 2a70fae..17bced5 100644
--- a/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmpplogintask_unittest.cc
@@ -19,7 +19,6 @@
 #include "third_party/libjingle_xmpp/xmpp/saslplainmechanism.h"
 #include "third_party/libjingle_xmpp/xmpp/util_unittest.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
-#include "third_party/webrtc/base/common.h"
 #include "third_party/webrtc/base/cryptstring.h"
 #include "third_party/webrtc/base/gunit.h"
 #include "third_party/webrtc/typedefs.h"
@@ -634,4 +633,3 @@
     SetUp();
   }
 }
-
diff --git a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.cc b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.cc
index 278b988..a42a1b8 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser.cc
@@ -12,7 +12,6 @@
 
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmpp/constants.h"
-#include "third_party/webrtc/base/common.h"
 #ifdef EXPAT_RELATIVE_PATH
 #include "expat.h"
 #else
@@ -81,8 +80,6 @@
 void
 XmppStanzaParser::IncomingError(
     XmlParseContext * pctx, XML_Error errCode) {
-  RTC_UNUSED(pctx);
-  RTC_UNUSED(errCode);
   psph_->XmlError();
 }
 
diff --git a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc
index 109701b3..2e9b9f5 100644
--- a/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc
+++ b/third_party/libjingle_xmpp/xmpp/xmppstanzaparser_unittest.cc
@@ -13,7 +13,6 @@
 #include <string>
 #include "third_party/libjingle_xmpp/xmllite/xmlelement.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppstanzaparser.h"
-#include "third_party/webrtc/base/common.h"
 #include "third_party/webrtc/base/gunit.h"
 
 using buzz::QName;
diff --git a/third_party/libpng/OWNERS b/third_party/libpng/OWNERS
index c447dcd..312b5da 100644
--- a/third_party/libpng/OWNERS
+++ b/third_party/libpng/OWNERS
@@ -1,2 +1,4 @@
 msarett@chromium.org
 scroggo@chromium.org
+
+# COMPONENT: Internals>Images>Codecs
diff --git a/third_party/protobuf/OWNERS b/third_party/protobuf/OWNERS
index e7125d3..f52d95f 100644
--- a/third_party/protobuf/OWNERS
+++ b/third_party/protobuf/OWNERS
@@ -1,2 +1,4 @@
 pkasting@chromium.org
 xyzzyz@chromium.org
+
+# COMPONENT: Internals
diff --git a/third_party/widevine/OWNERS b/third_party/widevine/OWNERS
index 0325fb4..d4eaf07 100644
--- a/third_party/widevine/OWNERS
+++ b/third_party/widevine/OWNERS
@@ -2,3 +2,5 @@
 ddorwin@chromium.org
 xhwang@chromium.org
 
+
+# COMPONENT: Internals>Media>Encrypted
diff --git a/third_party/widevine/cdm/BUILD.gn b/third_party/widevine/cdm/BUILD.gn
index ec798c3f..eebe2ab5 100644
--- a/third_party/widevine/cdm/BUILD.gn
+++ b/third_party/widevine/cdm/BUILD.gn
@@ -28,7 +28,10 @@
     widevine_cdm_binary_files = [ "chromeos/$widevine_arch/libwidevinecdm.so" ]
   } else if (is_linux) {
     widevine_cdm_version_h_file = "linux/$widevine_arch/widevine_cdm_version.h"
-    widevine_cdm_binary_files = [ "linux/$widevine_arch/libwidevinecdm.so" ]
+    widevine_cdm_binary_files = [
+      "linux/$widevine_arch/libwidevinecdm.so",
+      "linux/$widevine_arch/libwidevinecdm.so.sig",
+    ]
   } else if (is_win) {
     widevine_cdm_version_h_file = "win/$widevine_arch/widevine_cdm_version.h"
     widevine_cdm_binary_files = [
@@ -192,3 +195,18 @@
     ]
   }
 }
+
+if (is_chrome_branded) {
+  copy("widevine_signature_scripts") {
+    sources = [
+      "../scripts/signature_generator.py",
+      "../scripts/signer.py",
+    ]
+    outputs = [
+      "$root_out_dir/installer/widevine/{{source_file_part}}",
+    ]
+  }
+} else {
+  group("widevine_signature_scripts") {
+  }
+}
diff --git a/tools/chrome_proxy/webdriver/bypass.py b/tools/chrome_proxy/webdriver/bypass.py
index 3d5f3989..1f0014788 100644
--- a/tools/chrome_proxy/webdriver/bypass.py
+++ b/tools/chrome_proxy/webdriver/bypass.py
@@ -9,6 +9,20 @@
 
 class Bypass(IntegrationTest):
 
+  # Ensure Chrome does not use Data Saver for block-once, but does use Data
+  # Saver for a subsequent request.
+  def testBlockOnce(self):
+    with TestDriver() as t:
+      t.AddChromeArg('--enable-spdy-proxy-auth')
+      t.LoadURL('http://check.googlezip.net/blocksingle/')
+      responses = t.GetHTTPResponses()
+      self.assertEqual(2, len(responses))
+      for response in responses:
+        if response.url == "http://check.googlezip.net/image.png":
+          self.assertHasChromeProxyViaHeader(response)
+        else:
+          self.assertNotHasChromeProxyViaHeader(response)
+
   # Ensure Chrome does not use Data Saver for block=0, which uses the default
   # proxy retry delay.
   def testBypass(self):
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 8b3802a08..6f7f410 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -4866,6 +4866,9 @@
 </histogram>
 
 <histogram name="BlinkGC.TimeForStoppingThreads" units="ms">
+  <obsolete>
+    As of 02/2017, the code to stop Blink threads was removed.
+  </obsolete>
   <owner>haraken@chromium.org</owner>
   <summary>
     Duration of time taken to stop all Blink threads before starting a GC.
@@ -22568,7 +22571,7 @@
 </histogram>
 
 <histogram name="InstanceID.GetToken.RequestStatus"
-    enum="GCMUnregistrationRequestStatus">
+    enum="GCMRegistrationRequestStatus">
   <owner>juyik@chromium.org</owner>
   <summary>Status code of the outcome of GetToken request.</summary>
 </histogram>
@@ -32406,6 +32409,9 @@
 </histogram>
 
 <histogram name="Net.Http2SSLCipherSuite" enum="SSLCipherSuite">
+  <obsolete>
+    Removed 2017-02.
+  </obsolete>
   <owner>davidben@chromium.org</owner>
   <summary>
     The SSL/TLS cipher suite that was negotiated, recorded for each successful
@@ -43688,52 +43694,14 @@
 </histogram>
 
 <histogram
-    name="PageLoad.Clients.DataReductionProxy.Experimental.Requests.Network"
-    units="requests">
-  <owner>bengr@chromium.org</owner>
-  <owner>ryansturm@chromium.org</owner>
-  <summary>
-    The number of network requests in a page load when the main resource was
-    loaded through data reduction proxy. Recorded per page load when the user
-    navigates away, hides the tab, or backgrounds the app.
-  </summary>
-</histogram>
-
-<histogram
-    name="PageLoad.Clients.DataReductionProxy.Experimental.Requests.Network.NonProxied"
-    units="requests">
-  <owner>bengr@chromium.org</owner>
-  <owner>ryansturm@chromium.org</owner>
-  <summary>
-    The number of network requests in a page load that were not fetched through
-    the data reduction proxy when the main resource was loaded through data
-    reduction proxy. Recorded per page load when the user navigates away, hides
-    the tab, or backgrounds the app.
-  </summary>
-</histogram>
-
-<histogram
-    name="PageLoad.Clients.DataReductionProxy.Experimental.Requests.Network.PercentProxied"
+    name="PageLoad.Clients.DataReductionProxy.Experimental.CompletedResources.Network.PercentProxied"
     units="%">
   <owner>bengr@chromium.org</owner>
   <owner>ryansturm@chromium.org</owner>
   <summary>
-    The percent of network requests in a page load that use data reduction proxy
-    when the main resource was loaded through data reduction proxy. Recorded per
-    page load when the user navigates away, hides the tab, or backgrounds the
-    app.
-  </summary>
-</histogram>
-
-<histogram
-    name="PageLoad.Clients.DataReductionProxy.Experimental.Requests.Network.Proxied"
-    units="requests">
-  <owner>bengr@chromium.org</owner>
-  <owner>ryansturm@chromium.org</owner>
-  <summary>
-    The number of network requests in a page load that were fetched through the
-    data reduction proxy when the main resource was loaded through data
-    reduction proxy. Recorded per page load when the user navigates away, hides
+    The percent of completed resources loaded from network in a page load that
+    use data reduction proxy when the main resource was loaded through data
+    reduction proxy.  Recorded per page load when the user navigates away, hides
     the tab, or backgrounds the app.
   </summary>
 </histogram>
@@ -43773,6 +43741,17 @@
   <summary>Events related to Google CAPTCHA pages being seen by users.</summary>
 </histogram>
 
+<histogram name="PageLoad.Clients.SubresourceFilter.Count" enum="Boolean">
+  <owner>bmcquade@chromium.org</owner>
+  <summary>
+    Records 'true' for page loads where the subresource filter matched a
+    subresource loaded by the page. Includes dryrun matches. To compute the
+    percentage of total page loads affected by subresource filtering, divide by
+    the sum of counts for (PageLoad.ParseTiming.NavigationToParseStart +
+    PageLoad.ParseTiming.NavigationToParseStart.Background).
+  </summary>
+</histogram>
+
 <histogram name="PageLoad.CSSTiming.Parse.BeforeFirstContentfulPaint"
     units="ms">
   <owner>csharrison@chromium.org</owner>
@@ -43969,7 +43948,8 @@
   <owner>jkarlin@chromium.org</owner>
   <summary>
     The number of prefiltered (e.g., compressed) KiloBytes loaded from the cache
-    via the browser process for a page load. Recorded when the page is closed.
+    via the browser process for a page load. Recorded when the page load is
+    terminated.
   </summary>
 </histogram>
 
@@ -43977,8 +43957,8 @@
   <owner>jkarlin@chromium.org</owner>
   <summary>
     The number of prefiltered (e.g., compressed) KiloBytes loaded over the
-    network via the browser process for a page load. Recorded when the page is
-    closed.
+    network via the browser process for a page load. Recorded when the page load
+    is terminated.
   </summary>
 </histogram>
 
@@ -43986,7 +43966,7 @@
   <owner>jkarlin@chromium.org</owner>
   <summary>
     The number of prefiltered (e.g., compressed) KiloBytes loaded via the
-    browser process for a page load. Recorded when the page is closed.
+    browser process for a page load. Recorded when the page load is terminated.
   </summary>
 </histogram>
 
@@ -44008,6 +43988,36 @@
   </summary>
 </histogram>
 
+<histogram name="PageLoad.Experimental.CompletedResources.Cache"
+    units="resources">
+  <owner>csharrison@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    The number of completed resources loaded from the cache via the browser
+    process for a page load. Recorded when the page load is terminated.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Experimental.CompletedResources.Network"
+    units="resources">
+  <owner>csharrison@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    The number of completed resources loaded from the network via the browser
+    process for a page load. Recorded when the page load is terminated.
+  </summary>
+</histogram>
+
+<histogram name="PageLoad.Experimental.CompletedResources.Total"
+    units="resources">
+  <owner>csharrison@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    The total number of completed resources loaded via the browser process for a
+    page load. Recorded when the page load is terminated.
+  </summary>
+</histogram>
+
 <histogram
     name="PageLoad.Experimental.PaintTiming.FirstMeaningfulPaintSignalStatus"
     enum="FirstMeaningfulPaintSignalStatus">
@@ -46083,6 +46093,20 @@
   </summary>
 </histogram>
 
+<histogram name="Permissions.AutoBlocker.EmbargoStatus"
+    enum="PermissionEmbargoStatus">
+  <owner>dominickn@chromium.org</owner>
+  <owner>kcarattini@chromium.org</owner>
+  <summary>
+    Tracks the reason that an (origin, permission) pair has been placed under
+    embargo (blocked from making requests for that permission for a period of
+    time). This is triggered when a permission is placed under embargo for
+    blacklisting (once Safe Browsing has returned a result), when a permission
+    prompt has been shown and it is placed under embargo for repeated
+    dismissals, or when a permission prompt is shown and not embargoed.
+  </summary>
+</histogram>
+
 <histogram name="Permissions.AutoBlocker.SafeBrowsingResponse"
     enum="SafeBrowsingResponse">
   <owner>dominickn@chromium.org</owner>
@@ -63884,6 +63908,15 @@
   <summary>Events in reqests processing of IP-based SimpleGeolocation.</summary>
 </histogram>
 
+<histogram name="SimpleGeolocation.Request.HasCellTowers"
+    enum="SimpleGeolocationRequestHasCellTowers">
+  <owner>skylarc@chromium.org</owner>
+  <summary>
+    This boolean histogram counts SimpleGeolocationRequests carrying a nonzero
+    number of cell towers.
+  </summary>
+</histogram>
+
 <histogram name="SimpleGeolocation.Request.HasWiFiAccessPoints"
     enum="SimpleGeolocationRequestHasWiFiAccessPoints">
   <owner>alemate@chromium.org</owner>
@@ -73750,6 +73783,11 @@
   </summary>
 </histogram>
 
+<histogram name="VirtualKeyboard.InitLatency.FirstLoad" units="ms">
+  <owner>oka@chromium.org</owner>
+  <summary>Latency of the keyboard being loaded for the first time.</summary>
+</histogram>
+
 <histogram name="VirtualKeyboard.KeyboardControlEvent"
     enum="KeyboardControlEvent">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
@@ -73982,6 +74020,17 @@
   </summary>
 </histogram>
 
+<histogram name="WebApk.Install.InstallDuration" units="ms">
+  <owner>hanxi@chromium.org</owner>
+  <owner>pkotwicz@chromium.org</owner>
+  <owner>yfriedman@chromium.org</owner>
+  <summary>
+    How long it takes to install a WebAPK. The time is measured from the time
+    that the user initiates the install to the time that the Open button is
+    shown in the infobar. This metric is only recorded when install succeeds.
+  </summary>
+</histogram>
+
 <histogram name="WebApk.Install.InstallEvent" enum="WebApkInstallEvent">
   <owner>hanxi@chromium.org</owner>
   <owner>pkotwicz@chromium.org</owner>
@@ -93714,8 +93763,8 @@
 
 <enum name="HistoryPageView" type="int">
   <int value="0" label="History"/>
-  <int value="1" label="Grouped Week"/>
-  <int value="2" label="Grouped Month"/>
+  <int value="1" label="Grouped Week (Obsolete Feb. 2017)"/>
+  <int value="2" label="Grouped Month (Obsolete Feb. 2017)"/>
   <int value="3" label="Synced Tabs"/>
   <int value="4" label="Signin Promo"/>
 </enum>
@@ -94480,6 +94529,7 @@
   <int value="70" label="GROUPED_PERMISSION_INFOBAR_DELEGATE_ANDROID"/>
   <int value="71" label="OFFLINE_PAGE_INFOBAR_DELEGATE"/>
   <int value="72" label="SEARCH_GEOLOCATION_DISCLOSURE_INFOBAR_DELEGATE"/>
+  <int value="73" label="AUTOMATION_INFOBAR_DELEGATE"/>
 </enum>
 
 <enum name="InfoBarResponse" type="int">
@@ -96614,6 +96664,8 @@
   <int value="-2097515669" label="disable-cast"/>
   <int value="-2090484194" label="ContextualSearchUrlActions:disabled"/>
   <int value="-2083195884" label="enable-firewall-hole-punching"/>
+  <int value="-2082042818"
+      label="AutofillCreditCardLastUsedDateDisplay:enabled"/>
   <int value="-2077268643" label="disable-device-enumeration"/>
   <int value="-2075870708" label="MediaRemotingEncrypted:disabled"/>
   <int value="-2075807193" label="enable-webusb-on-any-origin"/>
@@ -96767,6 +96819,7 @@
   <int value="-1491417046" label="enable-fullscreen-toolbar-reveal"/>
   <int value="-1490298774" label="enable-captive-portal-bypass-proxy-option"/>
   <int value="-1488744539" label="QuickUnlockFingerprint:enabled"/>
+  <int value="-1487243228" label="NewUsbBackend:disabled"/>
   <int value="-1482685863" label="enable-request-tablet-site"/>
   <int value="-1480926949" label="MaterialDesignBookmarks:enabled"/>
   <int value="-1478876902" label="disable-permission-action-reporting"/>
@@ -96838,6 +96891,7 @@
   <int value="-1176748003"
       label="FramebustingNeedsSameOriginOrUserGesture:disabled"/>
   <int value="-1176493523" label="enable-md-extensions"/>
+  <int value="-1172572865" label="NTPShowGoogleGInOmnibox:enabled"/>
   <int value="-1172204005" label="enable-offline-auto-reload-visible-only"/>
   <int value="-1161409696" label="MediaRemotingEncrypted:enabled"/>
   <int value="-1160026273" label="enable-web-notification-custom-layouts"/>
@@ -97149,6 +97203,7 @@
   <int value="278756320" label="disable-app-list-app-info"/>
   <int value="280644887" label="mash"/>
   <int value="301869874" label="NTPPhysicalWebPageSuggestions:disabled"/>
+  <int value="304901781" label="NewUsbBackend:enabled"/>
   <int value="313303258" label="WebPaymentsModifiers:disabled"/>
   <int value="316182183" label="MediaDocumentDownloadButton:disabled"/>
   <int value="323605372" label="ui-disable-compositor-animation-timelines"/>
@@ -97349,6 +97404,8 @@
   <int value="1142788238" label="FontCacheScaling:disabled"/>
   <int value="1149823105" label="enable-input-ime-api"/>
   <int value="1150622273" label="enable-apps-file-associations"/>
+  <int value="1153454438"
+      label="AutofillCreditCardLastUsedDateDisplay:disabled"/>
   <int value="1155923106" label="NTPOfflinePages:enabled"/>
   <int value="1163255347" label="ash-enable-touch-view-touch-feedback"/>
   <int value="1166169237" label="disable-delay-agnostic-aec"/>
@@ -97507,6 +97564,7 @@
   <int value="1817312143" label="num-raster-threads"/>
   <int value="1819256299" label="disable-webrtc-hw-decoding"/>
   <int value="1819536169" label="disable-cast-streaming-hw-encoding"/>
+  <int value="1820317896" label="NTPShowGoogleGInOmnibox:disabled"/>
   <int value="1820451991" label="enable-offline-auto-reload"/>
   <int value="1821723343" label="disable-saml-signin"/>
   <int value="1827369558" label="AndroidPayIntegrationV1:disabled"/>
@@ -97560,6 +97618,7 @@
   <int value="1996125159" label="AutoplayMutedVideos:enabled"/>
   <int value="1997047666" label="NTPSnippetsIncreasedVisibility:disabled"/>
   <int value="2000091128" label="enable-touch-hover"/>
+  <int value="2003811018" label="enable-touch-support-for-screen-magnifier"/>
   <int value="2004483175" label="multi-instance-merge-tabs"/>
   <int value="2004829262" label="enable-webgl-draft-extensions"/>
   <int value="2005614493" label="tab-management-experiment-type-dill"/>
@@ -102415,6 +102474,12 @@
   <int value="4" label="REVOKED"/>
 </enum>
 
+<enum name="PermissionEmbargoStatus" type="int">
+  <int value="0" label="NOT_EMBARGOED"/>
+  <int value="1" label="BLACKLISTED"/>
+  <int value="2" label="REPEATED_DISMISSALS"/>
+</enum>
+
 <enum name="PermissionRequestType" type="int">
   <int value="0" label="PERMISSION_BUBBLE_UNKNOWN"/>
   <int value="1" label="PERMISSION_BUBBLE_MULTIPLE"/>
@@ -106446,11 +106511,13 @@
 
 <enum name="SettingsResetPromptConfigError" type="int">
   <int value="1" label="Config Ok"/>
-  <int value="2" label="Missing domain hashes param"/>
-  <int value="3" label="Bad domain hashes param"/>
+  <int value="2" label="Missing domain_hashes param"/>
+  <int value="3" label="Bad domain_hashes param"/>
   <int value="4" label="Bad domain hash"/>
   <int value="5" label="Bad domain id"/>
   <int value="6" label="Duplicate domain hash"/>
+  <int value="7" label="Bad delay_before_prompt_seconds param"/>
+  <int value="8" label="Bad use_modal_dialog param"/>
 </enum>
 
 <enum name="SettingsSections" type="int">
@@ -107027,6 +107094,11 @@
   <int value="4" label="Response malformed"/>
 </enum>
 
+<enum name="SimpleGeolocationRequestHasCellTowers" type="int">
+  <int value="0" label="No cell tower data in request."/>
+  <int value="1" label="Cell tower data present."/>
+</enum>
+
 <enum name="SimpleGeolocationRequestHasWiFiAccessPoints" type="int">
   <int value="0" label="No WiFi data in request."/>
   <int value="1" label="WiFi data present."/>
@@ -117041,6 +117113,7 @@
   <affected-histogram
       name="PageLoad.DocumentTiming.NavigationToLoadEventFired"/>
   <affected-histogram name="PageLoad.Experimental.Bytes.Network"/>
+  <affected-histogram name="PageLoad.Experimental.CompletedResources.Network"/>
   <affected-histogram
       name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"/>
   <affected-histogram
@@ -117053,6 +117126,16 @@
   <affected-histogram name="PageLoad.ParseTiming.ParseDuration"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PageLoadMetricsClientsDataReductionProxyResources"
+    separator=".">
+  <suffix name="NonProxied"
+      label="Resources not loaded through data reduction proxy."/>
+  <suffix name="Proxied"
+      label="Resources loaded through data reduction proxy."/>
+  <affected-histogram
+      name="PageLoad.Clients.DataReductionProxy.Experimental.CompletedResources.Network"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PageLoadMetricsClientsDocWrite" separator="."
     ordering="prefix">
   <suffix name="Clients.DocWrite.Block"
@@ -117288,6 +117371,30 @@
       name="PageLoad.Clients.ServiceWorker.PaintTiming.ParseStartToFirstContentfulPaint"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="PageLoadMetricsClientsSubresourceFilter"
+    separator="." ordering="prefix">
+  <suffix name="Clients.SubresourceFilter"
+      label="For pages with filtered subresources. Includes dryrun matches."/>
+  <affected-histogram
+      name="PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired"/>
+  <affected-histogram
+      name="PageLoad.DocumentTiming.NavigationToLoadEventFired"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Cache"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Network"/>
+  <affected-histogram name="PageLoad.Experimental.Bytes.Total"/>
+  <affected-histogram name="PageLoad.Experimental.CompletedResources.Cache"/>
+  <affected-histogram name="PageLoad.Experimental.CompletedResources.Network"/>
+  <affected-histogram name="PageLoad.Experimental.CompletedResources.Total"/>
+  <affected-histogram
+      name="PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint"/>
+  <affected-histogram
+      name="PageLoad.Experimental.PaintTiming.ParseStartToFirstMeaningfulPaint"/>
+  <affected-histogram
+      name="PageLoad.PaintTiming.NavigationToFirstContentfulPaint"/>
+  <affected-histogram
+      name="PageLoad.PaintTiming.ParseStartToFirstContentfulPaint"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="PageLoadMetricsLoadType" separator=".">
   <suffix name="LoadType.Reload" label="Restricted to reloaded pages."/>
   <suffix name="LoadType.ForwardBackNavigation"
diff --git a/tools/perf/page_sets/data/system_health_desktop.json b/tools/perf/page_sets/data/system_health_desktop.json
index c4a23e626..bdbba9e2 100644
--- a/tools/perf/page_sets/data/system_health_desktop.json
+++ b/tools/perf/page_sets/data/system_health_desktop.json
@@ -10,7 +10,8 @@
             "DEFAULT": "system_health_desktop_036.wpr"
         },
         "browse:media:youtube": {
-            "DEFAULT": "system_health_desktop_026.wpr"
+            "DEFAULT": "system_health_desktop_026.wpr",
+            "linux": "system_health_desktop_026.wpr"
         },
         "browse:news:cnn": {
             "DEFAULT": "system_health_desktop_013.wpr"
@@ -70,7 +71,8 @@
             "DEFAULT": "system_health_desktop_003.wpr"
         },
         "load:media:youtube": {
-            "DEFAULT": "system_health_desktop_003.wpr"
+            "DEFAULT": "system_health_desktop_003.wpr",
+            "linux": "system_health_desktop_003.wpr"
         },
         "load:news:bbc": {
             "DEFAULT": "system_health_desktop_002.wpr"
@@ -180,4 +182,4 @@
     },
     "description": "Describes the Web Page Replay archives for a story set. Don't edit by hand! Use record_wpr for updating.",
     "platform_specific": true
-}
\ No newline at end of file
+}
diff --git a/tools/perf/page_sets/system_health/browsing_stories.py b/tools/perf/page_sets/system_health/browsing_stories.py
index 9c56a35..d509d5d 100644
--- a/tools/perf/page_sets/system_health/browsing_stories.py
+++ b/tools/perf/page_sets/system_health/browsing_stories.py
@@ -406,6 +406,7 @@
   ITEM_VIEW_TIME_IN_SECONDS = 5
   ITEMS_TO_VISIT = 8
   ITEM_SELECTOR_INDEX = 3
+  PLATFORM_SPECIFIC = True
 
 
 class FacebookPhotosMobileStory(_MediaBrowsingStory):
diff --git a/tools/perf/page_sets/system_health/loading_stories.py b/tools/perf/page_sets/system_health/loading_stories.py
index 9d30253..6a51c1e 100644
--- a/tools/perf/page_sets/system_health/loading_stories.py
+++ b/tools/perf/page_sets/system_health/loading_stories.py
@@ -208,6 +208,7 @@
   # No way to disable autoplay on desktop.
   NAME = 'load:media:youtube'
   URL = 'https://www.youtube.com/watch?v=QGfhS1hfTWw&autoplay=false'
+  PLATFORM_SPECIFIC = True
 
 
 class LoadDailymotionStory(_LoadingStory):
diff --git a/tools/traffic_annotation/DEPS b/tools/traffic_annotation/DEPS
index fd1403a..efc7233 100644
--- a/tools/traffic_annotation/DEPS
+++ b/tools/traffic_annotation/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+net/traffic_annotation",
-]
\ No newline at end of file
+]
+
diff --git a/tools/traffic_annotation/sample_traffic_annotation.cc b/tools/traffic_annotation/sample_traffic_annotation.cc
index 552f301..45a191c2 100644
--- a/tools/traffic_annotation/sample_traffic_annotation.cc
+++ b/tools/traffic_annotation/sample_traffic_annotation.cc
@@ -6,7 +6,9 @@
 
 // This file includes a sample and a template for text-coded traffic_annotation.
 // For more description on each field, please refer to:
-// (tools/traffic_annotation/traffic_annotation.proto)
+// tools/traffic_annotation/traffic_annotation.proto
+// and
+// out/Debug/gen/components/policy/proto/cloud_policy.proto
 // For more information on policies, please refer to:
 // http://dev.chromium.org/administrators/policy-list-3
 
@@ -14,7 +16,7 @@
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("spellcheck_lookup", R"(
         semantics {
-          sender: "spellcheck"
+          sender: "Online Spellcheck"
           description:
             "Google Chrome can provide smarter spell-checking by sending "
             "text you type into the browser to Google's servers, allowing "
@@ -47,23 +49,24 @@
 
 void network_traffic_annotation_template() {
   net::NetworkTrafficAnnotationTag traffic_annotation =
-      net::DefineNetworkTrafficAnnotation("", R"(
+      net::DefineNetworkTrafficAnnotation("...", R"(
         semantics {
-          sender: ""
-          description: ""
-          trigger: ""
-          data: ""
+          sender: "..."
+          description: "..."
+          trigger: "..."
+          data: "..."
           destination: WEBSITE/GOOGLE_OWNED_SERVICE/OTHER
         }
         policy {
           cookies_allowed: false/true
-          cookies_store: ""
-          setting: ""
+          cookies_store: "..."
+          setting: "..."
           policy {
             [POLICY_NAME] {
                 policy_options {mode: MANDATORY/RECOMMENDED/UNSET}
                 value: ...
             }
           }
+          policy_exception_justification = "..."
         })");
 }
\ No newline at end of file
diff --git a/tools/traffic_annotation/traffic_annotation.proto b/tools/traffic_annotation/traffic_annotation.proto
index c43c0ca..8f8d43c 100644
--- a/tools/traffic_annotation/traffic_annotation.proto
+++ b/tools/traffic_annotation/traffic_annotation.proto
@@ -5,7 +5,10 @@
 syntax = "proto3";
 package traffic_annotation;
 
-import "components/policy/cloud_policy_full_runtime.proto";
+// cloud_policy_full_runtime.proto is a version of the following proto without
+// lite runtime optimization:
+// out/Debug/gen/components/policy/proto/cloud_policy.proto
+import "cloud_policy_full_runtime.proto";
 
 // Describes a specific kind of network traffic based on a fine-grained
 // semantic classification of all network traffic generated by Chrome.
@@ -152,7 +155,7 @@
 
     // Example policy configuration that disables this network request.
     // This would be a text serialized protobuf of any enterprise policy.
-    // see out/Debug/gen/components/policy/cloud_policy.proto
+    // see out/Debug/gen/components/policy/proto/cloud_policy.proto
     repeated enterprise_management.CloudPolicySettings policy = 4;
 
     // Justification for not having a policy that disables this feature.
diff --git a/tools/vim/ninja_output.py b/tools/vim/ninja_output.py
index af30520..5fc70ad 100644
--- a/tools/vim/ninja_output.py
+++ b/tools/vim/ninja_output.py
@@ -51,7 +51,13 @@
   def approx_directory_mtime(path):
     # This is a heuristic; don't recurse into subdirectories.
     paths = [path] + [os.path.join(path, f) for f in os.listdir(path)]
-    return max(os.path.getmtime(p) for p in paths)
+    return max(filter(None, [safe_mtime(p) for p in paths]))
+
+  def safe_mtime(path):
+    try:
+      return os.path.getmtime(path)
+    except OSError:
+      return None
 
   try:
     return max(generate_paths(), key=approx_directory_mtime)
diff --git a/ui/accessibility/extensions/alt/hide-images.css b/ui/accessibility/extensions/alt/hide-images.css
index 840d7f23..5ed474d 100644
--- a/ui/accessibility/extensions/alt/hide-images.css
+++ b/ui/accessibility/extensions/alt/hide-images.css
@@ -27,7 +27,7 @@
     clear: both;
 }
 
-@-webkit-keyframes slideDown {
+@keyframes slideDown {
     from {
       transform: translateY(-150%);
     }
@@ -36,7 +36,7 @@
     }
 }
 
-@-webkit-keyframes slideUp {
+@keyframes slideUp {
     from {
       transform: translateY(0%);
     }
@@ -46,26 +46,27 @@
 }
 
 body[show-alt] .show-alt-infobar {
-    -webkit-animation-name: slideDown;
-    -webkit-animation-duration: 0.5s;
-    -webkit-animation-delay: 0.5s;
-    -webkit-animation-iteration-count: 1;
-    -webkit-animation-timing-function: ease;
-    -webkit-animation-direction: forwards;
+    animation-delay: 0.5s;
+    animation-direction: forwards;
+    animation-duration: 0.5s;
+    animation-iteration-count: 1;
+    animation-name: slideDown;
+    animation-timing-function: ease;
     transform: translateY(0%);
 }
 
 body:not([show-alt]) .show-alt-infobar {
-    -webkit-animation-name: slideUp;
-    -webkit-animation-duration: 0.5s;
-    -webkit-animation-delay: 0.5s;
-    -webkit-animation-iteration-count: 1;
-    -webkit-animation-timing-function: ease;
-    -webkit-animation-direction: forwards;
+    animation-delay: 0.5s;
+    animation-direction: forwards;
+    animation-duration: 0.5s;
+    animation-iteration-count: 1;
+    animation-name: slideUp;
+    animation-timing-function: ease;
     transform: translateY(-150%);
 }
 
 .show-alt-infobar {
+    animation-fill-mode: backwards;
     top: 0;
     left: 0;
     right: 0;
@@ -76,10 +77,8 @@
     line-height: 2.0;
     overflow: hidden;
     box-shadow: 0 0 5px black;
-    box-shadow:         0 0 5px black;
     font-family: Arial, sans-serif !important;
     font-size: 12pt !important;
-    -webkit-animation-fill-mode: backwards;
 }
 
 .show-alt-infobar .content {
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index caf0fcc..8e1f152 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -338,6 +338,7 @@
 test("aura_unittests") {
   sources = [
     "gestures/gesture_recognizer_unittest.cc",
+    "mus/input_method_mus_unittest.cc",
     "mus/os_exchange_data_provider_mus_unittest.cc",
     "mus/property_converter_unittest.cc",
     "mus/user_activity_forwarder_unittest.cc",
diff --git a/ui/aura/mus/input_method_mus.cc b/ui/aura/mus/input_method_mus.cc
index 230dfff..d629df2 100644
--- a/ui/aura/mus/input_method_mus.cc
+++ b/ui/aura/mus/input_method_mus.cc
@@ -31,7 +31,15 @@
   SetDelegate(delegate);
 }
 
-InputMethodMus::~InputMethodMus() {}
+InputMethodMus::~InputMethodMus() {
+  // Mus won't dispatch the next key event until the existing one is acked. We
+  // may have KeyEvents sent to IME and awaiting the result, we need to ack
+  // them otherwise mus won't process the next event until it times out.
+  for (auto& callback_ptr : pending_callbacks_) {
+    if (callback_ptr)
+      callback_ptr->Run(EventResult::UNHANDLED);
+  }
+}
 
 void InputMethodMus::Init(service_manager::Connector* connector) {
   if (connector)
@@ -40,7 +48,7 @@
 
 void InputMethodMus::DispatchKeyEvent(
     ui::KeyEvent* event,
-    std::unique_ptr<base::Callback<void(EventResult)>> ack_callback) {
+    std::unique_ptr<EventResultCallback> ack_callback) {
   DCHECK(event->type() == ui::ET_KEY_PRESSED ||
          event->type() == ui::ET_KEY_RELEASED);
 
@@ -54,13 +62,7 @@
     return;
   }
 
-  // IME driver will notify us whether it handled the event or not by calling
-  // ProcessKeyEventCallback(), in which we will run the |ack_callback| to tell
-  // the window server if client handled the event or not.
-  input_method_->ProcessKeyEvent(
-      ui::Event::Clone(*event),
-      base::Bind(&InputMethodMus::ProcessKeyEventCallback,
-                 base::Unretained(this), *event, Passed(&ack_callback)));
+  SendKeyEventToInputMethod(*event, std::move(ack_callback));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -117,6 +119,19 @@
   return false;
 }
 
+void InputMethodMus::SendKeyEventToInputMethod(
+    const ui::KeyEvent& event,
+    std::unique_ptr<EventResultCallback> ack_callback) {
+  // IME driver will notify us whether it handled the event or not by calling
+  // ProcessKeyEventCallback(), in which we will run the |ack_callback| to tell
+  // the window server if client handled the event or not.
+  pending_callbacks_.push_back(std::move(ack_callback));
+  input_method_->ProcessKeyEvent(
+      ui::Event::Clone(event),
+      base::Bind(&InputMethodMus::ProcessKeyEventCallback,
+                 base::Unretained(this), event));
+}
+
 void InputMethodMus::OnDidChangeFocusedClient(
     ui::TextInputClient* focused_before,
     ui::TextInputClient* focused) {
@@ -132,7 +147,8 @@
     ui::mojom::StartSessionDetailsPtr details =
         ui::mojom::StartSessionDetails::New();
     details->client = text_input_client_->CreateInterfacePtrAndBind();
-    details->input_method_request = MakeRequest(&input_method_);
+    details->input_method_request = MakeRequest(&input_method_ptr_);
+    input_method_ = input_method_ptr_.get();
     details->text_input_type = focused->GetTextInputType();
     details->text_input_mode = focused->GetTextInputMode();
     details->text_direction = focused->GetTextDirection();
@@ -157,7 +173,6 @@
 
 void InputMethodMus::ProcessKeyEventCallback(
     const ui::KeyEvent& event,
-    std::unique_ptr<base::Callback<void(EventResult)>> ack_callback,
     bool handled) {
   EventResult event_result;
   if (!handled) {
@@ -171,6 +186,10 @@
   } else {
     event_result = EventResult::HANDLED;
   }
+  DCHECK(!pending_callbacks_.empty());
+  std::unique_ptr<EventResultCallback> ack_callback =
+      std::move(pending_callbacks_.front());
+  pending_callbacks_.pop_front();
   // |ack_callback| can be null if the standard form of DispatchKeyEvent() is
   // called instead of the version which provides a callback. In mus+ash we
   // use the version with callback, but some unittests use the standard form.
diff --git a/ui/aura/mus/input_method_mus.h b/ui/aura/mus/input_method_mus.h
index d540024..4a24498 100644
--- a/ui/aura/mus/input_method_mus.h
+++ b/ui/aura/mus/input_method_mus.h
@@ -5,6 +5,8 @@
 #ifndef UI_AURA_MUS_INPUT_METHOD_MUS_H_
 #define UI_AURA_MUS_INPUT_METHOD_MUS_H_
 
+#include <deque>
+
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -20,19 +22,20 @@
 
 namespace aura {
 
+class InputMethodMusTestApi;
 class TextInputClientImpl;
 class Window;
 
 class AURA_EXPORT InputMethodMus : public ui::InputMethodBase {
  public:
+  using EventResultCallback = base::Callback<void(ui::mojom::EventResult)>;
+
   InputMethodMus(ui::internal::InputMethodDelegate* delegate, Window* window);
   ~InputMethodMus() override;
 
   void Init(service_manager::Connector* connector);
-  void DispatchKeyEvent(
-      ui::KeyEvent* event,
-      std::unique_ptr<base::Callback<void(ui::mojom::EventResult)>>
-          ack_callback);
+  void DispatchKeyEvent(ui::KeyEvent* event,
+                        std::unique_ptr<EventResultCallback> ack_callback);
 
   // Overridden from ui::InputMethod:
   void OnFocus() override;
@@ -47,17 +50,23 @@
   bool IsCandidatePopupOpen() const override;
 
  private:
+  friend class InputMethodMusTestApi;
   friend TextInputClientImpl;
 
+  // Called from DispatchKeyEvent() to call to the InputMethod.
+  void SendKeyEventToInputMethod(
+      const ui::KeyEvent& event,
+      std::unique_ptr<EventResultCallback> ack_callback);
+
   // Overridden from ui::InputMethodBase:
   void OnDidChangeFocusedClient(ui::TextInputClient* focused_before,
                                 ui::TextInputClient* focused) override;
 
   void UpdateTextInputType();
+
+  // Called when the server responds to our request to process an event.
   void ProcessKeyEventCallback(
       const ui::KeyEvent& event,
-      std::unique_ptr<base::Callback<void(ui::mojom::EventResult)>>
-          ack_callback,
       bool handled);
 
   // The toplevel window which is not owned by this class. This may be null
@@ -66,9 +75,17 @@
 
   // May be null in tests.
   ui::mojom::IMEServerPtr ime_server_;
-  ui::mojom::InputMethodPtr input_method_;
+  ui::mojom::InputMethodPtr input_method_ptr_;
+  // Typically this is the same as |input_method_ptr_|, but it may be mocked
+  // in tests.
+  ui::mojom::InputMethod* input_method_ = nullptr;
   std::unique_ptr<TextInputClientImpl> text_input_client_;
 
+  // Callbacks supplied to DispatchKeyEvent() are added here while awaiting
+  // the response from the server. These are removed when the response is
+  // received (ProcessKeyEventCallback()).
+  std::deque<std::unique_ptr<EventResultCallback>> pending_callbacks_;
+
   DISALLOW_COPY_AND_ASSIGN(InputMethodMus);
 };
 
diff --git a/ui/aura/mus/input_method_mus_unittest.cc b/ui/aura/mus/input_method_mus_unittest.cc
new file mode 100644
index 0000000..19bcb38
--- /dev/null
+++ b/ui/aura/mus/input_method_mus_unittest.cc
@@ -0,0 +1,121 @@
+// 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 "ui/aura/mus/input_method_mus.h"
+
+#include "services/ui/public/interfaces/ime/ime.mojom.h"
+#include "ui/aura/test/aura_test_base.h"
+#include "ui/aura/window.h"
+#include "ui/base/ime/input_method_delegate.h"
+
+namespace aura {
+namespace {
+
+// Empty implementation of InputMethodDelegate.
+class TestInputMethodDelegate : public ui::internal::InputMethodDelegate {
+ public:
+  TestInputMethodDelegate() {}
+  ~TestInputMethodDelegate() override {}
+
+  // ui::internal::InputMethodDelegate:
+  ui::EventDispatchDetails DispatchKeyEventPostIME(ui::KeyEvent* key) override {
+    return ui::EventDispatchDetails();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestInputMethodDelegate);
+};
+
+using ProcessKeyEventCallback = base::Callback<void(bool)>;
+using ProcessKeyEventCallbacks = std::vector<ProcessKeyEventCallback>;
+using EventResultCallback = base::Callback<void(ui::mojom::EventResult)>;
+
+// InputMethod implementation that queues up the callbacks supplied to
+// ProcessKeyEvent().
+class TestInputMethod : public ui::mojom::InputMethod {
+ public:
+  TestInputMethod() {}
+  ~TestInputMethod() override {}
+
+  ProcessKeyEventCallbacks* process_key_event_callbacks() {
+    return &process_key_event_callbacks_;
+  }
+
+  // ui::ime::InputMethod:
+  void OnTextInputTypeChanged(ui::TextInputType text_input_type) override {}
+  void OnCaretBoundsChanged(const gfx::Rect& caret_bounds) override {}
+  void ProcessKeyEvent(std::unique_ptr<ui::Event> key_event,
+                       const ProcessKeyEventCallback& callback) override {
+    process_key_event_callbacks_.push_back(callback);
+  }
+  void CancelComposition() override {}
+
+ private:
+  ProcessKeyEventCallbacks process_key_event_callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestInputMethod);
+};
+
+}  // namespace
+
+using InputMethodMusTest = test::AuraTestBaseMus;
+
+class InputMethodMusTestApi {
+ public:
+  static void SetInputMethod(InputMethodMus* input_method_mus,
+                             ui::mojom::InputMethod* input_method) {
+    input_method_mus->input_method_ = input_method;
+  }
+  static void CallSendKeyEventToInputMethod(
+      InputMethodMus* input_method_mus,
+      const ui::KeyEvent& event,
+      std::unique_ptr<EventResultCallback> ack_callback) {
+    input_method_mus->SendKeyEventToInputMethod(event, std::move(ack_callback));
+  }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(InputMethodMusTestApi);
+};
+
+namespace {
+
+// Used in closure supplied to processing the event.
+void RunFunctionWithEventResult(bool* was_run, ui::mojom::EventResult result) {
+  *was_run = true;
+}
+
+}  // namespace
+
+TEST_F(InputMethodMusTest, PendingCallbackRunFromDestruction) {
+  aura::Window window(nullptr);
+  window.Init(ui::LAYER_NOT_DRAWN);
+  bool was_event_result_callback_run = false;
+  // Create an InputMethodMus and foward an event to it.
+  {
+    TestInputMethodDelegate input_method_delegate;
+    InputMethodMus input_method_mus(&input_method_delegate, &window);
+    TestInputMethod test_input_method;
+    InputMethodMusTestApi::SetInputMethod(&input_method_mus,
+                                          &test_input_method);
+    std::unique_ptr<EventResultCallback> callback =
+        base::MakeUnique<EventResultCallback>(base::Bind(
+            &RunFunctionWithEventResult, &was_event_result_callback_run));
+    InputMethodMusTestApi::CallSendKeyEventToInputMethod(
+        &input_method_mus, ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0),
+        std::move(callback));
+    // Add a null callback as well, to make sure null is deal with.
+    InputMethodMusTestApi::CallSendKeyEventToInputMethod(
+        &input_method_mus, ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_RETURN, 0),
+        nullptr);
+    // The event should have been queued.
+    EXPECT_EQ(2u, test_input_method.process_key_event_callbacks()->size());
+    // Callback should not have been run yet.
+    EXPECT_FALSE(was_event_result_callback_run);
+  }
+
+  // When the destructor is run the callback should be run.
+  EXPECT_TRUE(was_event_result_callback_run);
+}
+
+}  // namespace aura
diff --git a/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc b/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
index 75d6e7d..b3b5cfc 100644
--- a/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
+++ b/ui/aura/mus/os_exchange_data_provider_mus_unittest.cc
@@ -190,7 +190,6 @@
   EXPECT_EQ(2, value);
 }
 
-#if defined(USE_AURA)
 TEST_F(OSExchangeDataProviderMusTest, TestHTML) {
   OSExchangeData data;
   GURL url("http://www.google.com/");
@@ -206,6 +205,5 @@
   EXPECT_TRUE(copy.GetHtml(&read_html, &url));
   EXPECT_EQ(html, read_html);
 }
-#endif
 
 }  // namespace aura
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc
index ac8a12b..d8ab8b1 100644
--- a/ui/aura/mus/window_port_mus.cc
+++ b/ui/aura/mus/window_port_mus.cc
@@ -224,8 +224,6 @@
 }
 
 void WindowPortMus::SetOpacityFromServer(float opacity) {
-  // TODO(sky): route to server.
-  // Changes to opacity don't make it back to the server.
   window_->layer()->SetOpacity(opacity);
 }
 
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index ec6baf2..3f69a8f 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -1683,6 +1683,15 @@
                         out_rect);
 }
 
+void WindowTreeClient::OnWindowTreeHostSetOpacity(
+    WindowTreeHostMus* window_tree_host,
+    float opacity) {
+  WindowMus* window = WindowMus::Get(window_tree_host->window());
+  const uint32_t change_id = ScheduleInFlightChange(
+      base::MakeUnique<CrashInFlightChange>(window, ChangeType::OPACITY));
+  tree_->SetWindowOpacity(change_id, window->server_id(), opacity);
+}
+
 void WindowTreeClient::OnWindowTreeHostDeactivateWindow(
     WindowTreeHostMus* window_tree_host) {
   tree_->DeactivateWindow(
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index 4640e87a..3ab40e1 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -434,6 +434,8 @@
   void OnWindowTreeHostHitTestMaskWillChange(
       WindowTreeHostMus* window_tree_host,
       const base::Optional<gfx::Rect>& mask_rect) override;
+  void OnWindowTreeHostSetOpacity(WindowTreeHostMus* window_tree_host,
+                                  float opacity) override;
   void OnWindowTreeHostDeactivateWindow(
       WindowTreeHostMus* window_tree_host) override;
   void OnWindowTreeHostStackAbove(WindowTreeHostMus* window_tree_host,
diff --git a/ui/aura/mus/window_tree_host_mus.cc b/ui/aura/mus/window_tree_host_mus.cc
index 07c720c..6e157245 100644
--- a/ui/aura/mus/window_tree_host_mus.cc
+++ b/ui/aura/mus/window_tree_host_mus.cc
@@ -146,6 +146,10 @@
   delegate_->OnWindowTreeHostHitTestMaskWillChange(this, rect);
 }
 
+void WindowTreeHostMus::SetOpacity(float value) {
+  delegate_->OnWindowTreeHostSetOpacity(this, value);
+}
+
 void WindowTreeHostMus::DeactivateWindow() {
   delegate_->OnWindowTreeHostDeactivateWindow(this);
 }
diff --git a/ui/aura/mus/window_tree_host_mus.h b/ui/aura/mus/window_tree_host_mus.h
index 499d793..5f1642c 100644
--- a/ui/aura/mus/window_tree_host_mus.h
+++ b/ui/aura/mus/window_tree_host_mus.h
@@ -73,6 +73,9 @@
   // clear.
   void SetHitTestMask(const base::Optional<gfx::Rect>& rect);
 
+  // Sets the opacity of the underlying mus window.
+  void SetOpacity(float value);
+
   // Requests that the window manager change the activation to the next window.
   void DeactivateWindow();
 
diff --git a/ui/aura/mus/window_tree_host_mus_delegate.h b/ui/aura/mus/window_tree_host_mus_delegate.h
index 08d8f58..b93c6598 100644
--- a/ui/aura/mus/window_tree_host_mus_delegate.h
+++ b/ui/aura/mus/window_tree_host_mus_delegate.h
@@ -42,6 +42,10 @@
       WindowTreeHostMus* window_tree_host,
       const base::Optional<gfx::Rect>& mask_rect) = 0;
 
+  // Called when the opacity is changed client side.
+  virtual void OnWindowTreeHostSetOpacity(WindowTreeHostMus* window_tree_host,
+                                          float opacity) = 0;
+
   // Called to clear the focus of the current window.
   virtual void OnWindowTreeHostDeactivateWindow(
       WindowTreeHostMus* window_tree_host) = 0;
diff --git a/ui/base/cocoa/three_part_image_unittest.mm b/ui/base/cocoa/three_part_image_unittest.mm
index 9632490..a517ae33 100644
--- a/ui/base/cocoa/three_part_image_unittest.mm
+++ b/ui/base/cocoa/three_part_image_unittest.mm
@@ -7,9 +7,13 @@
 #include <memory>
 
 #include "testing/gtest_mac.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkRect.h"
 #include "ui/base/resource/resource_bundle.h"
-#import "ui/gfx/test/ui_cocoa_test_helper.h"
+#include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_unittest_util.h"
+#import "ui/gfx/test/ui_cocoa_test_helper.h"
 #include "ui/resources/grit/ui_resources.h"
 
 namespace ui {
@@ -48,26 +52,33 @@
 }
 
 TEST(ThreePartImageTest, HitTest) {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  base::scoped_nsobject<NSImage> leftImage(
-      rb.GetNativeImageNamed(IDR_BACK_ARROW).CopyNSImage());
-  base::scoped_nsobject<NSImage> rightImage(
-      rb.GetNativeImageNamed(IDR_FORWARD_ARROW).CopyNSImage());
-  ThreePartImage image(leftImage, nullptr, rightImage);
-  NSRect bounds = NSMakeRect(0, 0, 512, 128);
+  // Create a bitmap with transparent top and bottom.
+  const int size = 128;
+  const int corner_size = 8;
+  SkBitmap bitmap = gfx::test::CreateBitmap(size, size);
+  // Clear top and bottom.
+  bitmap.erase(SK_ColorTRANSPARENT, SkIRect::MakeXYWH(0, 0, size, corner_size));
+  bitmap.erase(SK_ColorTRANSPARENT,
+               SkIRect::MakeXYWH(0, size - corner_size, size, corner_size));
+  gfx::Image part_image = gfx::Image::CreateFrom1xBitmap(bitmap);
 
-  // The middle of the arrows are hits.
-  EXPECT_TRUE(image.HitTest(NSMakePoint(64, 64), bounds));
-  EXPECT_TRUE(image.HitTest(NSMakePoint(448, 64), bounds));
+  // Create a three-part image.
+  base::scoped_nsobject<NSImage> ns_image(part_image.CopyNSImage());
+  ThreePartImage image(ns_image, nullptr, ns_image);
+  NSRect bounds = NSMakeRect(0, 0, 4 * size, size);
+
+  // The middle of the left and right parts are hits.
+  EXPECT_TRUE(image.HitTest(NSMakePoint(size / 2, size / 2), bounds));
+  EXPECT_TRUE(image.HitTest(NSMakePoint(7 * size / 2, size / 2), bounds));
 
   // No middle image means the middle rect is a hit.
-  EXPECT_TRUE(image.HitTest(NSMakePoint(256, 64), bounds));
+  EXPECT_TRUE(image.HitTest(NSMakePoint(2 * size, size / 2), bounds));
 
   // The corners are transparent.
   EXPECT_FALSE(image.HitTest(NSMakePoint(0, 0), bounds));
-  EXPECT_FALSE(image.HitTest(NSMakePoint(0, 127), bounds));
-  EXPECT_FALSE(image.HitTest(NSMakePoint(511, 0), bounds));
-  EXPECT_FALSE(image.HitTest(NSMakePoint(511, 127), bounds));
+  EXPECT_FALSE(image.HitTest(NSMakePoint(0, size - 1), bounds));
+  EXPECT_FALSE(image.HitTest(NSMakePoint(4 * size - 1, 0), bounds));
+  EXPECT_FALSE(image.HitTest(NSMakePoint(4 * size - 1, size - 1), bounds));
 }
 
 }  // namespace test
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js
index 8781ea15..6f834c04 100644
--- a/ui/file_manager/audio_player/js/audio_player.js
+++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -14,7 +14,7 @@
  */
 function AudioPlayer(container) {
   this.container_ = container;
-  this.volumeManager_ = new VolumeManagerWrapper(AllowedPaths.ANY_PATH);
+  this.volumeManager_ = new VolumeManagerWrapper(AllowedPaths.ANY_PATH, false);
   this.metadataModel_ = MetadataModel.create(this.volumeManager_);
   this.selectedEntry_ = null;
   this.invalidTracks_ = {};
diff --git a/ui/file_manager/file_manager/foreground/css/common.css b/ui/file_manager/file_manager/foreground/css/common.css
index d212ea9..66ea9ad 100644
--- a/ui/file_manager/file_manager/foreground/css/common.css
+++ b/ui/file_manager/file_manager/foreground/css/common.css
@@ -227,7 +227,7 @@
   outline: none;
 }
 
-@-webkit-keyframes pulse {
+@keyframes pulse {
  0% {
    transform: scale(1);
  }
@@ -243,10 +243,10 @@
 }
 
 .cr-dialog-frame.pulse {
-  -webkit-animation-duration: 180ms;
-  -webkit-animation-iteration-count: 1;
-  -webkit-animation-name: pulse;
-  -webkit-animation-timing-function: ease-in-out;
+  animation-duration: 180ms;
+  animation-iteration-count: 1;
+  animation-name: pulse;
+  animation-timing-function: ease-in-out;
 }
 
 .shown > .cr-dialog-frame {
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index b3c82b2c..c17d4c2c 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1086,7 +1086,7 @@
   height: 0;
 }
 
-@-webkit-keyframes heightAnimation {
+@keyframes heightAnimation {
   0% {
     display: flex;
     height: 0;
@@ -1095,8 +1095,8 @@
 
 /* Drive space warning banner. */
 .volume-warning {
-  -webkit-animation: heightAnimation 70ms linear;
   align-items: center;
+  animation: heightAnimation 70ms linear;
   background-color: rgb(79, 129, 232);
   color: white;
   display: flex;
@@ -1302,7 +1302,7 @@
 }
 
 .thumbnail-grid .img-container > .thumbnail.animate {
-  -webkit-animation: fadeIn 250ms linear;
+  animation: fadeIn 250ms linear;
 }
 
 .thumbnail-grid .shield {
@@ -1422,10 +1422,10 @@
 #directory-tree .tree-item.accepts > .tree-row,
 #list-container list > li.accepts,
 #list-container grid > li.accepts {
-  -webkit-animation: acceptsBlink 200ms linear 1s 3;
+  animation: acceptsBlink 200ms linear 1s 3;
 }
 
-@-webkit-keyframes acceptsBlink {
+@keyframes acceptsBlink {
   0% {
     color: rgb(90, 90, 90);
     background-color: transparent;
@@ -1495,7 +1495,7 @@
   justify-content: flex-end;
 }
 
-@-webkit-keyframes fadeIn {
+@keyframes fadeIn {
   from {
     opacity: 0;
   }
@@ -1504,7 +1504,7 @@
   }
 }
 
-@-webkit-keyframes fadeOut {
+@keyframes fadeOut {
   from {
     opacity: 1;
   }
@@ -1666,13 +1666,13 @@
 }
 
 #list-container list li .detail-thumbnail > .thumbnail.animate {
-  -webkit-animation: fadeIn 220ms ease;
+  animation: fadeIn 220ms ease;
 }
 
 body.check-select #list-container list li[selected] .detail-thumbnail
 > .thumbnail {
   /* Fade out after checkmark fades in. */
-  -webkit-animation: fadeOut 0ms 220ms ease backwards;
+  animation: fadeOut 0ms 220ms ease backwards;
   opacity: 0;
 }
 
@@ -2056,7 +2056,7 @@
 
 /* Progress center */
 
-@-webkit-keyframes progress-center-toggle {
+@keyframes progress-center-toggle {
   /* Height values of each frame are set by script.
    * Keep the animation sync with JS. */
   from {
@@ -2075,7 +2075,7 @@
 }
 
 #progress-center.animated {
-  -webkit-animation: progress-center-toggle 300ms ease-out;
+  animation: progress-center-toggle 300ms ease-out;
 }
 
 #progress-center-open-view {
diff --git a/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.html b/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.html
index 6bbd82a..e6b2bc22 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.html
+++ b/ui/file_manager/file_manager/foreground/elements/files_metadata_entry.html
@@ -48,7 +48,6 @@
     }
 
     #value[loading]:after {
-      -webkit-animation: ellipsis steps(4,end) 900ms infinite;
       animation: ellipsis steps(4,end) 900ms infinite;
       content: "\2026"; /* ascii code for the ellipsis character */
       display: inline-block;
@@ -63,7 +62,7 @@
       }
     }
 
-    @-webkit-keyframes ellipsis {
+    @keyframes ellipsis {
       to {
         width: 1.25em;
       }
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 49f6153..45251ce 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -815,6 +815,9 @@
       }
     }
 
+    var writableOnly =
+        this.launchParams_.type === DialogType.SELECT_SAVEAS_FILE;
+
     // VolumeManagerWrapper hides virtual file system related event and data
     // even depends on the value of |supportVirtualPath|. If it is
     // VirtualPathSupport.NO_VIRTUAL_PATH, it hides Drive even if Drive is
@@ -825,7 +828,7 @@
     // Note that the Drive enabling preference change is listened by
     // DriveIntegrationService, so here we don't need to take care about it.
     this.volumeManager_ = new VolumeManagerWrapper(
-        allowedPaths, this.backgroundPage_);
+        allowedPaths, writableOnly, this.backgroundPage_);
   };
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js b/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
index fc1bbbf6..b035356 100644
--- a/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/gear_menu_controller.js
@@ -91,7 +91,9 @@
 
   // TODO(mtomasz): Add support for remaining space indication for provided
   // file systems.
-  if (currentVolumeInfo.volumeType == VolumeManagerCommon.VolumeType.PROVIDED) {
+  if (currentVolumeInfo.volumeType == VolumeManagerCommon.VolumeType.PROVIDED ||
+      currentVolumeInfo.volumeType ==
+          VolumeManagerCommon.VolumeType.MEDIA_VIEW) {
     this.gearMenu_.setSpaceInfo(null, false);
     return;
   }
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index dca897e..e154cdb 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -684,7 +684,7 @@
     thumbnail.style.backgroundSize = 'cover';
 
   thumbnail.style.backgroundImage = 'url(' + dataUrl + ')';
-  thumbnail.addEventListener('webkitAnimationEnd', function() {
+  thumbnail.addEventListener('animationend', function() {
     // Remove animation css once animation is completed in order not to animate
     // again when an item is attached to the dom again.
     thumbnail.classList.remove('animate');
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index e5ef783..1dae4d4 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -961,7 +961,7 @@
   var thumbnail = box.ownerDocument.createElement('div');
   thumbnail.classList.add('thumbnail');
   thumbnail.style.backgroundImage = 'url(' + dataUrl + ')';
-  thumbnail.addEventListener('webkitAnimationEnd', function() {
+  thumbnail.addEventListener('animationend', function() {
     // Remove animation css once animation is completed in order not to animate
     // again when an item is attached to the dom again.
     thumbnail.classList.remove('animate');
diff --git a/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js b/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
index 6d498d9..6bc88e62 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/progress_center_panel.js
@@ -260,7 +260,7 @@
   // Register event handlers.
   element.addEventListener('click', this.onClick_.bind(this));
   element.addEventListener(
-      'webkitAnimationEnd', this.onToggleAnimationEnd_.bind(this));
+      'animationend', this.onToggleAnimationEnd_.bind(this));
   element.addEventListener(
       ProgressCenterItemElement.PROGRESS_ANIMATION_END_EVENT,
       this.onItemAnimationEnd_.bind(this));
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 bb356d87..42e4247 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
@@ -4,8 +4,9 @@
 
 /**
  * Thin wrapper for VolumeManager. This should be an interface proxy to talk
- * to VolumeManager. This class also filters Drive related data/events if
- * driveEnabled is set to false.
+ * to VolumeManager. This class also filters some "disallowed" volumes;
+ * for example, Drive volumes are dropped if Drive is disabled, and read-only
+ * volumes are dropped in save-as dialogs.
  *
  * @constructor
  * @extends {cr.EventTarget}
@@ -13,15 +14,17 @@
  *
  * @param {!AllowedPaths} allowedPaths Which paths are supported in the Files
  *     app dialog.
+ * @param {boolean} writableOnly If true, only writable volumes are returned.
  * @param {Window=} opt_backgroundPage Window object of the background
  *     page. If this is specified, the class skips to get background page.
  *     TOOD(hirono): Let all clients of the class pass the background page and
  *     make the argument not optional.
  */
-function VolumeManagerWrapper(allowedPaths, opt_backgroundPage) {
+function VolumeManagerWrapper(allowedPaths, writableOnly, opt_backgroundPage) {
   cr.EventTarget.call(this);
 
   this.allowedPaths_ = allowedPaths;
+  this.writableOnly_ = writableOnly;
   this.volumeInfoList = new cr.ui.ArrayDataModel([]);
 
   this.volumeManager_ = null;
@@ -62,28 +65,43 @@
 VolumeManagerWrapper.prototype.__proto__ = cr.EventTarget.prototype;
 
 /**
+ * Checks if a volume type is allowed.
+ *
+ * Note that even if a volume type is allowed, a volume of that type might be
+ * disallowed for other restrictions. To check if a specific volume is allowed
+ * or not, use isAllowedVolume_() instead.
+ *
  * @param {VolumeManagerCommon.VolumeType} volumeType
  * @return {boolean}
  */
-VolumeManagerWrapper.prototype.isAllowedVolume_ = function(volumeType) {
-  if (this.allowedPaths_ === AllowedPaths.ANY_PATH)
-    return true;
-
-  if (this.allowedPaths_ === AllowedPaths.NATIVE_OR_DRIVE_PATH &&
-      (VolumeManagerCommon.VolumeType.isNative(volumeType) ||
-       volumeType == VolumeManagerCommon.VolumeType.DRIVE)) {
-    return true;
+VolumeManagerWrapper.prototype.isAllowedVolumeType_ = function(volumeType) {
+  switch (this.allowedPaths_) {
+    case AllowedPaths.ANY_PATH:
+      return true;
+    case AllowedPaths.NATIVE_OR_DRIVE_PATH:
+      return (VolumeManagerCommon.VolumeType.isNative(volumeType) ||
+              volumeType == VolumeManagerCommon.VolumeType.DRIVE);
+    case AllowedPaths.NATIVE_PATH:
+      return VolumeManagerCommon.VolumeType.isNative(volumeType);
   }
-
-  if (this.allowedPaths_ === AllowedPaths.NATIVE_PATH &&
-      VolumeManagerCommon.VolumeType.isNative(volumeType)) {
-    return true;
-  }
-
   return false;
 };
 
 /**
+ * Checks if a volume is allowed.
+ *
+ * @param {!VolumeInfo} volumeInfo
+ * @return {boolean}
+ */
+VolumeManagerWrapper.prototype.isAllowedVolume_ = function(volumeInfo) {
+  if (!this.isAllowedVolumeType_(volumeInfo.volumeType))
+    return false;
+  if (this.writableOnly_ && volumeInfo.isReadOnly)
+    return false;
+  return true;
+};
+
+/**
  * Called when the VolumeManager gets ready for post initialization.
  * @param {VolumeManager} volumeManager The initialized VolumeManager instance.
  * @private
@@ -110,7 +128,7 @@
   for (var i = 0; i < this.volumeManager_.volumeInfoList.length; i++) {
     var volumeInfo = this.volumeManager_.volumeInfoList.item(i);
     // TODO(hidehiko): Filter mounted volumes located on Drive File System.
-    if (!this.isAllowedVolume_(volumeInfo.volumeType))
+    if (!this.isAllowedVolume_(volumeInfo))
       continue;
     volumeInfoList.push(volumeInfo);
   }
@@ -154,19 +172,17 @@
  * @private
  */
 VolumeManagerWrapper.prototype.onEvent_ = function(event) {
-  var eventVolumeType;
   switch (event.type) {
     case 'drive-connection-changed':
-      eventVolumeType = VolumeManagerCommon.VolumeType.DRIVE;
+      if (this.isAllowedVolumeType_(VolumeManagerCommon.VolumeType.DRIVE))
+        this.dispatchEvent(event);
       break;
     case 'externally-unmounted':
       event = /** @type {!ExternallyUnmountedEvent} */ (event);
-      eventVolumeType = event.volumeInfo.volumeType;
+      if (this.isAllowedVolume_(event.volumeInfo))
+        this.dispatchEvent(event);
       break;
   }
-
-  if (eventVolumeType && this.isAllowedVolume_(eventVolumeType))
-    this.dispatchEvent(event);
 };
 
 /**
@@ -175,32 +191,25 @@
  * @private
  */
 VolumeManagerWrapper.prototype.onVolumeInfoListUpdated_ = function(event) {
-  if (this.allowedPaths_ === AllowedPaths.ANY_PATH) {
-    // Apply the splice as is.
-    this.volumeInfoList.splice.apply(
-         this.volumeInfoList,
-         [event.index, event.removed.length].concat(event.added));
-    return;
-  }
-
-  // Filters Drive related volumes.
+  // Filters some volumes.
   var index = event.index;
   for (var i = 0; i < event.index; i++) {
-    var volumeType = this.volumeManager_.volumeInfoList.item(i).volumeType;
-    if (!this.isAllowedVolume_(volumeType))
+    var volumeInfo = this.volumeManager_.volumeInfoList.item(i);
+    if (!this.isAllowedVolume_(volumeInfo))
       index--;
   }
 
   var numRemovedVolumes = 0;
   for (var i = 0; i < event.removed.length; i++) {
-    if (this.isAllowedVolume_(event.removed[i].volumeType))
+    var volumeInfo = event.removed[i];
+    if (this.isAllowedVolume_(volumeInfo))
       numRemovedVolumes++;
   }
 
   var addedVolumes = [];
   for (var i = 0; i < event.added.length; i++) {
     var volumeInfo = event.added[i];
-    if (this.isAllowedVolume_(volumeInfo.volumeType)) {
+    if (this.isAllowedVolume_(volumeInfo)) {
       addedVolumes.push(volumeInfo);
     }
   }
@@ -237,7 +246,7 @@
  *     state.
  */
 VolumeManagerWrapper.prototype.getDriveConnectionState = function() {
-  if (!this.isAllowedVolume_(VolumeManagerCommon.VolumeType.DRIVE) ||
+  if (!this.isAllowedVolumeType_(VolumeManagerCommon.VolumeType.DRIVE) ||
       !this.volumeManager_) {
     return {
       type: VolumeManagerCommon.DriveConnectionType.OFFLINE,
@@ -250,7 +259,7 @@
 
 /** @override */
 VolumeManagerWrapper.prototype.getVolumeInfo = function(entry) {
-  return this.filterDisabledVolume_(
+  return this.filterDisallowedVolume_(
       this.volumeManager_ && this.volumeManager_.getVolumeInfo(entry));
 };
 
@@ -261,7 +270,7 @@
  */
 VolumeManagerWrapper.prototype.getCurrentProfileVolumeInfo =
     function(volumeType) {
-  return this.filterDisabledVolume_(
+  return this.filterDisallowedVolume_(
       this.volumeManager_ &&
       this.volumeManager_.getCurrentProfileVolumeInfo(volumeType));
 };
@@ -294,7 +303,7 @@
       this.volumeManager_ && this.volumeManager_.getLocationInfo(entry);
   if (!locationInfo)
     return null;
-  if (!this.filterDisabledVolume_(locationInfo.volumeInfo))
+  if (!this.filterDisallowedVolume_(locationInfo.volumeInfo))
     return null;
   return locationInfo;
 };
@@ -355,16 +364,16 @@
 };
 
 /**
- * Filters volume info by referring allowedPaths_.
+ * Filters volume info by isAllowedVolume_().
  *
  * @param {VolumeInfo} volumeInfo Volume info.
- * @return {VolumeInfo} Null if the volume is disabled. Otherwise just returns
+ * @return {VolumeInfo} Null if the volume is disallowed. Otherwise just returns
  *     the volume.
  * @private
  */
-VolumeManagerWrapper.prototype.filterDisabledVolume_ =
+VolumeManagerWrapper.prototype.filterDisallowedVolume_ =
     function(volumeInfo) {
-  if (volumeInfo && this.isAllowedVolume_(volumeInfo.volumeType)) {
+  if (volumeInfo && this.isAllowedVolume_(volumeInfo)) {
     return volumeInfo;
   } else {
     return null;
diff --git a/ui/file_manager/gallery/css/gallery.css b/ui/file_manager/gallery/css/gallery.css
index 70bec09a..e7583f2 100644
--- a/ui/file_manager/gallery/css/gallery.css
+++ b/ui/file_manager/gallery/css/gallery.css
@@ -51,8 +51,8 @@
 }
 
 .bubble .pointer.bottom {
-  transform: rotate(180deg);
   bottom: -11px;
+  transform: rotate(180deg);
 }
 
 .bubble .close-x {
@@ -464,10 +464,10 @@
 }
 
 .gallery .image-wrapper > img:not(.cached) {
-  -webkit-animation: fadeIn 500ms ease-in;
+  animation: fadeIn 500ms ease-in;
 }
 
-@-webkit-keyframes fadeIn {
+@keyframes fadeIn {
   from {
     opacity: 0;
   }
@@ -571,8 +571,8 @@
 }
 
 .gallery .edit-mode-toolbar .saved[highlighted] {
-  transform: scaleX(1.1) scaleY(1.1) rotate(0);
   opacity: 1;
+  transform: scaleX(1.1) scaleY(1.1) rotate(0);
 }
 
 /* Editor buttons. */
diff --git a/ui/file_manager/gallery/js/gallery.js b/ui/file_manager/gallery/js/gallery.js
index 79cae82a..4f986de4 100644
--- a/ui/file_manager/gallery/js/gallery.js
+++ b/ui/file_manager/gallery/js/gallery.js
@@ -1064,7 +1064,7 @@
  * @type {!Promise}
  */
 var volumeManagerPromise = new Promise(function(fulfill, reject) {
-  var volumeManager = new VolumeManagerWrapper(AllowedPaths.ANY_PATH);
+  var volumeManager = new VolumeManagerWrapper(AllowedPaths.ANY_PATH, false);
   volumeManager.ensureInitialized(fulfill.bind(null, volumeManager));
 });
 
diff --git a/ui/file_manager/video_player/css/media_controls.css b/ui/file_manager/video_player/css/media_controls.css
index 6c0ff616..1e55df19 100644
--- a/ui/file_manager/video_player/css/media_controls.css
+++ b/ui/file_manager/video_player/css/media_controls.css
@@ -136,8 +136,8 @@
   background-image: -webkit-image-set(
     url(../images/media/media_chromecast.png) 1x,
     url(../images/media/2x/media_chromecast.png) 2x);
-  display: none;
   border-radius: 2px;
+  display: none;
 }
 
 /* Reset browser's button style. */
@@ -194,7 +194,7 @@
 }
 
 .playback-state-icon {
-  -webkit-animation: none;
+  animation: none;
   background-position: center center;
   background-repeat: no-repeat;
   display: none;
@@ -230,7 +230,7 @@
 }
 
 .text-banner[visible] {
-  -webkit-animation: text-banner-blowup 3000ms;
+  animation: text-banner-blowup 3000ms;
   display: block;
 }
 
@@ -238,44 +238,44 @@
   display: block;
 }
 
-@-webkit-keyframes blowup {
+@keyframes blowup {
   from {
     opacity: 1;
   }
   to {
-    transform: scale(3);
     opacity: 0;
+    transform: scale(3);
   }
 }
 
-@-webkit-keyframes text-banner-blowup {
+@keyframes text-banner-blowup {
   from {
-    transform: scale(0.5);
     opacity: 0;
+    transform: scale(0.5);
   }
   20% {
-    transform: scale(1);
     opacity: 0.75;
+    transform: scale(1);
   }
   80% {
-    transform: scale(1);
     opacity: 0.75;
+    transform: scale(1);
   }
   to {
-    transform: scale(3);
     opacity: 0;
+    transform: scale(3);
   }
 }
 
 .playback-state-icon[state='play'] {
-  -webkit-animation: blowup 500ms;
+  animation: blowup 500ms;
   background-image: -webkit-image-set(
     url(../images/media/media_play_onscreen.png) 1x,
     url(../images/media/2x/media_play_onscreen.png) 2x);
 }
 
 .playback-state-icon[state='pause'] {
-  -webkit-animation: blowup 500ms;
+  animation: blowup 500ms;
   background-image: -webkit-image-set(
     url(../images/media/media_pause_onscreen.png) 1x,
     url(../images/media/2x/media_pause_onscreen.png) 2x);
diff --git a/ui/file_manager/video_player/js/media_controls.js b/ui/file_manager/video_player/js/media_controls.js
index de0b827..aa49c92 100644
--- a/ui/file_manager/video_player/js/media_controls.js
+++ b/ui/file_manager/video_player/js/media_controls.js
@@ -1038,9 +1038,9 @@
       if (stateIcon.getAttribute('state') === state)
         stateIcon.removeAttribute('state');
 
-      stateIcon.removeEventListener('webkitAnimationEnd', onAnimationEnd);
+      stateIcon.removeEventListener('animationend', onAnimationEnd);
     }.bind(null, newState);
-    stateIcon.addEventListener('webkitAnimationEnd', onAnimationEnd);
+    stateIcon.addEventListener('animationend', onAnimationEnd);
 
     // Shows the icon with animation.
     stateIcon.setAttribute('state', newState);
@@ -1060,10 +1060,10 @@
   setTimeout(function() {
     var onAnimationEnd = function(event) {
       this.textBanner_.removeEventListener(
-          'webkitAnimationEnd', onAnimationEnd);
+          'animationend', onAnimationEnd);
       this.textBanner_.removeAttribute('visible');
     }.bind(this);
-    this.textBanner_.addEventListener('webkitAnimationEnd', onAnimationEnd);
+    this.textBanner_.addEventListener('animationend', onAnimationEnd);
 
     this.textBanner_.setAttribute('visible', 'true');
   }.bind(this), 0);
diff --git a/ui/file_manager/video_player/js/video_player.js b/ui/file_manager/video_player/js/video_player.js
index 48a7d1c..a3dd0a33 100644
--- a/ui/file_manager/video_player/js/video_player.js
+++ b/ui/file_manager/video_player/js/video_player.js
@@ -800,7 +800,7 @@
 }
 
 function initVolumeManager(callback) {
-  var volumeManager = new VolumeManagerWrapper(AllowedPaths.ANY_PATH);
+  var volumeManager = new VolumeManagerWrapper(AllowedPaths.ANY_PATH, false);
   volumeManager.ensureInitialized(callback);
 }
 
diff --git a/ui/gfx/color_space.h b/ui/gfx/color_space.h
index c7792cbb..d0fe36e8 100644
--- a/ui/gfx/color_space.h
+++ b/ui/gfx/color_space.h
@@ -89,10 +89,10 @@
     // display.
     SMPTEST2084_NON_HDR,
 
-    // TODO(hubbe): Need to store an approximation of the gamma function(s).
-    CUSTOM,
     // Like LINEAR, but intended for HDR. (can go outside of 0-1)
     LINEAR_HDR,
+    // TODO(hubbe): Need to store an approximation of the gamma function(s).
+    CUSTOM,
     LAST = CUSTOM,
   };
 
diff --git a/ui/gfx/mojo/buffer_types.typemap b/ui/gfx/mojo/buffer_types.typemap
index d357458..ca27a08 100644
--- a/ui/gfx/mojo/buffer_types.typemap
+++ b/ui/gfx/mojo/buffer_types.typemap
@@ -8,9 +8,9 @@
   "//ui/gfx/gpu_memory_buffer.h",
   "//ui/gfx/native_pixmap_handle.h",
 ]
-traits_headers = [ "//ui/gfx/mojo/buffer_types_traits.h" ]
+traits_headers = [ "//ui/gfx/mojo/buffer_types_struct_traits.h" ]
 sources = [
-  "//ui/gfx/mojo/buffer_types_traits.cc",
+  "//ui/gfx/mojo/buffer_types_struct_traits.cc",
 ]
 public_deps = [
   "//ui/gfx",
diff --git a/ui/gfx/mojo/buffer_types_traits.cc b/ui/gfx/mojo/buffer_types_struct_traits.cc
similarity index 98%
rename from ui/gfx/mojo/buffer_types_traits.cc
rename to ui/gfx/mojo/buffer_types_struct_traits.cc
index 540326f..fbe8ee2 100644
--- a/ui/gfx/mojo/buffer_types_traits.cc
+++ b/ui/gfx/mojo/buffer_types_struct_traits.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 "ui/gfx/mojo/buffer_types_traits.h"
+#include "ui/gfx/mojo/buffer_types_struct_traits.h"
 
 #include "mojo/public/cpp/system/platform_handle.h"
 
diff --git a/ui/gfx/mojo/buffer_types_traits.h b/ui/gfx/mojo/buffer_types_struct_traits.h
similarity index 98%
rename from ui/gfx/mojo/buffer_types_traits.h
rename to ui/gfx/mojo/buffer_types_struct_traits.h
index 086b27de..3716a61f4 100644
--- a/ui/gfx/mojo/buffer_types_traits.h
+++ b/ui/gfx/mojo/buffer_types_struct_traits.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 UI_GFX_MOJO_BUFFER_TYPES_TRAITS_H_
-#define UI_GFX_MOJO_BUFFER_TYPES_TRAITS_H_
+#ifndef UI_GFX_MOJO_BUFFER_TYPES_STRUCT_TRAITS_H_
+#define UI_GFX_MOJO_BUFFER_TYPES_STRUCT_TRAITS_H_
 
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/mojo/buffer_types.mojom.h"
@@ -276,4 +276,4 @@
 
 }  // namespace mojo
 
-#endif  // UI_GFX_MOJO_BUFFER_TYPES_TRAITS_H_
+#endif  // UI_GFX_MOJO_BUFFER_TYPES_STRUCT_TRAITS_H_
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc
index 3c1d61a..56591dc 100644
--- a/ui/gl/gl_context.cc
+++ b/ui/gl/gl_context.cc
@@ -169,6 +169,7 @@
     case kGLImplementationDesktopGL:
       return false;
     case kGLImplementationEGLGLES2:
+    case kGLImplementationSwiftShaderGL:
       return true;
     case kGLImplementationOSMesaGL:
     case kGLImplementationAppleGL:
diff --git a/ui/gl/gl_implementation.cc b/ui/gl/gl_implementation.cc
index b4ca6c72..73154b3 100644
--- a/ui/gl/gl_implementation.cc
+++ b/ui/gl/gl_implementation.cc
@@ -29,14 +29,14 @@
   const char* name;
   GLImplementation implementation;
 } kGLImplementationNamePairs[] = {
-  { kGLImplementationDesktopName, kGLImplementationDesktopGL },
-  { kGLImplementationOSMesaName, kGLImplementationOSMesaGL },
+    {kGLImplementationDesktopName, kGLImplementationDesktopGL},
+    {kGLImplementationOSMesaName, kGLImplementationOSMesaGL},
+    {kGLImplementationSwiftShaderName, kGLImplementationSwiftShaderGL},
 #if defined(OS_MACOSX)
-  { kGLImplementationAppleName, kGLImplementationAppleGL },
+    {kGLImplementationAppleName, kGLImplementationAppleGL},
 #endif
-  { kGLImplementationEGLName, kGLImplementationEGLGLES2 },
-  { kGLImplementationMockName, kGLImplementationMockGL }
-};
+    {kGLImplementationEGLName, kGLImplementationEGLGLES2},
+    {kGLImplementationMockName, kGLImplementationMockGL}};
 
 typedef std::vector<base::NativeLibrary> LibraryArray;
 
diff --git a/ui/gl/gl_implementation.h b/ui/gl/gl_implementation.h
index 6fca588..23c9629 100644
--- a/ui/gl/gl_implementation.h
+++ b/ui/gl/gl_implementation.h
@@ -26,6 +26,7 @@
   kGLImplementationDesktopGL,
   kGLImplementationDesktopGLCoreProfile,
   kGLImplementationOSMesaGL,
+  kGLImplementationSwiftShaderGL,
   kGLImplementationAppleGL,
   kGLImplementationEGLGLES2,
   kGLImplementationMockGL,
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index d1120003..2e1cfff 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -379,7 +379,7 @@
                         std::vector<DisplayType>* init_displays) {
   // SwiftShader does not use the platform extensions
   if (command_line->GetSwitchValueASCII(switches::kUseGL) ==
-      kGLImplementationSwiftShaderName) {
+      kGLImplementationSwiftShaderForWebGLName) {
     init_displays->push_back(SWIFT_SHADER);
     return;
   }
diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc
index 6beb533..3fabe5c 100644
--- a/ui/gl/gl_switches.cc
+++ b/ui/gl/gl_switches.cc
@@ -13,6 +13,7 @@
 const char kGLImplementationEGLName[]         = "egl";
 const char kGLImplementationANGLEName[]       = "angle";
 const char kGLImplementationSwiftShaderName[] = "swiftshader";
+const char kGLImplementationSwiftShaderForWebGLName[] = "swiftshader-webgl";
 const char kGLImplementationMockName[]        = "mock";
 const char kGLImplementationStubName[] = "stub";
 
diff --git a/ui/gl/gl_switches.h b/ui/gl/gl_switches.h
index 57f8d8d..a6c398a3 100644
--- a/ui/gl/gl_switches.h
+++ b/ui/gl/gl_switches.h
@@ -18,6 +18,7 @@
 GL_EXPORT extern const char kGLImplementationEGLName[];
 GL_EXPORT extern const char kGLImplementationANGLEName[];
 GL_EXPORT extern const char kGLImplementationSwiftShaderName[];
+GL_EXPORT extern const char kGLImplementationSwiftShaderForWebGLName[];
 extern const char kGLImplementationMockName[];
 extern const char kGLImplementationStubName[];
 
diff --git a/ui/gl/init/gl_factory.cc b/ui/gl/init/gl_factory.cc
index dff751b..376ab44 100644
--- a/ui/gl/init/gl_factory.cc
+++ b/ui/gl/init/gl_factory.cc
@@ -38,7 +38,10 @@
     if (requested_implementation_name == "any") {
       fallback_to_osmesa = true;
     } else if (requested_implementation_name ==
-                   kGLImplementationSwiftShaderName ||
+               kGLImplementationSwiftShaderName) {
+      impl = kGLImplementationSwiftShaderGL;
+    } else if (requested_implementation_name ==
+                   kGLImplementationSwiftShaderForWebGLName ||
                requested_implementation_name == kGLImplementationANGLEName) {
       impl = kGLImplementationEGLGLES2;
     } else {
diff --git a/ui/gl/init/gl_factory_win.cc b/ui/gl/init/gl_factory_win.cc
index bf0640c..da07adc 100644
--- a/ui/gl/init/gl_factory_win.cc
+++ b/ui/gl/init/gl_factory_win.cc
@@ -31,6 +31,7 @@
   impls.push_back(kGLImplementationEGLGLES2);
   impls.push_back(kGLImplementationDesktopGL);
   impls.push_back(kGLImplementationOSMesaGL);
+  impls.push_back(kGLImplementationSwiftShaderGL);
   return impls;
 }
 
@@ -53,6 +54,7 @@
     case kGLImplementationOSMesaGL:
       return InitializeGLContext(new GLContextOSMesa(share_group),
                                  compatible_surface, attribs);
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       return InitializeGLContext(new GLContextEGL(share_group),
                                  compatible_surface, attribs);
@@ -78,6 +80,7 @@
   switch (GetGLImplementation()) {
     case kGLImplementationOSMesaGL:
       return InitializeGLSurface(new GLSurfaceOSMesaWin(window));
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2: {
       DCHECK(window != gfx::kNullAcceleratedWidget);
       scoped_refptr<NativeViewGLSurfaceEGL> surface(
@@ -108,6 +111,7 @@
       format.SetDefaultPixelLayout(GLSurfaceFormat::PIXEL_LAYOUT_RGBA);
       return InitializeGLSurfaceWithFormat(
           new GLSurfaceOSMesa(format, size), format);
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       return InitializeGLSurfaceWithFormat(
           new PbufferGLSurfaceEGL(size), format);
diff --git a/ui/gl/init/gl_factory_x11.cc b/ui/gl/init/gl_factory_x11.cc
index 0b7fc2d..38a4d221 100644
--- a/ui/gl/init/gl_factory_x11.cc
+++ b/ui/gl/init/gl_factory_x11.cc
@@ -31,6 +31,7 @@
   impls.push_back(kGLImplementationDesktopGL);
   impls.push_back(kGLImplementationEGLGLES2);
   impls.push_back(kGLImplementationOSMesaGL);
+  impls.push_back(kGLImplementationSwiftShaderGL);
   return impls;
 }
 
@@ -56,6 +57,7 @@
     case kGLImplementationDesktopGL:
       return InitializeGLContext(new GLContextGLX(share_group),
                                  compatible_surface, attribs);
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       return InitializeGLContext(new GLContextEGL(share_group),
                                  compatible_surface, attribs);
@@ -80,6 +82,7 @@
       return InitializeGLSurface(new GLSurfaceOSMesaX11(window));
     case kGLImplementationDesktopGL:
       return InitializeGLSurface(new GLSurfaceGLXX11(window));
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       DCHECK(window != gfx::kNullAcceleratedWidget);
       return InitializeGLSurface(new NativeViewGLSurfaceEGLX11(window));
@@ -103,6 +106,7 @@
     case kGLImplementationDesktopGL:
       return InitializeGLSurfaceWithFormat(
           new UnmappedNativeViewGLSurfaceGLX(size), format);
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       return InitializeGLSurfaceWithFormat(
           new PbufferGLSurfaceEGL(size), format);
diff --git a/ui/gl/init/gl_initializer_win.cc b/ui/gl/init/gl_initializer_win.cc
index 6116bfb..c8648a761 100644
--- a/ui/gl/init/gl_initializer_win.cc
+++ b/ui/gl/init/gl_initializer_win.cc
@@ -98,9 +98,11 @@
   base::FilePath gles_path;
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
+  const std::string use_gl =
+      command_line->GetSwitchValueASCII(switches::kUseGL);
   bool using_swift_shader =
-      command_line->GetSwitchValueASCII(switches::kUseGL) ==
-      kGLImplementationSwiftShaderName;
+      (use_gl == kGLImplementationSwiftShaderName) ||
+      (use_gl == kGLImplementationSwiftShaderForWebGLName);
   if (using_swift_shader) {
     if (!command_line->HasSwitch(switches::kSwiftShaderPath))
       return false;
@@ -242,6 +244,7 @@
         return false;
       }
       break;
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       if (!GLSurfaceEGL::InitializeOneOff(GetDC(nullptr))) {
         LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
@@ -273,6 +276,7 @@
   switch (implementation) {
     case kGLImplementationOSMesaGL:
       return InitializeStaticOSMesaInternal();
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       return InitializeStaticEGLInternal();
     case kGLImplementationDesktopGL:
diff --git a/ui/gl/init/gl_initializer_x11.cc b/ui/gl/init/gl_initializer_x11.cc
index 1474057..2d88875 100644
--- a/ui/gl/init/gl_initializer_x11.cc
+++ b/ui/gl/init/gl_initializer_x11.cc
@@ -39,6 +39,9 @@
 const char kGLESv2ANGLELibraryName[] = "libGLESv2.so";
 const char kEGLANGLELibraryName[] = "libEGL.so";
 
+const char kGLESv2SwiftShaderLibraryName[] = "libGLESv2.so";
+const char kEGLSwiftShaderLibraryName[] = "libEGL.so";
+
 bool InitializeStaticGLXInternal() {
   base::NativeLibrary library = NULL;
   const base::CommandLine* command_line =
@@ -89,6 +92,15 @@
 
     glesv2_path = module_path.Append(kGLESv2ANGLELibraryName);
     egl_path = module_path.Append(kEGLANGLELibraryName);
+  } else if (command_line->GetSwitchValueASCII(switches::kUseGL) ==
+             kGLImplementationSwiftShaderName) {
+    base::FilePath module_path;
+    if (!command_line->HasSwitch(switches::kSwiftShaderPath))
+      return false;
+    module_path = command_line->GetSwitchValuePath(switches::kSwiftShaderPath);
+
+    glesv2_path = module_path.Append(kGLESv2SwiftShaderLibraryName);
+    egl_path = module_path.Append(kEGLSwiftShaderLibraryName);
   }
 
   base::NativeLibrary gles_library = LoadLibraryAndPrintError(glesv2_path);
@@ -143,6 +155,7 @@
         return false;
       }
       return true;
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       if (!GLSurfaceEGL::InitializeOneOff(gfx::GetXDisplay())) {
         LOG(ERROR) << "GLSurfaceEGL::InitializeOneOff failed.";
@@ -171,6 +184,7 @@
       return InitializeStaticGLBindingsOSMesaGL();
     case kGLImplementationDesktopGL:
       return InitializeStaticGLXInternal();
+    case kGLImplementationSwiftShaderGL:
     case kGLImplementationEGLGLES2:
       return InitializeStaticEGLInternal();
     case kGLImplementationMockGL:
diff --git a/ui/gl/test/egl_initialization_displays_unittest.cc b/ui/gl/test/egl_initialization_displays_unittest.cc
index 5b16b92..aefeed2 100644
--- a/ui/gl/test/egl_initialization_displays_unittest.cc
+++ b/ui/gl/test/egl_initialization_displays_unittest.cc
@@ -46,7 +46,7 @@
 
   // If swiftshader is requested, only SWIFT_SHADER should be returned
   command_line->AppendSwitchASCII(switches::kUseGL,
-                                  gl::kGLImplementationSwiftShaderName);
+                                  gl::kGLImplementationSwiftShaderForWebGLName);
   displays.clear();
   GetEGLInitDisplays(true, true, true, command_line.get(), &displays);
   EXPECT_NE(std::find(displays.begin(), displays.end(), gl::SWIFT_SHADER),
diff --git a/ui/gl/test/gl_image_test_template.h b/ui/gl/test/gl_image_test_template.h
index daab9b9e..fa34a71 100644
--- a/ui/gl/test/gl_image_test_template.h
+++ b/ui/gl/test/gl_image_test_template.h
@@ -14,6 +14,7 @@
 
 #include "base/strings/stringize_macros.h"
 #include "base/strings/stringprintf.h"
+#include "base/task_scheduler/task_scheduler.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/buffer_format_util.h"
@@ -162,6 +163,10 @@
  protected:
   // Overridden from testing::Test:
   void SetUp() override {
+    constexpr int kMaxTaskSchedulerThreads = 3;
+    base::TaskScheduler::CreateAndSetSimpleTaskScheduler(
+        kMaxTaskSchedulerThreads);
+
     GLImageTestSupport::InitializeGL();
     surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
     context_ =
diff --git a/ui/keyboard/keyboard_util.cc b/ui/keyboard/keyboard_util.cc
index 549e82f..ec5d4fc7 100644
--- a/ui/keyboard/keyboard_util.cc
+++ b/ui/keyboard/keyboard_util.cc
@@ -367,7 +367,7 @@
   if (!logged) {
     // Log the delta only once.
     UMA_HISTOGRAM_TIMES(
-        "VirtualKeyboard.FirstLoadTime",
+        "VirtualKeyboard.InitLatency.FirstLoad",
         base::Time::Now() - g_keyboard_load_time_start.Get());
     logged = true;
   }
diff --git a/ui/login/account_picker/user_pod_row.css b/ui/login/account_picker/user_pod_row.css
index 0dff606..03db017 100644
--- a/ui/login/account_picker/user_pod_row.css
+++ b/ui/login/account_picker/user_pod_row.css
@@ -399,11 +399,11 @@
 }
 
 .custom-icon-spinner {
-  -webkit-animation: easy-unlock-spinner-animation 2s steps(45) infinite;
+  animation: easy-unlock-spinner-animation 2s steps(45) infinite;
   background-image: url(chrome://theme/IDR_EASY_UNLOCK_SPINNER);
 }
 
-@-webkit-keyframes easy-unlock-spinner-animation {
+@keyframes easy-unlock-spinner-animation {
   from { background-position: 0 }
   to { background-position: -1215px }
 }
@@ -440,9 +440,9 @@
 
 .pod[auth-type='onlineSignIn'] .reauth-hint-container {
   display: flex;
+  justify-content: center;
   margin-top: 8px;
   width: 100%;
-  justify-content: center;
 }
 
 .reauth-hint-container .reauth-warning {
@@ -961,10 +961,10 @@
 
 /* Animations for the animated ellipsis: */
 .animated-ellipsis-component0 {
-  -webkit-animation: ellipsis-component0 1.5s infinite;
+  animation: ellipsis-component0 1.5s infinite;
 }
 
-@-webkit-keyframes ellipsis-component0 {
+@keyframes ellipsis-component0 {
   0% { opacity: 0; }
   25% { opacity: 1; }
   50% { opacity: 1; }
@@ -973,10 +973,10 @@
 }
 
 .animated-ellipsis-component1 {
-  -webkit-animation: ellipsis-component1 1.5s infinite;
+  animation: ellipsis-component1 1.5s infinite;
 }
 
-@-webkit-keyframes ellipsis-component1 {
+@keyframes ellipsis-component1 {
   0% { opacity: 0; }
   25% { opacity: 0; }
   50% { opacity: 1; }
@@ -985,10 +985,10 @@
 }
 
 .animated-ellipsis-component2 {
-  -webkit-animation: ellipsis-component2 1.5s infinite;
+  animation: ellipsis-component2 1.5s infinite;
 }
 
-@-webkit-keyframes ellipsis-component2 {
+@keyframes ellipsis-component2 {
   0% { opacity: 0; }
   25% { opacity: 0; }
   50% { opacity: 0; }
diff --git a/ui/login/screen_container.css b/ui/login/screen_container.css
index 848d04c..446669f 100644
--- a/ui/login/screen_container.css
+++ b/ui/login/screen_container.css
@@ -6,11 +6,11 @@
 #outer-container {
   -webkit-box-align: center;
   -webkit-box-pack: center;
-  -webkit-perspective: 1px; /* Workaround, see http://crbug.com/360567 */
   bottom: 57px;  /* Leave space for the header bar */
   display: -webkit-box;
   left: 0;
   min-height: 717px; /* This enables scrolling. Min resolution: 1024x768 */
+  perspective: 1px; /* Workaround, see http://crbug.com/360567 */
   position: absolute;
   right: 0;
   top: 0;
@@ -18,8 +18,8 @@
 }
 
 .oobe-display #outer-container {
-  -webkit-perspective: 600px;
   bottom: 47px; /* header-bar is 47 pixels high during OOBE */
+  perspective: 600px;
 }
 
 .pin-container.pin-enabled {
diff --git a/ui/message_center/views/custom_notification_view.cc b/ui/message_center/views/custom_notification_view.cc
index e81ba92..14106fb 100644
--- a/ui/message_center/views/custom_notification_view.cc
+++ b/ui/message_center/views/custom_notification_view.cc
@@ -11,6 +11,7 @@
 #include "ui/base/ime/text_input_type.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/message_center/message_center_style.h"
+#include "ui/message_center/views/message_center_controller.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/image_view.h"
@@ -145,4 +146,10 @@
   return MessageView::OnKeyPressed(event);
 }
 
+void CustomNotificationView::ChildPreferredSizeChanged(View* child) {
+  // Notify MessageCenterController when the custom content changes size,
+  // as it may need to relayout.
+  controller()->UpdateNotificationSize(notification_id());
+}
+
 }  // namespace message_center
diff --git a/ui/message_center/views/custom_notification_view.h b/ui/message_center/views/custom_notification_view.h
index fd8b760..0700010 100644
--- a/ui/message_center/views/custom_notification_view.h
+++ b/ui/message_center/views/custom_notification_view.h
@@ -41,6 +41,7 @@
   void RequestFocus() override;
   void OnPaint(gfx::Canvas* canvas) override;
   bool OnKeyPressed(const ui::KeyEvent& event) override;
+  void ChildPreferredSizeChanged(View* child) override;
 
  private:
   friend class CustomNotificationViewTest;
diff --git a/ui/message_center/views/custom_notification_view_unittest.cc b/ui/message_center/views/custom_notification_view_unittest.cc
index 5c82693..c90b1ac 100644
--- a/ui/message_center/views/custom_notification_view_unittest.cc
+++ b/ui/message_center/views/custom_notification_view_unittest.cc
@@ -146,6 +146,11 @@
     NOTREACHED();
   }
 
+  void UpdateNotificationSize(const std::string& notification_id) override {
+    // For this test, this method should not be invoked.
+    NOTREACHED();
+  }
+
   bool IsRemoved(const std::string& notification_id) const {
     return (removed_ids_.find(notification_id) != removed_ids_.end());
   }
diff --git a/ui/message_center/views/message_center_controller.h b/ui/message_center/views/message_center_controller.h
index 9ff85a5..2c43886 100644
--- a/ui/message_center/views/message_center_controller.h
+++ b/ui/message_center/views/message_center_controller.h
@@ -30,6 +30,11 @@
   virtual void ClickOnNotificationButton(const std::string& notification_id,
                                          int button_index) = 0;
   virtual void ClickOnSettingsButton(const std::string& notification_id) = 0;
+  // For ArcCustomNotificationView, size changes might come after the
+  // notification update over Mojo. Provide a method here to notify when
+  // a notification changed in some way and needs to be laid out again.
+  // See crbug.com/690813.
+  virtual void UpdateNotificationSize(const std::string& notification_id) = 0;
 };
 
 }  // namespace message_center
diff --git a/ui/message_center/views/message_center_view.cc b/ui/message_center/views/message_center_view.cc
index 2fca998..0ea74df 100644
--- a/ui/message_center/views/message_center_view.cc
+++ b/ui/message_center/views/message_center_view.cc
@@ -447,6 +447,11 @@
   message_center_->ClickOnSettingsButton(notification_id);
 }
 
+void MessageCenterView::UpdateNotificationSize(
+    const std::string& notification_id) {
+  OnNotificationUpdated(notification_id);
+}
+
 void MessageCenterView::AnimationEnded(const gfx::Animation* animation) {
   DCHECK_EQ(animation, settings_transition_animation_.get());
 
diff --git a/ui/message_center/views/message_center_view.h b/ui/message_center/views/message_center_view.h
index f5c3046..bd923fa 100644
--- a/ui/message_center/views/message_center_view.h
+++ b/ui/message_center/views/message_center_view.h
@@ -86,6 +86,7 @@
   void ClickOnNotificationButton(const std::string& notification_id,
                                  int button_index) override;
   void ClickOnSettingsButton(const std::string& notification_id) override;
+  void UpdateNotificationSize(const std::string& notification_id) override;
 
   // Overridden from MessageListView::Observer:
   void OnAllNotificationsCleared() override;
diff --git a/ui/message_center/views/message_center_view_unittest.cc b/ui/message_center/views/message_center_view_unittest.cc
index e038a8d..36a8302 100644
--- a/ui/message_center/views/message_center_view_unittest.cc
+++ b/ui/message_center/views/message_center_view_unittest.cc
@@ -156,6 +156,7 @@
   void ClickOnNotificationButton(const std::string& notification_id,
                                  int button_index) override;
   void ClickOnSettingsButton(const std::string& notification_id) override;
+  void UpdateNotificationSize(const std::string& notification_id) override;
 
   // Overridden from MockNotificationView::Test
   void RegisterCall(CallType type) override;
@@ -353,6 +354,12 @@
   NOTREACHED();
 }
 
+void MessageCenterViewTest::UpdateNotificationSize(
+    const std::string& notification_id) {
+  // For this test, this method should not be invoked.
+  NOTREACHED();
+}
+
 void MessageCenterViewTest::RegisterCall(CallType type) {
   callCounts_[type] += 1;
 }
diff --git a/ui/message_center/views/message_list_view_unittest.cc b/ui/message_center/views/message_list_view_unittest.cc
index a4dc8b12..730bda1 100644
--- a/ui/message_center/views/message_list_view_unittest.cc
+++ b/ui/message_center/views/message_list_view_unittest.cc
@@ -152,6 +152,7 @@
   void ClickOnNotificationButton(const std::string& notification_id,
                                  int button_index) override {}
   void ClickOnSettingsButton(const std::string& notification_id) override {}
+  void UpdateNotificationSize(const std::string& notification_id) override;
 
   // Widget to host a MessageListView.
   std::unique_ptr<views::Widget> widget_;
@@ -161,6 +162,12 @@
   DISALLOW_COPY_AND_ASSIGN(MessageListViewTest);
 };
 
+void MessageListViewTest::UpdateNotificationSize(
+    const std::string& notification_id) {
+  // For this test, this method should not be invoked.
+  NOTREACHED();
+}
+
 /* Unit tests *****************************************************************/
 
 TEST_F(MessageListViewTest, AddNotification) {
diff --git a/ui/message_center/views/message_popup_collection.cc b/ui/message_center/views/message_popup_collection.cc
index 9b859200..c9556d3 100644
--- a/ui/message_center/views/message_popup_collection.cc
+++ b/ui/message_center/views/message_popup_collection.cc
@@ -125,6 +125,11 @@
   message_center_->ClickOnSettingsButton(notification_id);
 }
 
+void MessagePopupCollection::UpdateNotificationSize(
+    const std::string& notification_id) {
+  OnNotificationUpdated(notification_id);
+}
+
 void MessagePopupCollection::MarkAllPopupsShown() {
   std::set<std::string> closed_ids = CloseAllWidgets();
   for (std::set<std::string>::iterator iter = closed_ids.begin();
diff --git a/ui/message_center/views/message_popup_collection.h b/ui/message_center/views/message_popup_collection.h
index 402c747..fa0068de 100644
--- a/ui/message_center/views/message_popup_collection.h
+++ b/ui/message_center/views/message_popup_collection.h
@@ -68,6 +68,7 @@
   void ClickOnNotificationButton(const std::string& notification_id,
                                  int button_index) override;
   void ClickOnSettingsButton(const std::string& notification_id) override;
+  void UpdateNotificationSize(const std::string& notification_id) override;
 
   void MarkAllPopupsShown();
 
diff --git a/ui/message_center/views/notification_view_unittest.cc b/ui/message_center/views/notification_view_unittest.cc
index 930ccc0..5264eaa 100644
--- a/ui/message_center/views/notification_view_unittest.cc
+++ b/ui/message_center/views/notification_view_unittest.cc
@@ -94,6 +94,7 @@
   void ClickOnNotificationButton(const std::string& notification_id,
                                  int button_index) override;
   void ClickOnSettingsButton(const std::string& notification_id) override;
+  void UpdateNotificationSize(const std::string& notification_id) override;
 
  protected:
   // Used to fill bitmaps returned by CreateBitmap().
@@ -285,6 +286,12 @@
   NOTREACHED();
 }
 
+void NotificationViewTest::UpdateNotificationSize(
+    const std::string& notification_id) {
+  // For this test, this method should not be invoked.
+  NOTREACHED();
+}
+
 /* Unit tests *****************************************************************/
 
 TEST_F(NotificationViewTest, CreateOrUpdateTest) {
diff --git a/ui/message_center/views/toast_contents_view.cc b/ui/message_center/views/toast_contents_view.cc
index 877c3105..e20b03e 100644
--- a/ui/message_center/views/toast_contents_view.cc
+++ b/ui/message_center/views/toast_contents_view.cc
@@ -327,6 +327,12 @@
     collection_->ClickOnSettingsButton(notification_id);
 }
 
+void ToastContentsView::UpdateNotificationSize(
+    const std::string& notification_id) {
+  if (collection_)
+    collection_->UpdateNotificationSize(notification_id);
+}
+
 void ToastContentsView::RemoveNotification(
     const std::string& notification_id,
     bool by_user) {
diff --git a/ui/message_center/views/toast_contents_view.h b/ui/message_center/views/toast_contents_view.h
index f7d0cc2..cb06a4a 100644
--- a/ui/message_center/views/toast_contents_view.h
+++ b/ui/message_center/views/toast_contents_view.h
@@ -97,6 +97,7 @@
   void ClickOnNotificationButton(const std::string& notification_id,
                                  int button_index) override;
   void ClickOnSettingsButton(const std::string& notification_id) override;
+  void UpdateNotificationSize(const std::string& notification_id) override;
 
   // Overridden from gfx::AnimationDelegate:
   void AnimationProgressed(const gfx::Animation* animation) override;
diff --git a/ui/native_theme/OWNERS b/ui/native_theme/OWNERS
index 4986915..7768376 100644
--- a/ui/native_theme/OWNERS
+++ b/ui/native_theme/OWNERS
@@ -1,2 +1,4 @@
 estade@chromium.org
 pkasting@chromium.org
+
+# COMPONENT: UI
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
index ec411f4..82c927d 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -202,14 +202,16 @@
 void HardwareDisplayController::AddCrtc(
     std::unique_ptr<CrtcController> controller) {
   scoped_refptr<DrmDevice> drm = controller->drm();
-  owned_hardware_planes_[drm.get()] =
-      base::MakeUnique<HardwareDisplayPlaneList>();
+
+  std::unique_ptr<HardwareDisplayPlaneList>& owned_planes =
+      owned_hardware_planes_[drm.get()];
+  if (!owned_planes)
+    owned_planes.reset(new HardwareDisplayPlaneList());
 
   // Check if this controller owns any planes and ensure we keep track of them.
   const std::vector<std::unique_ptr<HardwareDisplayPlane>>& all_planes =
       drm->plane_manager()->planes();
-  HardwareDisplayPlaneList* crtc_plane_list =
-      owned_hardware_planes_[drm.get()].get();
+  HardwareDisplayPlaneList* crtc_plane_list = owned_planes.get();
   uint32_t crtc = controller->crtc();
   for (const auto& plane : all_planes) {
     if (plane->in_use() && (plane->owning_crtc() == crtc))
diff --git a/ui/resources/default_100_percent/common/back_arrow.png b/ui/resources/default_100_percent/common/back_arrow.png
deleted file mode 100644
index 0334cafe..0000000
--- a/ui/resources/default_100_percent/common/back_arrow.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_100_percent/common/forward_arrow.png b/ui/resources/default_100_percent/common/forward_arrow.png
deleted file mode 100644
index 6804069..0000000
--- a/ui/resources/default_100_percent/common/forward_arrow.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_200_percent/common/back_arrow.png b/ui/resources/default_200_percent/common/back_arrow.png
deleted file mode 100644
index e1f212f..0000000
--- a/ui/resources/default_200_percent/common/back_arrow.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/default_200_percent/common/forward_arrow.png b/ui/resources/default_200_percent/common/forward_arrow.png
deleted file mode 100644
index 85ebf17..0000000
--- a/ui/resources/default_200_percent/common/forward_arrow.png
+++ /dev/null
Binary files differ
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index ea73b366..db6fe50 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -83,8 +83,6 @@
         <structure type="chrome_scaled_image" name="IDR_AURA_SHADOW_INACTIVE" file="common/window_shadow_inactive.png" />
         <structure type="chrome_scaled_image" name="IDR_WINDOW_BUBBLE_SHADOW_SMALL" file="common/window_bubble_shadow_small.png" />
       </if>
-      <structure type="chrome_scaled_image" name="IDR_BACK_ARROW" file="common/back_arrow.png" />
-      <structure type="chrome_scaled_image" name="IDR_FORWARD_ARROW" file="common/forward_arrow.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_2" file="close_2.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_2_H" file="close_2_hover.png" />
       <structure type="chrome_scaled_image" name="IDR_CLOSE_2_MASK" file="close_2_mask.png" />
diff --git a/ui/vector_icons/BUILD.gn b/ui/vector_icons/BUILD.gn
index c299793..52e95265 100644
--- a/ui/vector_icons/BUILD.gn
+++ b/ui/vector_icons/BUILD.gn
@@ -8,8 +8,12 @@
   icon_directory = "."
 
   icons = [
+    "back_arrow.1x.icon",
+    "back_arrow.icon",
     "close.1x.icon",
     "close.icon",
+    "forward_arrow.1x.icon",
+    "forward_arrow.icon",
   ]
 }
 
diff --git a/chrome/app/vector_icons/navigate_back.1x.icon b/ui/vector_icons/back_arrow.1x.icon
similarity index 100%
rename from chrome/app/vector_icons/navigate_back.1x.icon
rename to ui/vector_icons/back_arrow.1x.icon
diff --git a/chrome/app/vector_icons/navigate_back.icon b/ui/vector_icons/back_arrow.icon
similarity index 100%
rename from chrome/app/vector_icons/navigate_back.icon
rename to ui/vector_icons/back_arrow.icon
diff --git a/chrome/app/vector_icons/navigate_forward.1x.icon b/ui/vector_icons/forward_arrow.1x.icon
similarity index 100%
rename from chrome/app/vector_icons/navigate_forward.1x.icon
rename to ui/vector_icons/forward_arrow.1x.icon
diff --git a/chrome/app/vector_icons/navigate_forward.icon b/ui/vector_icons/forward_arrow.icon
similarity index 100%
rename from chrome/app/vector_icons/navigate_forward.icon
rename to ui/vector_icons/forward_arrow.icon
diff --git a/ui/views/accessibility/ax_widget_obj_wrapper.cc b/ui/views/accessibility/ax_widget_obj_wrapper.cc
index 70307b91..2d96f8c 100644
--- a/ui/views/accessibility/ax_widget_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_widget_obj_wrapper.cc
@@ -32,8 +32,10 @@
 
 void AXWidgetObjWrapper::GetChildren(
     std::vector<AXAuraObjWrapper*>* out_children) {
-  if (!widget_->IsVisible() || !widget_->GetRootView()->visible())
+  if (!widget_->IsVisible() || !widget_->GetRootView() ||
+      !widget_->GetRootView()->visible()) {
     return;
+  }
 
   out_children->push_back(
       AXAuraObjCache::GetInstance()->GetOrCreate(widget_->GetRootView()));
diff --git a/ui/views/accessibility/native_view_accessibility_unittest.cc b/ui/views/accessibility/native_view_accessibility_unittest.cc
index a678848..eecbff0 100644
--- a/ui/views/accessibility/native_view_accessibility_unittest.cc
+++ b/ui/views/accessibility/native_view_accessibility_unittest.cc
@@ -2,11 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ui/views/accessibility/native_view_accessibility.h"
+
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/views/accessibility/native_view_accessibility.h"
+#include "ui/views/accessibility/ax_aura_obj_cache.h"
+#include "ui/views/accessibility/ax_aura_obj_wrapper.h"
+#include "ui/views/accessibility/ax_widget_obj_wrapper.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/test/views_test_base.h"
@@ -157,5 +161,69 @@
   parent_widget.reset();
 }
 
+#if defined(USE_AURA)
+class DerivedTestView : public View {
+ public:
+  DerivedTestView() : View() {}
+  ~DerivedTestView() override {}
+
+  void OnBlur() override { SetVisible(false); }
+};
+
+class AxTestViewsDelegate : public TestViewsDelegate {
+ public:
+  AxTestViewsDelegate() {}
+  ~AxTestViewsDelegate() override {}
+
+  void NotifyAccessibilityEvent(views::View* view,
+                                ui::AXEvent event_type) override {
+    AXAuraObjCache* ax = AXAuraObjCache::GetInstance();
+    std::vector<AXAuraObjWrapper*> out_children;
+    AXAuraObjWrapper* ax_obj = ax->GetOrCreate(view->GetWidget());
+    ax_obj->GetChildren(&out_children);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AxTestViewsDelegate);
+};
+
+class AXViewTest : public ViewsTestBase {
+ public:
+  AXViewTest() {}
+  ~AXViewTest() override {}
+  void SetUp() override {
+    std::unique_ptr<TestViewsDelegate> views_delegate(
+        new AxTestViewsDelegate());
+    set_views_delegate(std::move(views_delegate));
+    views::ViewsTestBase::SetUp();
+  }
+};
+
+// Check if the destruction of the widget ends successfully if |view|'s
+// visibility changed during destruction.
+TEST_F(AXViewTest, LayoutCalledInvalidateRootView) {
+  std::unique_ptr<Widget> widget(new Widget);
+  Widget::InitParams params = CreateParams(Widget::InitParams::TYPE_POPUP);
+  params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  widget->Init(params);
+  widget->Show();
+
+  View* root = widget->GetRootView();
+  DerivedTestView* parent = new DerivedTestView();
+  DerivedTestView* child = new DerivedTestView();
+  root->AddChildView(parent);
+  parent->AddChildView(child);
+  child->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS);
+  parent->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS);
+  root->SetFocusBehavior(DerivedTestView::FocusBehavior::ALWAYS);
+  parent->RequestFocus();
+  // During the destruction of parent, OnBlur will be called and change the
+  // visibility to false.
+  parent->SetVisible(true);
+  AXAuraObjCache* ax = AXAuraObjCache::GetInstance();
+  ax->GetOrCreate(widget.get());
+}
+#endif
+
 }  // namespace test
 }  // namespace views
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index 2086222..2d16942 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -30,6 +30,7 @@
 #include "ui/gfx/text_elider.h"
 #include "ui/native_theme/native_theme.h"
 #include "ui/strings/grit/ui_strings.h"
+#include "ui/views/background.h"
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/focus/focus_manager.h"
 #include "ui/views/native_cursor.h"
@@ -450,8 +451,30 @@
 
 void Label::PaintText(gfx::Canvas* canvas) {
   MaybeBuildRenderTextLines();
+
   for (size_t i = 0; i < lines_.size(); ++i)
     lines_[i]->Draw(canvas);
+
+#if DCHECK_IS_ON()
+  // Attempt to ensure that if we're using subpixel rendering, we're painting
+  // to an opaque background. What we don't want to find is an ancestor in the
+  // hierarchy that paints to a non-opaque layer.
+  if (lines_.empty() || lines_[0]->subpixel_rendering_suppressed())
+    return;
+
+  for (View* view = this; view; view = view->parent()) {
+    if (view->background() &&
+        SkColorGetA(view->background()->get_color()) == SK_AlphaOPAQUE)
+      break;
+
+    if (view->layer()) {
+      DCHECK(view->layer()->fills_bounds_opaquely())
+          << " Ancestor view has a non-opaque layer: " << view->GetClassName()
+          << " with ID " << view->id();
+      break;
+    }
+  }
+#endif
 }
 
 void Label::OnBoundsChanged(const gfx::Rect& previous_bounds) {
@@ -964,7 +987,8 @@
 void Label::ApplyTextColors() const {
   SkColor color = enabled() ? actual_enabled_color_ : actual_disabled_color_;
   bool subpixel_rendering_suppressed =
-      SkColorGetA(background_color_) != 0xFF || !subpixel_rendering_enabled_;
+      SkColorGetA(background_color_) != SK_AlphaOPAQUE ||
+      !subpixel_rendering_enabled_;
   for (size_t i = 0; i < lines_.size(); ++i) {
     lines_[i]->SetColor(color);
     lines_[i]->set_selection_color(actual_selection_text_color_);
diff --git a/ui/views/controls/textfield/OWNERS b/ui/views/controls/textfield/OWNERS
index b1b0e2d..d0cc0583 100644
--- a/ui/views/controls/textfield/OWNERS
+++ b/ui/views/controls/textfield/OWNERS
@@ -1,3 +1,5 @@
 msw@chromium.org
 oshima@chromium.org
 pkasting@chromium.org
+
+# COMPONENT: Internals>Views
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc
index adb1612..b482dbe 100644
--- a/ui/views/focus/focus_manager.cc
+++ b/ui/views/focus/focus_manager.cc
@@ -301,6 +301,9 @@
     View* view, FocusChangeReason reason) {
   if (focused_view_ == view)
     return;
+  // TODO(oshima|achuith): This is to diagnose crbug.com/687232.
+  // Change this to DCHECK once it's resolved.
+  CHECK(!view || ContainsView(view));
 
 #if !defined(OS_MACOSX)
   // TODO(warx): There are some AccessiblePaneViewTest failed on macosx.
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc
index e8dcb5b..26389b85 100644
--- a/ui/views/mus/desktop_window_tree_host_mus.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -675,9 +675,7 @@
          ui::SHOW_STATE_FULLSCREEN;
 }
 void DesktopWindowTreeHostMus::SetOpacity(float opacity) {
-  // TODO: this likely need to go to server so that non-client decorations get
-  // opacity. http://crbug.com/663619.
-  window()->layer()->SetOpacity(opacity);
+  WindowTreeHostMus::SetOpacity(opacity);
 }
 
 void DesktopWindowTreeHostMus::SetWindowIcons(const gfx::ImageSkia& window_icon,
diff --git a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
index f4976aab..4c72bb5 100644
--- a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
+++ b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -268,6 +268,16 @@
   waiter.Wait();
 }
 
+TEST_F(DesktopWindowTreeHostMusTest, SetOpacity) {
+  std::unique_ptr<Widget> widget1(CreateWidget(nullptr));
+  widget1->Show();
+
+  aura::test::ChangeCompletionWaiter waiter(
+      MusClient::Get()->window_tree_client(), aura::ChangeType::OPACITY, true);
+  widget1->SetOpacity(0.5f);
+  waiter.Wait();
+}
+
 TEST_F(DesktopWindowTreeHostMusTest, TransientParentWiredToHostWindow) {
   std::unique_ptr<Widget> widget1(CreateWidget());
   widget1->Show();
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 18dff1a..872d0ccb 100644
--- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
+++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
@@ -129,7 +129,8 @@
       <div id="leftSpacer">
         <!-- Note: showing #menuPromo relies on this dom-if being [restamp]. -->
         <template is="dom-if" if="[[showMenu]]" restamp>
-          <paper-icon-button id="menuButton" icon="cr:menu" on-tap="onMenuTap_"
+          <paper-icon-button id="menuButton" icon="cr20:menu"
+              on-tap="onMenuTap_"
               title="[[titleIfNotShowMenuPromo_(menuLabel, showMenuPromo)]]"
               aria-label$="[[menuLabel]]">
           </paper-icon-button>
diff --git a/ui/webui/resources/cr_elements/icons.html b/ui/webui/resources/cr_elements/icons.html
index c0e6d47..674926d52 100644
--- a/ui/webui/resources/cr_elements/icons.html
+++ b/ui/webui/resources/cr_elements/icons.html
@@ -4,7 +4,22 @@
 <!--
 List commonly used icons here to prevent duplication.
 Do not add rarely used icons here; place those in your application.
+Note that 20px and 24px icons are specified separately (size="", below).
+
+Icons are rendered at 20x20 px, but we don't have 20 px SVGs for everything.
+The 24 px icons are used where 20 px icons are unavailable (which may appear
+blurry at 20 px). Please use 20 px icons when available.
 -->
+<iron-iconset-svg name="cr20" size="20">
+  <svg>
+    <defs>
+      <!--
+      Keep these in sorted order by id="". See also http://goo.gl/Y1OdAq
+      -->
+      <g id="domain"><path d="M2,3 L2,17 L11.8267655,17 L13.7904799,17 L18,17 L18,7 L12,7 L12,3 L2,3 Z M8,13 L10,13 L10,15 L8,15 L8,13 Z M4,13 L6,13 L6,15 L4,15 L4,13 Z M8,9 L10,9 L10,11 L8,11 L8,9 Z M4,9 L6,9 L6,11 L4,11 L4,9 Z M12,9 L16,9 L16,15 L12,15 L12,9 Z M12,11 L14,11 L14,13 L12,13 L12,11 Z M8,5 L10,5 L10,7 L8,7 L8,5 Z M4,5 L6,5 L6,7 L4,7 L4,5 Z"></path></g>
+      <g id="menu"><rect x="2" y="4" width="16" height="2"></rect><rect x="2" y="9" width="16" height="2"></rect><rect x="2" y="14" width="16" height="2"></rect></g>
+  </svg>
+</iron-iconset-svg>
 <iron-iconset-svg name="cr" size="24">
   <svg>
     <defs>
@@ -23,7 +38,6 @@
       <g id="clear"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g>
       <g id="close"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></g>
       <g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></g>
-      <g id="domain" shape-rendering="crispEdges" viewBox="-0.75 -0.75 25.5 25.5"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"></path></g>
       <g id="expand-less"><path d="M12 8l-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z"></path></g>
       <g id="expand-more"><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"></path></g>
       <g id="extension"><path d="M20.5 11H19V7c0-1.1-.9-2-2-2h-4V3.5C13 2.12 11.88 1 10.5 1S8 2.12 8 3.5V5H4c-1.1 0-1.99.9-1.99 2v3.8H3.5c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-1.5c0-1.49 1.21-2.7 2.7-2.7 1.49 0 2.7 1.21 2.7 2.7V22H17c1.1 0 2-.9 2-2v-4h1.5c1.38 0 2.5-1.12 2.5-2.5S21.88 11 20.5 11z"></path></g>
@@ -31,7 +45,6 @@
       <g id="folder"><path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"></path></g>
       <g id="fullscreen"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"></path></g>
       <g id="group"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"></path></g>
-      <g id="menu" shape-rendering="crispEdges" viewBox="0.375 0.375 23.38 23.38"><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"></path></g>
       <g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g>
       <g id="open-in-new"><path d="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"></path></g>
       <g id="person"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"></path></g>
@@ -42,4 +55,4 @@
       <g id="warning"><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"></path></g>
     </defs>
   </svg>
-</iron-iconset-svg>
+</iron-iconset-svg>
\ No newline at end of file
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_item.html b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
index de555d0..c149622 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list_item.html
+++ b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
@@ -31,7 +31,7 @@
         border-style: none;
         display: flex;
         flex-direction: row;
-        height: 32px;
+        min-height: 32px;
       }
 
       #divText {
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js b/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
index 5367637b..205465c 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
@@ -54,20 +54,20 @@
       case CrPolicyIndicatorType.NONE:
         return icon;
       case CrPolicyIndicatorType.PRIMARY_USER:
-        icon = 'group';
+        icon = 'cr:group';
         break;
       case CrPolicyIndicatorType.OWNER:
-        icon = 'person';
+        icon = 'cr:person';
         break;
       case CrPolicyIndicatorType.USER_POLICY:
       case CrPolicyIndicatorType.DEVICE_POLICY:
       case CrPolicyIndicatorType.RECOMMENDED:
-        icon = 'domain';
+        icon = 'cr20:domain';
         break;
       default:
         assertNotReached();
     }
-    return 'cr:' + icon;
+    return icon;
   },
 
   /**
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.html b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.html
index 814eced..d0e0390 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.html
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_pref_indicator.html
@@ -9,6 +9,10 @@
 <dom-module id="cr-policy-pref-indicator">
   <link rel="import" type="css" href="cr_policy_indicator.css">
   <style>
+    :host {
+      display: flex;  /* Position independantly from the line-height. */
+    }
+
     paper-tooltip {
       --paper-tooltip: var(--cr-policy-tooltip);
     }
diff --git a/ui/webui/resources/css/dialogs.css b/ui/webui/resources/css/dialogs.css
index a20bc24..376061ed 100644
--- a/ui/webui/resources/css/dialogs.css
+++ b/ui/webui/resources/css/dialogs.css
@@ -36,7 +36,7 @@
   outline: none;
 }
 
-@-webkit-keyframes pulse {
+@keyframes pulse {
  0% {
    transform: scale(1);
  }
@@ -52,24 +52,24 @@
 }
 
 .cr-dialog-frame.pulse {
-  -webkit-animation-duration: 180ms;
-  -webkit-animation-iteration-count: 1;
-  -webkit-animation-name: pulse;
-  -webkit-animation-timing-function: ease-in-out;
+  animation-duration: 180ms;
+  animation-iteration-count: 1;
+  animation-name: pulse;
+  animation-timing-function: ease-in-out;
 }
 
 .shown > .cr-dialog-frame {
-  transform: perspective(500px) scale(1)
-                     translateY(0) rotateX(0);
   opacity: 1;
+  transform: perspective(500px) scale(1)
+             translateY(0) rotateX(0);
 }
 
 .cr-dialog-frame {
-  transform: perspective(500px) scale(0.99)
-                     translateY(-20px) rotateX(5deg);
   -webkit-transition: all 180ms;
   -webkit-transition-duration: 250ms;
   opacity: 0;
+  transform: perspective(500px) scale(0.99)
+             translateY(-20px) rotateX(5deg);
 }
 
 .cr-dialog-shield {
diff --git a/ui/webui/resources/css/overlay.css b/ui/webui/resources/css/overlay.css
index b8d7af51c..ed95bd4 100644
--- a/ui/webui/resources/css/overlay.css
+++ b/ui/webui/resources/css/overlay.css
@@ -7,8 +7,6 @@
   -webkit-box-align: center;
   -webkit-box-orient: vertical;
   -webkit-box-pack: center;
-  /* TODO(dbeam): remove perspective when http://crbug.com/374970 is fixed. */
-  -webkit-perspective: 1px;
   -webkit-transition: 200ms opacity;
   background-color: rgba(255, 255, 255, 0.75);
   bottom: 0;
@@ -16,6 +14,8 @@
   left: 0;
   overflow: auto;
   padding: 20px;
+  /* TODO(dbeam): remove perspective when http://crbug.com/374970 is fixed. */
+  perspective: 1px;
   position: fixed;
   right: 0;
   top: 0;
@@ -50,7 +50,7 @@
 }
 
 /* keyframes used to pulse the overlay */
-@-webkit-keyframes pulse {
+@keyframes pulse {
  0% {
    transform: scale(1);
  }
@@ -66,10 +66,10 @@
 }
 
 .overlay .page.pulse {
-  -webkit-animation-duration: 180ms;
-  -webkit-animation-iteration-count: 1;
-  -webkit-animation-name: pulse;
-  -webkit-animation-timing-function: ease-in-out;
+  animation-duration: 180ms;
+  animation-iteration-count: 1;
+  animation-name: pulse;
+  animation-timing-function: ease-in-out;
 }
 
 .overlay .page > .close-button {
diff --git a/ui/webui/resources/css/trash.css b/ui/webui/resources/css/trash.css
index dfe66dc0..414d6de 100644
--- a/ui/webui/resources/css/trash.css
+++ b/ui/webui/resources/css/trash.css
@@ -28,14 +28,14 @@
 }
 
 .trash > .lid {
-  -webkit-transform-origin: -7% 100%;
   -webkit-transition: transform 150ms;
   height: 6px;
+  transform-origin: -7% 100%;
   width: 14px;
 }
 
 html[dir='rtl'] .trash > .lid {
-  -webkit-transform-origin: 107% 100%;
+  transform-origin: 107% 100%;
 }
 
 .trash:-webkit-any(:focus, :hover, .open) > .lid {
diff --git a/ui/webui/resources/images/throbber_medium.svg b/ui/webui/resources/images/throbber_medium.svg
index c6f51b2..790ed9fa 100644
--- a/ui/webui/resources/images/throbber_medium.svg
+++ b/ui/webui/resources/images/throbber_medium.svg
@@ -37,23 +37,23 @@
 
       /* SVG elements seem to have a different default origin */
       .qp-circular-loader, .qp-circular-loader * {
-        -webkit-transform-origin: 50% 50%;
+        transform-origin: 50% 50%;
       }
 
       /* Rotating the whole thing */
-      @-webkit-keyframes rotate {
+      @keyframes rotate {
         from {transform: rotate(0deg);}
         to {transform: rotate(360deg);}
       }
       .qp-circular-loader {
-        -webkit-animation-name: rotate;
-        -webkit-animation-duration: 1568.63ms; /* 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
-        -webkit-animation-iteration-count: infinite;
-        -webkit-animation-timing-function: linear;
+        animation-duration: 1568.63ms; /* 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
+        animation-iteration-count: infinite;
+        animation-name: rotate;
+        animation-timing-function: linear;
       }
 
       /* Filling and unfilling the arc */
-      @-webkit-keyframes fillunfill {
+      @keyframes fillunfill {
         from {
           stroke-dashoffset: 58.8 /* 2*RADIUS*PI * ARCSIZE/360 - 0.1 */
                                   /* 0.1 a bit of a magic constant here */
@@ -66,7 +66,7 @@
                                    /* 0.5 a bit of a magic constant here */
         }
       }
-      @-webkit-keyframes rot {
+      @keyframes rot {
         from {
           transform: rotate(0deg);
         }
@@ -74,7 +74,7 @@
           transform: rotate(-360deg);
         }
       }
-      @-webkit-keyframes colors {
+      @keyframes colors {
         from {
           stroke: #4285f4;
         }
@@ -83,12 +83,12 @@
         }
       }
       .qp-circular-loader-path {
-        -webkit-animation-name: fillunfill, rot, colors;
-        -webkit-animation-duration: 1333ms, 5332ms, 5332ms; /* ARCTIME, 4*ARCTIME, 4*ARCTIME */
-        -webkit-animation-iteration-count: infinite, infinite, infinite;
-        -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), steps(4), linear;
-        -webkit-animation-play-state: running, running, running;
-        -webkit-animation-fill-mode: forwards;
+        animation-duration: 1333ms, 5332ms, 5332ms; /* ARCTIME, 4*ARCTIME, 4*ARCTIME */
+        animation-fill-mode: forwards;
+        animation-iteration-count: infinite, infinite, infinite;
+        animation-name: fillunfill, rot, colors;
+        animation-play-state: running, running, running;
+        animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), steps(4), linear;
       }
 
   </style>
diff --git a/ui/webui/resources/images/throbber_small.svg b/ui/webui/resources/images/throbber_small.svg
index 6f31d49..54170aa 100644
--- a/ui/webui/resources/images/throbber_small.svg
+++ b/ui/webui/resources/images/throbber_small.svg
@@ -38,23 +38,23 @@
 
       /* SVG elements seem to have a different default origin */
       .qp-circular-loader, .qp-circular-loader * {
-        -webkit-transform-origin: 50% 50%;
+        transform-origin: 50% 50%;
       }
 
       /* Rotating the whole thing */
-      @-webkit-keyframes rotate {
+      @keyframes rotate {
         from {transform: rotate(0deg);}
         to {transform: rotate(360deg);}
       }
       .qp-circular-loader {
-        -webkit-animation-name: rotate;
-        -webkit-animation-duration: 1568.63ms; /* 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
-        -webkit-animation-iteration-count: infinite;
-        -webkit-animation-timing-function: linear;
+        animation-duration: 1568.63ms; /* 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
+        animation-iteration-count: infinite;
+        animation-name: rotate;
+        animation-timing-function: linear;
       }
 
       /* Filling and unfilling the arc */
-      @-webkit-keyframes fillunfill {
+      @keyframes fillunfill {
         from {
           stroke-dashoffset: 32.3 /* 2*RADIUS*PI * ARCSIZE/360 - 0.1 */
                                   /* 0.1 a bit of a magic constant here */
@@ -67,7 +67,7 @@
                                    /* 0.5 a bit of a magic constant here */
         }
       }
-      @-webkit-keyframes rot {
+      @keyframes rot {
         from {
           transform: rotate(0deg);
         }
@@ -75,7 +75,7 @@
           transform: rotate(-360deg);
         }
       }
-      @-webkit-keyframes colors {
+      @keyframes colors {
         from {
           stroke: #4285f4;
         }
@@ -84,12 +84,12 @@
         }
       }
       .qp-circular-loader-path {
-        -webkit-animation-name: fillunfill, rot, colors;
-        -webkit-animation-duration: 1333ms, 5332ms, 5332ms; /* ARCTIME, 4*ARCTIME, 4*ARCTIME */
-        -webkit-animation-iteration-count: infinite, infinite, infinite;
-        -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), steps(4), linear;
-        -webkit-animation-play-state: running, running, running;
-        -webkit-animation-fill-mode: forwards;
+        animation-duration: 1333ms, 5332ms, 5332ms; /* ARCTIME, 4*ARCTIME, 4*ARCTIME */
+        animation-fill-mode: forwards;
+        animation-iteration-count: infinite, infinite, infinite;
+        animation-name: fillunfill, rot, colors;
+        animation-play-state: running, running, running;
+        animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), steps(4), linear;
       }
 
   </style>
diff --git a/ui/webui/resources/js/cr/ui/overlay.js b/ui/webui/resources/js/cr/ui/overlay.js
index 2e068c4..16ad0ef4 100644
--- a/ui/webui/resources/js/cr/ui/overlay.js
+++ b/ui/webui/resources/js/cr/ui/overlay.js
@@ -128,7 +128,7 @@
       if (overlayPage)
         overlayPage.classList.add('pulse');
     });
-    overlay.addEventListener('webkitAnimationEnd', function(e) {
+    overlay.addEventListener('animationend', function(e) {
       e.target.classList.remove('pulse');
     });
   }