diff --git a/.gitignore b/.gitignore
index b435be2..d3c9275 100644
--- a/.gitignore
+++ b/.gitignore
@@ -184,6 +184,7 @@
 /ios/third_party/material_text_accessibility_ios/src
 /ios/third_party/ochamcrest/src
 /ios_internal
+/libassistant
 /llvm
 /media/cast/logging/cast_logging_proto_lib.xml
 /media/cdm/api
diff --git a/.gn b/.gn
index 4518d99..cd7ed79 100644
--- a/.gn
+++ b/.gn
@@ -41,7 +41,6 @@
     "//third_party/WebKit/Source/core/streams/WritableStream.js",
   ]
   v8_experimental_extra_library_files = []
-  v8_enable_inspector = true
   v8_enable_gdbjit = false
   v8_imminent_deprecation_warnings = false
 }
diff --git a/AUTHORS b/AUTHORS
index dbcb070..888a1a3 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -226,7 +226,6 @@
 Franklin Ta <fta2012@gmail.com>
 Frédéric Jacob <frederic.jacob.78@gmail.com>
 Frédéric Wang <fred.wang@free.fr>
-Fu Junwei <junwei.fu@intel.com>
 Gaetano Mendola <mendola@gmail.com>
 Gajendra N <gajendra.n@samsung.com>
 Gajendra Singh <wxjg68@motorola.com>
diff --git a/DEPS b/DEPS
index 1549c82..7333333 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': '2e2b27fcc1505e23453b773e1de081fc7aa589e9',
+  'skia_revision': '9a121cc6ad746c37611229dc0ec1805545c4d2e0',
   # 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': '2e0c8d2cbba7f0e7c00dee5331216df452288514',
+  'v8_revision': 'c5350347a7ff55ad11f0944279b28dc8a3079636',
   # 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': 'fa416b18e3903d2f0bb6d7a9b6ac34e3e658b1bc',
+  'angle_revision': 'fe48632f2f47f9513c0557c331a8f346ed92c82d',
   # 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': 'bf58fbb14a8b235fb864fbc45c353174446da4ca',
+  'pdfium_revision': 'c758d9dd3f94c2dee89e7fdd50195af08f7e456c',
   # 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': '3680efbfbcc7f2e6f4d15cab3f3f4e3d45cbbbfb',
+  'catapult_revision': 'ea02aa5af9f1b334923b191aeaaf070cb3feebf1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/ash/DEPS b/ash/DEPS
index 02f6b464..4b1eb603 100644
--- a/ash/DEPS
+++ b/ash/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+device/bluetooth",
   "+cc/debug",
+  "+cc/output",
   "+components/prefs",
   "+components/quirks",
   "+components/session_manager",
diff --git a/ash/common/ash_switches.cc b/ash/common/ash_switches.cc
index 6c259f10..c493204 100644
--- a/ash/common/ash_switches.cc
+++ b/ash/common/ash_switches.cc
@@ -61,6 +61,10 @@
 // Enables mirrored screen.
 const char kAshEnableMirroredScreen[] = "ash-enable-mirrored-screen";
 
+// Enables a smoother animation for screen rotation.
+const char kAshEnableSmoothScreenRotation[] =
+    "ash-enable-smooth-screen-rotation";
+
 // Specifies the estimated time (in milliseconds) from VSYNC event until when
 // visible light can be noticed by the user.
 const char kAshEstimatedPresentationDelay[] =
diff --git a/ash/common/ash_switches.h b/ash/common/ash_switches.h
index d4f699c..c468473 100644
--- a/ash/common/ash_switches.h
+++ b/ash/common/ash_switches.h
@@ -28,6 +28,7 @@
 ASH_EXPORT extern const char kAshEnablePaletteOnAllDisplays[];
 ASH_EXPORT extern const char kAshEnableTouchView[];
 ASH_EXPORT extern const char kAshEnableMirroredScreen[];
+ASH_EXPORT extern const char kAshEnableSmoothScreenRotation[];
 ASH_EXPORT extern const char kAshEstimatedPresentationDelay[];
 ASH_EXPORT extern const char kAshForceEnablePalette[];
 ASH_EXPORT extern const char kAshForceTabletMode[];
diff --git a/ash/rotator/screen_rotation_animator.cc b/ash/rotator/screen_rotation_animator.cc
index b78ccd15..5128813 100644
--- a/ash/rotator/screen_rotation_animator.cc
+++ b/ash/rotator/screen_rotation_animator.cc
@@ -8,6 +8,7 @@
 #include <utility>
 #include <vector>
 
+#include "ash/common/ash_switches.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/rotator/screen_rotation_animation.h"
 #include "ash/rotator/screen_rotation_animator_observer.h"
@@ -16,6 +17,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_animation_element.h"
@@ -184,14 +187,6 @@
 
 }  // namespace
 
-struct ScreenRotationAnimator::ScreenRotationRequest {
-  ScreenRotationRequest(display::Display::Rotation to_rotation,
-                        display::Display::RotationSource from_source)
-      : new_rotation(to_rotation), source(from_source) {}
-  display::Display::Rotation new_rotation;
-  display::Display::RotationSource source;
-};
-
 ScreenRotationAnimator::ScreenRotationAnimator(int64_t display_id)
     : display_id_(display_id),
       is_rotating_(false),
@@ -212,9 +207,86 @@
   metrics_reporter_.reset();
 }
 
+void ScreenRotationAnimator::StartRotationAnimation(
+    std::unique_ptr<ScreenRotationRequest> rotation_request) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kAshEnableSmoothScreenRotation)) {
+    RequestCopyRootLayerAndAnimateRotation(std::move(rotation_request));
+  } else {
+    CreateOldLayerTree();
+    AnimateRotation(std::move(rotation_request));
+  }
+}
+
+void ScreenRotationAnimator::RequestCopyRootLayerAndAnimateRotation(
+    std::unique_ptr<ScreenRotationRequest> rotation_request) {
+  std::unique_ptr<cc::CopyOutputRequest> copy_output_request =
+      cc::CopyOutputRequest::CreateRequest(
+          CreateAfterCopyCallback(std::move(rotation_request)));
+  ui::Layer* layer = GetRootWindow(display_id_)->layer();
+  copy_output_request->set_area(gfx::Rect(layer->size()));
+  layer->RequestCopyOfOutput(std::move(copy_output_request));
+}
+
+ScreenRotationAnimator::CopyCallback
+ScreenRotationAnimator::CreateAfterCopyCallback(
+    std::unique_ptr<ScreenRotationRequest> rotation_request) {
+  return base::Bind(&ScreenRotationAnimator::OnRootLayerCopiedBeforeRotation,
+                    weak_factory_.GetWeakPtr(),
+                    base::Passed(&rotation_request));
+}
+
+void ScreenRotationAnimator::OnRootLayerCopiedBeforeRotation(
+    std::unique_ptr<ScreenRotationRequest> rotation_request,
+    std::unique_ptr<cc::CopyOutputResult> result) {
+  // If display was removed, should abort rotation.
+  if (!IsDisplayIdValid(display_id_)) {
+    ProcessAnimationQueue();
+    return;
+  }
+
+  // Fall back to recreate layers solution when the copy request has been
+  // canceled or failed. It would fail if, for examples: a) The layer is removed
+  // from the compositor and destroyed before committing the request to the
+  // compositor. b) The compositor is shutdown.
+  if (result->IsEmpty())
+    CreateOldLayerTree();
+  else
+    CopyOldLayerTree(std::move(result));
+  AnimateRotation(std::move(rotation_request));
+}
+
+void ScreenRotationAnimator::CreateOldLayerTree() {
+  old_layer_tree_owner_ = ::wm::RecreateLayers(GetRootWindow(display_id_));
+}
+
+void ScreenRotationAnimator::CopyOldLayerTree(
+    std::unique_ptr<cc::CopyOutputResult> result) {
+  cc::TextureMailbox texture_mailbox;
+  std::unique_ptr<cc::SingleReleaseCallback> release_callback;
+  result->TakeTexture(&texture_mailbox, &release_callback);
+  DCHECK(texture_mailbox.IsTexture());
+
+  aura::Window* root_window = GetRootWindow(display_id_);
+  gfx::Rect rect(root_window->layer()->size());
+  std::unique_ptr<ui::Layer> copy_layer = base::MakeUnique<ui::Layer>();
+  copy_layer->SetBounds(rect);
+  copy_layer->SetTextureMailbox(texture_mailbox, std::move(release_callback),
+                                rect.size());
+  old_layer_tree_owner_ =
+      base::MakeUnique<ui::LayerTreeOwner>(std::move(copy_layer));
+}
+
 void ScreenRotationAnimator::AnimateRotation(
     std::unique_ptr<ScreenRotationRequest> rotation_request) {
   aura::Window* root_window = GetRootWindow(display_id_);
+  std::unique_ptr<LayerCleanupObserver> old_layer_cleanup_observer(
+      new LayerCleanupObserver(weak_factory_.GetWeakPtr()));
+  ui::Layer* old_root_layer = old_layer_tree_owner_->root();
+  old_root_layer->set_name("ScreenRotationAnimator:old_layer_tree");
+  // Add the cloned layer tree in to the root, so it will be rendered.
+  root_window->layer()->Add(old_root_layer);
+  root_window->layer()->StackAtTop(old_root_layer);
 
   const gfx::Rect original_screen_bounds = root_window->GetTargetBounds();
 
@@ -229,18 +301,6 @@
 
   const gfx::Tween::Type tween_type = gfx::Tween::FAST_OUT_LINEAR_IN;
 
-  std::unique_ptr<ui::LayerTreeOwner> old_layer_tree =
-      ::wm::RecreateLayers(root_window);
-  old_layer_tree->root()->set_name("ScreenRotationAnimator:old_layer_tree");
-
-  // Add the cloned layer tree in to the root, so it will be rendered.
-  root_window->layer()->Add(old_layer_tree->root());
-  root_window->layer()->StackAtTop(old_layer_tree->root());
-
-  old_layer_tree_owner_ = std::move(old_layer_tree);
-  std::unique_ptr<LayerCleanupObserver> old_layer_cleanup_observer(
-      new LayerCleanupObserver(weak_factory_.GetWeakPtr()));
-
   Shell::Get()->display_manager()->SetDisplayRotation(
       display_id_, rotation_request->new_rotation, rotation_request->source);
 
@@ -248,7 +308,6 @@
   const gfx::Point pivot = gfx::Point(rotated_screen_bounds.width() / 2,
                                       rotated_screen_bounds.height() / 2);
 
-  ui::Layer* old_root_layer = old_layer_tree_owner_->root();
   // We must animate each non-cloned child layer individually because the cloned
   // layer was added as a child to |root_window|'s layer so that it will be
   // rendered.
@@ -327,7 +386,7 @@
     StopAnimating();
   } else {
     is_rotating_ = true;
-    AnimateRotation(std::move(rotation_request));
+    StartRotationAnimation(std::move(rotation_request));
   }
 }
 
diff --git a/ash/rotator/screen_rotation_animator.h b/ash/rotator/screen_rotation_animator.h
index b541106..1852033b 100644
--- a/ash/rotator/screen_rotation_animator.h
+++ b/ash/rotator/screen_rotation_animator.h
@@ -8,11 +8,16 @@
 #include <stdint.h>
 
 #include "ash/ash_export.h"
+#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "ui/display/display.h"
 
+namespace cc {
+class CopyOutputResult;
+}  // namespace cc
+
 namespace ui {
 class AnimationMetricsReporter;
 class Layer;
@@ -30,7 +35,7 @@
 class ASH_EXPORT ScreenRotationAnimator {
  public:
   explicit ScreenRotationAnimator(int64_t display_id);
-  ~ScreenRotationAnimator();
+  virtual ~ScreenRotationAnimator();
 
   // Rotates the display::Display specified by |display_id_| to the
   // |new_rotation| orientation, for the given |source|. The rotation will also
@@ -55,11 +60,46 @@
   // notifies |screen_rotation_animator_observer_|.
   void ProcessAnimationQueue();
 
+ protected:
+  using CopyCallback =
+      base::Callback<void(std::unique_ptr<cc::CopyOutputResult> result)>;
+  struct ScreenRotationRequest {
+    ScreenRotationRequest(display::Display::Rotation to_rotation,
+                          display::Display::RotationSource from_source)
+        : new_rotation(to_rotation), source(from_source) {}
+    display::Display::Rotation new_rotation;
+    display::Display::RotationSource source;
+  };
+
+  // This function can be overridden in unit test to test removing external
+  // display.
+  virtual CopyCallback CreateAfterCopyCallback(
+      std::unique_ptr<ScreenRotationRequest> rotation_request);
+
  private:
   friend class ash::test::ScreenRotationAnimatorTestApi;
-  struct ScreenRotationRequest;
 
-  // Set the screen orientation to |new_rotation| and animate the change. The
+  void StartRotationAnimation(
+      std::unique_ptr<ScreenRotationRequest> rotation_request);
+
+  // This is an asynchronous call to request copy output of root layer.
+  void RequestCopyRootLayerAndAnimateRotation(
+      std::unique_ptr<ScreenRotationRequest> rotation_request);
+
+  // The callback in |RequestCopyRootLayerAndAnimateRotation()|.
+  void OnRootLayerCopiedBeforeRotation(
+      std::unique_ptr<ScreenRotationRequest> rotation_request,
+      std::unique_ptr<cc::CopyOutputResult> result);
+
+  // Recreates all |root_window| layers.
+  void CreateOldLayerTree();
+
+  // Requests a copy of |root_window| root layer output.
+  void CopyOldLayerTree(std::unique_ptr<cc::CopyOutputResult> result);
+
+  // Note: Only call this function when the |old_layer_tree_owner_| is set up
+  // properly.
+  // Sets the screen orientation to |new_rotation| and animate the change. The
   // animation will rotate the initial orientation's layer towards the new
   // orientation through |rotation_degrees| while fading out, and the new
   // orientation's layer will be rotated in to the |new_orientation| through
diff --git a/ash/rotator/screen_rotation_animator_unittest.cc b/ash/rotator/screen_rotation_animator_unittest.cc
index 9a84d05..ec03db5a 100644
--- a/ash/rotator/screen_rotation_animator_unittest.cc
+++ b/ash/rotator/screen_rotation_animator_unittest.cc
@@ -3,12 +3,18 @@
 // found in the LICENSE file.
 
 #include "ash/rotator/screen_rotation_animator.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm_shell.h"
 #include "ash/rotator/screen_rotation_animator_observer.h"
 #include "ash/rotator/test/screen_rotation_animator_test_api.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
+#include "base/callback_forward.h"
+#include "base/command_line.h"
 #include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "cc/output/copy_output_request.h"
+#include "cc/output/copy_output_result.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/display/display.h"
 #include "ui/display/manager/display_manager.h"
@@ -49,6 +55,44 @@
   DISALLOW_COPY_AND_ASSIGN(AnimationObserver);
 };
 
+class TestScreenRotationAnimator : public ScreenRotationAnimator {
+ public:
+  TestScreenRotationAnimator(int64_t display_id, const base::Closure& callback);
+  ~TestScreenRotationAnimator() override {}
+
+ private:
+  CopyCallback CreateAfterCopyCallback(
+      std::unique_ptr<ScreenRotationRequest> rotation_request) override;
+
+  void IntersectBefore(CopyCallback next_callback,
+                       std::unique_ptr<cc::CopyOutputResult> result);
+
+  base::Closure intersect_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestScreenRotationAnimator);
+};
+
+TestScreenRotationAnimator::TestScreenRotationAnimator(
+    int64_t display_id,
+    const base::Closure& callback)
+    : ScreenRotationAnimator(display_id), intersect_callback_(callback) {}
+
+ScreenRotationAnimator::CopyCallback
+TestScreenRotationAnimator::CreateAfterCopyCallback(
+    std::unique_ptr<ScreenRotationRequest> rotation_request) {
+  CopyCallback next_callback = ScreenRotationAnimator::CreateAfterCopyCallback(
+      std::move(rotation_request));
+  return base::Bind(&TestScreenRotationAnimator::IntersectBefore,
+                    base::Unretained(this), next_callback);
+}
+
+void TestScreenRotationAnimator::IntersectBefore(
+    CopyCallback next_callback,
+    std::unique_ptr<cc::CopyOutputResult> result) {
+  intersect_callback_.Run();
+  next_callback.Run(std::move(result));
+}
+
 }  // namespace
 
 class ScreenRotationAnimatorTest : public test::AshTestBase {
@@ -59,38 +103,65 @@
   // AshTestBase:
   void SetUp() override;
 
+  void RemoveSecondaryDisplay(const std::string& specs);
+
  protected:
   int64_t display_id() const { return display_.id(); }
 
-  ScreenRotationAnimator* animator() { return animator_.get(); }
+  TestScreenRotationAnimator* animator() { return animator_.get(); }
+
+  void SetScreenRotationAnimator(int64_t display_id,
+                                 const base::Closure& callback);
 
   test::ScreenRotationAnimatorTestApi* test_api() { return test_api_.get(); }
 
-  std::unique_ptr<ui::ScopedAnimationDurationScaleMode> non_zero_duration_mode_;
+  void WaitForCopyCallback();
+
+  std::unique_ptr<base::RunLoop> run_loop_;
 
  private:
   display::Display display_;
 
-  std::unique_ptr<ScreenRotationAnimator> animator_;
+  std::unique_ptr<TestScreenRotationAnimator> animator_;
 
   std::unique_ptr<test::ScreenRotationAnimatorTestApi> test_api_;
 
+  std::unique_ptr<ui::ScopedAnimationDurationScaleMode> non_zero_duration_mode_;
+
   DISALLOW_COPY_AND_ASSIGN(ScreenRotationAnimatorTest);
 };
 
+void ScreenRotationAnimatorTest::RemoveSecondaryDisplay(
+    const std::string& specs) {
+  UpdateDisplay(specs);
+  run_loop_->QuitWhenIdle();
+}
+
 void ScreenRotationAnimatorTest::SetUp() {
   AshTestBase::SetUp();
 
   display_ = display::Screen::GetScreen()->GetPrimaryDisplay();
-  animator_ = base::MakeUnique<ScreenRotationAnimator>(display_.id());
-  test_api_ =
-      base::MakeUnique<test::ScreenRotationAnimatorTestApi>(animator_.get());
-  test_api()->DisableAnimationTimers();
+  run_loop_ = base::MakeUnique<base::RunLoop>();
+  SetScreenRotationAnimator(display_.id(), run_loop_->QuitWhenIdleClosure());
   non_zero_duration_mode_ =
       base::MakeUnique<ui::ScopedAnimationDurationScaleMode>(
           ui::ScopedAnimationDurationScaleMode::SLOW_DURATION);
 }
 
+void ScreenRotationAnimatorTest::SetScreenRotationAnimator(
+    int64_t display_id,
+    const base::Closure& callback) {
+  animator_ =
+      base::MakeUnique<TestScreenRotationAnimator>(display_id, callback);
+  test_api_ =
+      base::MakeUnique<test::ScreenRotationAnimatorTestApi>(animator_.get());
+  test_api()->DisableAnimationTimers();
+}
+
+void ScreenRotationAnimatorTest::WaitForCopyCallback() {
+  run_loop_->Run();
+}
+
 TEST_F(ScreenRotationAnimatorTest, ShouldNotifyObserver) {
   // TODO(wutao): needs GetDisplayInfo http://crbug.com/622480.
   if (WmShell::Get()->IsRunningInMash()) {
@@ -223,4 +294,54 @@
   EXPECT_EQ(display::Display::ROTATE_270, GetDisplayRotation(display_id()));
 }
 
+// Test enable smooth screen rotation code path.
+TEST_F(ScreenRotationAnimatorTest, RotatesToDifferentRotationWithCopyCallback) {
+  // TODO(wutao): needs GetDisplayInfo http://crbug.com/622480.
+  if (WmShell::Get()->IsRunningInMash()) {
+    ASSERT_TRUE(WmShell::Get()->GetDisplayInfo(display_id()).id() !=
+                display_id());
+    return;
+  }
+
+  SetDisplayRotation(display_id(), display::Display::ROTATE_0);
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableSmoothScreenRotation);
+  animator()->Rotate(display::Display::ROTATE_90,
+                     display::Display::RotationSource::ROTATION_SOURCE_USER);
+  WaitForCopyCallback();
+  EXPECT_TRUE(test_api()->HasActiveAnimations());
+
+  test_api()->CompleteAnimations();
+  EXPECT_FALSE(test_api()->HasActiveAnimations());
+}
+
+// If the external display is removed, it should not crash.
+TEST_F(ScreenRotationAnimatorTest, RemoveSecondaryDisplayAfterCopyCallback) {
+  // TODO(wutao): needs GetDisplayInfo http://crbug.com/622480.
+  if (WmShell::Get()->IsRunningInMash()) {
+    ASSERT_TRUE(WmShell::Get()->GetDisplayInfo(display_id()).id() !=
+                display_id());
+    return;
+  }
+
+  UpdateDisplay("640x480,800x600");
+  EXPECT_EQ(2U, display_manager()->GetNumDisplays());
+
+  const unsigned int primary_display_id =
+      display_manager()->GetDisplayAt(0).id();
+  SetScreenRotationAnimator(
+      display_manager()->GetDisplayAt(1).id(),
+      base::Bind(&ScreenRotationAnimatorTest::RemoveSecondaryDisplay,
+                 base::Unretained(this), "640x480"));
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kAshEnableSmoothScreenRotation);
+  SetDisplayRotation(display_manager()->GetDisplayAt(1).id(),
+                     display::Display::ROTATE_0);
+  animator()->Rotate(display::Display::ROTATE_90,
+                     display::Display::RotationSource::ROTATION_SOURCE_USER);
+  WaitForCopyCallback();
+  EXPECT_EQ(1U, display_manager()->GetNumDisplays());
+  EXPECT_EQ(primary_display_id, display_manager()->GetDisplayAt(0).id());
+}
+
 }  // namespace ash
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc
index 65dc5ce..30749906 100644
--- a/base/files/file_util_win.cc
+++ b/base/files/file_util_win.cc
@@ -20,6 +20,7 @@
 
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
+#include "base/guid.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/metrics/histogram.h"
@@ -340,25 +341,48 @@
 bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
   ThreadRestrictions::AssertIOAllowed();
 
-  wchar_t temp_name[MAX_PATH + 1];
+  // Use GUID instead of ::GetTempFileName() to generate unique file names.
+  // "Due to the algorithm used to generate file names, GetTempFileName can
+  // perform poorly when creating a large number of files with the same prefix.
+  // In such cases, it is recommended that you construct unique file names based
+  // on GUIDs."
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364991(v=vs.85).aspx
 
-  if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) {
+  FilePath temp_name;
+  bool create_file_success = false;
+
+  // Although it is nearly impossible to get a duplicate name with GUID, we
+  // still use a loop here in case it happens.
+  for (int i = 0; i < 100; ++i) {
+    temp_name = dir.Append(ASCIIToUTF16(base::GenerateGUID()) + L".tmp");
+    File file(temp_name,
+              File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
+    if (file.IsValid()) {
+      file.Close();
+      create_file_success = true;
+      break;
+    }
+  }
+
+  // Exist early if we can't create an unique name.
+  if (!create_file_success) {
     DPLOG(WARNING) << "Failed to get temporary file name in "
                    << UTF16ToUTF8(dir.value());
     return false;
   }
 
   wchar_t long_temp_name[MAX_PATH + 1];
-  DWORD long_name_len = GetLongPathName(temp_name, long_temp_name, MAX_PATH);
+  DWORD long_name_len =
+      GetLongPathName(temp_name.value().c_str(), long_temp_name, MAX_PATH);
   if (long_name_len > MAX_PATH || long_name_len == 0) {
     // GetLongPathName() failed, but we still have a temporary file.
-    *temp_file = FilePath(temp_name);
+    *temp_file = std::move(temp_name);
     return true;
   }
 
   FilePath::StringType long_temp_name_str;
   long_temp_name_str.assign(long_temp_name, long_name_len);
-  *temp_file = FilePath(long_temp_name_str);
+  *temp_file = FilePath(std::move(long_temp_name_str));
   return true;
 }
 
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index 057e3071..d79d7f32 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -356,6 +356,7 @@
     ]
     srcjar_deps = [ ":test_support_java_aidl" ]
     java_files = [
+      "android/java/src/org/chromium/base/ChildProcessConstants.java",
       "android/java/src/org/chromium/base/MainReturnCodeResult.java",
       "android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java",
       "android/java/src/org/chromium/base/MultiprocessTestClientService.java",
@@ -374,7 +375,9 @@
       "//base/android/java/src",
     ]
     sources = [
+      "android/java/src/org/chromium/base/ITestCallback.aidl",
       "android/java/src/org/chromium/base/ITestClient.aidl",
+      "android/java/src/org/chromium/base/ITestController.aidl",
     ]
   }
 }
diff --git a/base/test/android/java/src/org/chromium/base/ChildProcessConstants.java b/base/test/android/java/src/org/chromium/base/ChildProcessConstants.java
new file mode 100644
index 0000000..457c59cb
--- /dev/null
+++ b/base/test/android/java/src/org/chromium/base/ChildProcessConstants.java
@@ -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.
+
+package org.chromium.base;
+
+/**
+ * Constants to be used by child processes.
+ */
+public interface ChildProcessConstants {
+    // Key for the command line.
+    public static final String EXTRA_COMMAND_LINE = "org.chromium.base.extra.command_line";
+
+    // Key for the file descriptors that should be mapped in the child process..
+    public static final String EXTRA_FILES = "org.chromium.base.extra.extra_files";
+}
diff --git a/base/test/android/java/src/org/chromium/base/ITestCallback.aidl b/base/test/android/java/src/org/chromium/base/ITestCallback.aidl
new file mode 100644
index 0000000..48d9994
--- /dev/null
+++ b/base/test/android/java/src/org/chromium/base/ITestCallback.aidl
@@ -0,0 +1,16 @@
+// 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.
+
+package org.chromium.base;
+
+import org.chromium.base.ITestController;
+import org.chromium.base.MainReturnCodeResult;
+import org.chromium.base.process_launcher.FileDescriptorInfo;
+
+/**
+ * This interface is called by the child process to pass its controller to its parent.
+ */
+oneway interface ITestCallback {
+  void childConnected(ITestController controller);
+}
diff --git a/base/test/android/java/src/org/chromium/base/ITestClient.aidl b/base/test/android/java/src/org/chromium/base/ITestClient.aidl
index 22acdfbca..227725c 100644
--- a/base/test/android/java/src/org/chromium/base/ITestClient.aidl
+++ b/base/test/android/java/src/org/chromium/base/ITestClient.aidl
@@ -9,37 +9,22 @@
 
 /**
  * This interface is used to control child processes.
+ * TODO(jcivelli): http://crbug.com/702316 remove this once ChildProcessLauncher has moved to base/.
  */
 interface ITestClient {
+  // On the first call to this method, the service will record the calling PID
+  // and return true. Subsequent calls will only return true if the calling PID
+  // is the same as the recorded one.
+  boolean bindToCaller();
+
   /**
    * Runs the native <code>main</code> method in that service's process.
-   * @param args the arguments passed to <code>main</code>
-   * @param fdsToMap a list of file descriptors that are mapped in the native code
-   * in <code>base::GlobalDescriptors</code>.
+   * @param args contains the arguments passed to <code>main</code> as well as the files to be
+   * mapped in the service process, see <code>org.chromium.base.ChildProcessConstants</code>.
+   * @param callback a callback used to communicate back to the parent process. (until we use the
+   * common launcher in base/, we'll use this test implentation and this callback is an
+   * ITestCallback).
    * @return the process ID for the service's process.
    */
-  int launch(in String[] args, in FileDescriptorInfo[] fdsToMap);
-
-  /**
-   * Blocks until the <code>main</code> method started with {@link #launch()} returns, or returns
-   * immediately if main has already returned.
-   * @param timeoutMs time in milliseconds after which this method returns even if the main method
-   * has not returned yet.
-   * @return a result containing whether a timeout occured and the value returned by the
-   * <code>main</code> method
-   */
-  MainReturnCodeResult waitForMainToReturn(int timeoutMs);
-
-  /**
-   * Forces the service process to terminate and block until the process stops.
-   * @param exitCode the exit code the process should terminate with.
-   * @return always true, a return value is only returned to force the call to be synchronous.
-   */
-  boolean forceStopSynchronous(int exitCode);
-
-  /**
-   * Forces the service process to terminate.
-   * @param exitCode the exit code the process should terminate with.
-   */
-  void forceStop(int exitCode);
+  int setupConnection(in Bundle args, IBinder callback);
 }
diff --git a/base/test/android/java/src/org/chromium/base/ITestController.aidl b/base/test/android/java/src/org/chromium/base/ITestController.aidl
new file mode 100644
index 0000000..4bf7429
--- /dev/null
+++ b/base/test/android/java/src/org/chromium/base/ITestController.aidl
@@ -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.
+
+package org.chromium.base;
+
+import org.chromium.base.MainReturnCodeResult;
+import org.chromium.base.process_launcher.FileDescriptorInfo;
+
+/**
+ * This interface is used to control child processes.
+ */
+interface ITestController {
+   /**
+   * Blocks until the <code>main</code> method started with {@link #launch()} returns, or returns
+   * immediately if main has already returned.
+   * @param timeoutMs time in milliseconds after which this method returns even if the main method
+   * has not returned yet.
+   * @return a result containing whether a timeout occured and the value returned by the
+   * <code>main</code> method
+   */
+  MainReturnCodeResult waitForMainToReturn(int timeoutMs);
+
+  /**
+   * Forces the service process to terminate and block until the process stops.
+   * @param exitCode the exit code the process should terminate with.
+   * @return always true, a return value is only returned to force the call to be synchronous.
+   */
+  boolean forceStopSynchronous(int exitCode);
+
+  /**
+   * Forces the service process to terminate.
+   * @param exitCode the exit code the process should terminate with.
+   */
+  void forceStop(int exitCode);
+}
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
index 9cdf5242..d5dca6c 100644
--- a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
+++ b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
@@ -8,6 +8,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -21,6 +22,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Queue;
+import java.util.concurrent.CountDownLatch;
 
 import javax.annotation.concurrent.GuardedBy;
 
@@ -99,19 +101,39 @@
     }
 
     private static class ClientServiceConnection implements ServiceConnection {
-        private final String[] mCommandLine;
-        private final FileDescriptorInfo[] mFilesToMap;
+        private final Bundle mSetupBundle;
         private final Object mConnectedLock = new Object();
+        private final CountDownLatch mPidReceived = new CountDownLatch(1);
         private final int mSlot;
         private ITestClient mService = null;
         @GuardedBy("mConnectedLock")
         private boolean mConnected;
         private int mPid;
+        private ITestController mTestController;
+        private final ITestCallback.Stub mCallback = new ITestCallback.Stub() {
+            public void childConnected(ITestController controller) {
+                mTestController = controller;
+                // This method can be called before onServiceConnected below has set the PID.
+                // Wait for mPid to be set before notifying.
+                try {
+                    mPidReceived.await();
+                } catch (InterruptedException ie) {
+                    Log.e(TAG, "Interrupted while waiting for connection PID.");
+                    return;
+                }
+                // Now we are fully initialized, notify clients.
+                synchronized (mConnectedLock) {
+                    mConnected = true;
+                    mConnectedLock.notifyAll();
+                }
+            }
+        };
 
         ClientServiceConnection(int slot, String[] commandLine, FileDescriptorInfo[] filesToMap) {
             mSlot = slot;
-            mCommandLine = commandLine;
-            mFilesToMap = filesToMap;
+            mSetupBundle = new Bundle();
+            mSetupBundle.putStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE, commandLine);
+            mSetupBundle.putParcelableArray(ChildProcessConstants.EXTRA_FILES, filesToMap);
         }
 
         public void waitForConnection() {
@@ -130,11 +152,12 @@
         public void onServiceConnected(ComponentName className, IBinder service) {
             try {
                 mService = ITestClient.Stub.asInterface(service);
-                mPid = mService.launch(mCommandLine, mFilesToMap);
-                synchronized (mConnectedLock) {
-                    mConnected = true;
-                    mConnectedLock.notifyAll();
+                if (!mService.bindToCaller()) {
+                    Log.e(TAG, "Failed to bind to child service");
+                    return;
                 }
+                mPid = mService.setupConnection(mSetupBundle, mCallback);
+                mPidReceived.countDown();
             } catch (RemoteException e) {
                 Log.e(TAG, "Connect failed");
             }
@@ -149,8 +172,8 @@
             sConnectionAllocator.freeConnection(this);
         }
 
-        public ITestClient getService() {
-            return mService;
+        public ITestController getTestController() {
+            return mTestController;
         }
 
         public String getServiceClassName() {
@@ -228,7 +251,7 @@
             return null;
         }
         try {
-            return connection.getService().waitForMainToReturn(timeoutMs);
+            return connection.getTestController().waitForMainToReturn(timeoutMs);
         } catch (RemoteException e) {
             Log.e(TAG, "Remote call to waitForMainToReturn failed.");
             return null;
@@ -246,9 +269,9 @@
         }
         try {
             if (wait) {
-                connection.getService().forceStopSynchronous(exitCode);
+                connection.getTestController().forceStopSynchronous(exitCode);
             } else {
-                connection.getService().forceStop(exitCode);
+                connection.getTestController().forceStop(exitCode);
             }
         } catch (RemoteException e) {
             // We expect this failure, since the forceStop's service implementation calls
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientService.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientService.java
index d601afe..58a6c02 100644
--- a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientService.java
+++ b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientService.java
@@ -6,9 +6,12 @@
 
 import android.app.Service;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Parcelable;
 import android.os.Process;
+import android.os.RemoteException;
 
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.library_loader.LibraryLoader;
@@ -34,29 +37,7 @@
     @GuardedBy("mResultLock")
     private MainReturnCodeResult mResult;
 
-    private final ITestClient.Stub mBinder = new ITestClient.Stub() {
-        @Override
-        public int launch(final String[] commandLine, FileDescriptorInfo[] fdsToMap) {
-            final int[] fdKeys = new int[fdsToMap.length];
-            final int[] fdFds = new int[fdsToMap.length];
-            for (int i = 0; i < fdsToMap.length; i++) {
-                fdKeys[i] = fdsToMap[i].id;
-                // Take ownership of the file descriptor so they outlive the FileDescriptorInfo
-                // instances. Native code will own them.
-                fdFds[i] = fdsToMap[i].fd.detachFd();
-            }
-            // Don't run main directly, it would block and the response would not be returned.
-            // We post to the main thread as this thread does not have a Looper.
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    int result = MainRunner.runMain(commandLine, fdKeys, fdFds);
-                    setMainReturnValue(result);
-                }
-            });
-            return Process.myPid();
-        }
-
+    private final ITestController.Stub mTestController = new ITestController.Stub() {
         @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE")
         @Override
         public MainReturnCodeResult waitForMainToReturn(int timeoutMs) {
@@ -91,6 +72,63 @@
         }
     };
 
+    private final ITestClient.Stub mBinder = new ITestClient.Stub() {
+        @Override
+        public boolean bindToCaller() {
+            return true;
+        }
+
+        @Override
+        public int setupConnection(Bundle args, final IBinder callback) {
+            // Required to unparcel FileDescriptorInfo.
+            args.setClassLoader(getApplicationContext().getClassLoader());
+
+            final String[] commandLine =
+                    args.getStringArray(ChildProcessConstants.EXTRA_COMMAND_LINE);
+            final Parcelable[] fdInfosAsParcelable =
+                    args.getParcelableArray(ChildProcessConstants.EXTRA_FILES);
+
+            FileDescriptorInfo[] fdsToMap = new FileDescriptorInfo[fdInfosAsParcelable.length];
+            System.arraycopy(fdInfosAsParcelable, 0, fdsToMap, 0, fdInfosAsParcelable.length);
+
+            final int[] fdKeys = new int[fdsToMap.length];
+            final int[] fdFds = new int[fdsToMap.length];
+            for (int i = 0; i < fdsToMap.length; i++) {
+                fdKeys[i] = fdsToMap[i].id;
+                // Take ownership of the file descriptor so they outlive the FileDescriptorInfo
+                // instances. Native code will own them.
+                fdFds[i] = fdsToMap[i].fd.detachFd();
+            }
+
+            // Prevent potential deadlocks by letting this method return before calling back to the
+            // launcher: the childConnected implementation on the launcher side might block until
+            // this method returns.
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        ITestCallback testCallback = ITestCallback.Stub.asInterface(callback);
+                        testCallback.childConnected(mTestController);
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Failed to notify parent process of connection.");
+                    }
+                }
+            });
+
+            // Don't run main directly, it would block and the response would not be returned.
+            // We post to the main thread as this thread does not have a Looper.
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    int result = MainRunner.runMain(commandLine, fdKeys, fdFds);
+                    setMainReturnValue(result);
+                }
+            });
+
+            return Process.myPid();
+        }
+    };
+
     @SuppressFBWarnings("DM_EXIT")
     @Override
     public void onCreate() {
diff --git a/cc/ipc/compositor_frame_metadata_struct_traits.cc b/cc/ipc/compositor_frame_metadata_struct_traits.cc
index bc0d07d..fae339a 100644
--- a/cc/ipc/compositor_frame_metadata_struct_traits.cc
+++ b/cc/ipc/compositor_frame_metadata_struct_traits.cc
@@ -38,7 +38,7 @@
   out->bottom_controls_height = data.bottom_controls_height();
   out->bottom_controls_shown_ratio = data.bottom_controls_shown_ratio();
   out->content_source_id = data.content_source_id();
-
+  out->frame_token = data.frame_token();
   out->root_background_color = data.root_background_color();
   out->can_activate_before_dependencies =
       data.can_activate_before_dependencies();
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index 2049f61..5115809 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -374,6 +374,7 @@
   SurfaceId id(FrameSinkId(1234, 4321),
                LocalSurfaceId(5678, base::UnguessableToken::Create()));
   referenced_surfaces.push_back(id);
+  uint32_t frame_token = 0xdeadbeef;
 
   CompositorFrameMetadata input;
   input.device_scale_factor = device_scale_factor;
@@ -396,6 +397,7 @@
   input.selection = selection;
   input.latency_info = latency_infos;
   input.referenced_surfaces = referenced_surfaces;
+  input.frame_token = frame_token;
 
   mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
   CompositorFrameMetadata output;
@@ -427,6 +429,7 @@
   EXPECT_EQ(referenced_surfaces.size(), output.referenced_surfaces.size());
   for (uint32_t i = 0; i < referenced_surfaces.size(); ++i)
     EXPECT_EQ(referenced_surfaces[i], output.referenced_surfaces[i]);
+  EXPECT_EQ(frame_token, output.frame_token);
 }
 
 TEST_F(StructTraitsTest, CopyOutputRequest_BitmapRequest) {
diff --git a/cc/layers/render_surface_impl_unittest.cc b/cc/layers/render_surface_impl_unittest.cc
index 351d2acb..49f2f7d 100644
--- a/cc/layers/render_surface_impl_unittest.cc
+++ b/cc/layers/render_surface_impl_unittest.cc
@@ -72,7 +72,9 @@
   scoped_refptr<FakeRasterSource> raster_source =
       FakeRasterSource::CreateFilledSolidColor(layer_size);
 
-  LayerTestCommon::LayerImplTest impl;
+  LayerTreeSettings settings;
+  settings.layer_transforms_should_scale_layer_contents = true;
+  LayerTestCommon::LayerImplTest impl(settings);
   std::unique_ptr<LayerImpl> root =
       LayerImpl::Create(impl.host_impl()->active_tree(), 2);
   std::unique_ptr<LayerImpl> surface =
diff --git a/cc/output/program_binding.cc b/cc/output/program_binding.cc
index 8402e82..a8f4b6a 100644
--- a/cc/output/program_binding.cc
+++ b/cc/output/program_binding.cc
@@ -177,24 +177,21 @@
   return !!program_;
 }
 
-bool ProgramBindingBase::Link(GLES2Interface* context,
-                              const std::string& vertex_source,
-                              const std::string& fragment_source) {
+bool ProgramBindingBase::Link(GLES2Interface* context) {
   context->LinkProgram(program_);
   CleanupShaders(context);
   if (!program_)
     return false;
+#ifndef NDEBUG
   int linked = 0;
   context->GetProgramiv(program_, GL_LINK_STATUS, &linked);
   if (!linked) {
     char buffer[1024] = "";
     context->GetProgramInfoLog(program_, sizeof(buffer), nullptr, buffer);
-    LOG(ERROR) << "Error linking shader: " << buffer << "\n"
-               << "Vertex shader:\n"
-               << vertex_source << "Fragment shader:\n"
-               << fragment_source;
+    DLOG(ERROR) << "Error compiling shader: " << buffer;
     return false;
   }
+#endif
   return true;
 }
 
@@ -224,16 +221,17 @@
       shader_source_str,
       shader_length);
   context->CompileShader(shader);
+#if DCHECK_IS_ON()
   int compiled = 0;
   context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
   if (!compiled) {
     char buffer[1024] = "";
     context->GetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
-    LOG(ERROR) << "Error compiling shader: " << buffer << "\n"
-               << "Shader program:\n"
-               << shader_source;
+    DLOG(ERROR) << "Error compiling shader: " << buffer
+                << "\n shader program: " << shader_source;
     return 0u;
   }
+#endif
   return shader;
 }
 
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h
index ce45f269..6f1bc91 100644
--- a/cc/output/program_binding.h
+++ b/cc/output/program_binding.h
@@ -32,9 +32,7 @@
   bool Init(gpu::gles2::GLES2Interface* context,
             const std::string& vertex_shader,
             const std::string& fragment_shader);
-  bool Link(gpu::gles2::GLES2Interface* context,
-            const std::string& vertex_source,
-            const std::string& fragment_source);
+  bool Link(gpu::gles2::GLES2Interface* context);
   void Cleanup(gpu::gles2::GLES2Interface* context);
 
   unsigned program() const { return program_; }
@@ -405,10 +403,9 @@
     if (IsContextLost(context_provider->ContextGL()))
       return;
 
-    std::string vertex_source = vertex_shader_.GetShaderString();
-    std::string fragment_source = fragment_shader_.GetShaderString();
-    if (!ProgramBindingBase::Init(context_provider->ContextGL(), vertex_source,
-                                  fragment_source)) {
+    if (!ProgramBindingBase::Init(context_provider->ContextGL(),
+                                  vertex_shader_.GetShaderString(),
+                                  fragment_shader_.GetShaderString())) {
       DCHECK(IsContextLost(context_provider->ContextGL()));
       return;
     }
@@ -420,7 +417,7 @@
                           program_, &base_uniform_index);
 
     // Link after binding uniforms
-    if (!Link(context_provider->ContextGL(), vertex_source, fragment_source)) {
+    if (!Link(context_provider->ContextGL())) {
       DCHECK(IsContextLost(context_provider->ContextGL()));
       return;
     }
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index b59c54d..6298b78 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -140,6 +140,10 @@
   TryEndTest();
 }
 
+void LayerTreePixelTest::InitializeSettings(LayerTreeSettings* settings) {
+  settings->layer_transforms_should_scale_layer_contents = true;
+}
+
 void LayerTreePixelTest::TryEndTest() {
   if (!result_bitmap_)
     return;
diff --git a/cc/test/layer_tree_pixel_test.h b/cc/test/layer_tree_pixel_test.h
index d2ecca30..2d13e37 100644
--- a/cc/test/layer_tree_pixel_test.h
+++ b/cc/test/layer_tree_pixel_test.h
@@ -50,6 +50,7 @@
   void SetupTree() override;
   void AfterTest() override;
   void EndTest() override;
+  void InitializeSettings(LayerTreeSettings* settings) override;
 
   void TryEndTest();
 
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index b533594..79ab6ba 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -1360,6 +1360,67 @@
       base::Bind(callback, task_set_finished_weak_ptr_factory_.GetWeakPtr())));
 }
 
+std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+TileManager::ActivationStateAsValue() {
+  auto state = base::MakeUnique<base::trace_event::TracedValue>();
+  state->SetString("tree_priority",
+                   TreePriorityToString(global_state_.tree_priority));
+  state->SetInteger("soft_memory_limit",
+                    global_state_.soft_memory_limit_in_bytes);
+  state->SetInteger("hard_memory_limit",
+                    global_state_.soft_memory_limit_in_bytes);
+  state->SetInteger("pending_required_for_activation_callback_id",
+                    pending_required_for_activation_callback_id_);
+  state->SetInteger("current_memory_usage",
+                    resource_pool_->memory_usage_bytes());
+  state->SetInteger("current_resource_usage", resource_pool_->resource_count());
+
+  // Use a custom tile_as_value, instead of Tile::AsValueInto, since we don't
+  // need all of the state that would be captured by other functions.
+  auto tile_as_value = [](const PrioritizedTile& prioritized_tile,
+                          base::trace_event::TracedValue* value) {
+    Tile* tile = prioritized_tile.tile();
+    TilePriority priority = prioritized_tile.priority();
+
+    value->SetInteger("id", tile->id());
+    value->SetString("content_rect", tile->content_rect().ToString());
+    value->SetDouble("contents_scale", tile->contents_scale());
+    value->SetBoolean("is_ready_to_draw", tile->draw_info().IsReadyToDraw());
+    value->SetString("resolution", TileResolutionToString(priority.resolution));
+    value->SetString("priority_bin",
+                     TilePriorityBinToString(priority.priority_bin));
+    value->SetDouble("distance_to_visible", priority.distance_to_visible);
+    value->SetBoolean("required_for_activation",
+                      tile->required_for_activation());
+    value->SetBoolean("required_for_draw", tile->required_for_draw());
+  };
+
+  std::unique_ptr<RasterTilePriorityQueue> raster_priority_queue(
+      client_->BuildRasterQueue(global_state_.tree_priority,
+                                RasterTilePriorityQueue::Type::ALL));
+  state->BeginArray("raster_tiles");
+  for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
+    state->BeginDictionary();
+    tile_as_value(raster_priority_queue->Top(), state.get());
+    state->EndDictionary();
+  }
+  state->EndArray();
+
+  std::unique_ptr<RasterTilePriorityQueue> required_priority_queue(
+      client_->BuildRasterQueue(
+          global_state_.tree_priority,
+          RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
+  state->BeginArray("activation_tiles");
+  for (; !required_priority_queue->IsEmpty(); required_priority_queue->Pop()) {
+    state->BeginDictionary();
+    tile_as_value(required_priority_queue->Top(), state.get());
+    state->EndDictionary();
+  }
+  state->EndArray();
+
+  return std::move(state);
+}
+
 TileManager::MemoryUsage::MemoryUsage()
     : memory_bytes_(0), resource_count_(0) {}
 
diff --git a/cc/tiles/tile_manager.h b/cc/tiles/tile_manager.h
index 5de0a154..3327cf1 100644
--- a/cc/tiles/tile_manager.h
+++ b/cc/tiles/tile_manager.h
@@ -229,6 +229,11 @@
   // CheckerImageTrackerClient implementation.
   void NeedsInvalidationForCheckerImagedTiles() override;
 
+  // This method can only be used for debugging information, since it performs a
+  // non trivial amount of work.
+  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+  ActivationStateAsValue();
+
  protected:
   friend class Tile;
   // Must be called by tile during destruction.
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 1bcf179..27eb425d 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -899,7 +899,8 @@
 
 void UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
                                           PropertyTrees* property_trees,
-                                          bool can_render_to_separate_surface) {
+                                          bool can_render_to_separate_surface,
+                                          bool can_adjust_raster_scales) {
   bool render_surfaces_need_update = false;
   if (property_trees->non_root_surfaces_enabled !=
       can_render_to_separate_surface) {
@@ -907,6 +908,11 @@
     property_trees->transform_tree.set_needs_update(true);
     render_surfaces_need_update = true;
   }
+  if (property_trees->can_adjust_raster_scales != can_adjust_raster_scales) {
+    property_trees->can_adjust_raster_scales = can_adjust_raster_scales;
+    property_trees->transform_tree.set_needs_update(true);
+    render_surfaces_need_update = true;
+  }
   if (property_trees->transform_tree.needs_update()) {
     property_trees->clip_tree.set_needs_update(true);
     property_trees->effect_tree.set_needs_update(true);
diff --git a/cc/trees/draw_property_utils.h b/cc/trees/draw_property_utils.h
index 3fafc01..b5ff981 100644
--- a/cc/trees/draw_property_utils.h
+++ b/cc/trees/draw_property_utils.h
@@ -45,7 +45,8 @@
 void CC_EXPORT
 UpdatePropertyTreesAndRenderSurfaces(LayerImpl* root_layer,
                                      PropertyTrees* property_trees,
-                                     bool can_render_to_separate_surface);
+                                     bool can_render_to_separate_surface,
+                                     bool can_adjust_raster_scales);
 
 void CC_EXPORT FindLayersThatNeedUpdates(LayerTreeHost* layer_tree_host,
                                          const PropertyTrees* property_trees,
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 8ff9f718..7169a2a 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -487,7 +487,8 @@
           inputs->device_transform, inputs->property_trees);
       draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
           inputs->root_layer, inputs->property_trees,
-          inputs->can_render_to_separate_surface);
+          inputs->can_render_to_separate_surface,
+          inputs->can_adjust_raster_scales);
 
       // Property trees are normally constructed on the main thread and
       // passed to compositor thread. Source to parent updates on them are not
@@ -533,7 +534,8 @@
           inputs->device_transform, inputs->root_layer->position());
       draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
           inputs->root_layer, inputs->property_trees,
-          inputs->can_render_to_separate_surface);
+          inputs->can_render_to_separate_surface,
+          inputs->can_adjust_raster_scales);
       break;
     }
   }
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index eb05727..240309c 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -218,6 +218,7 @@
       LayerImpl* root_layer) {
     DCHECK(root_layer->layer_tree_impl());
     bool can_render_to_separate_surface = true;
+    bool can_adjust_raster_scales = true;
 
     const LayerImpl* page_scale_layer = nullptr;
     LayerImpl* inner_viewport_scroll_layer =
@@ -244,7 +245,8 @@
         elastic_overscroll, page_scale_factor, device_scale_factor,
         gfx::Rect(device_viewport_size), gfx::Transform(), property_trees);
     draw_property_utils::UpdatePropertyTreesAndRenderSurfaces(
-        root_layer, property_trees, can_render_to_separate_surface);
+        root_layer, property_trees, can_render_to_separate_surface,
+        can_adjust_raster_scales);
     draw_property_utils::FindLayersThatNeedUpdates(
         root_layer->layer_tree_impl(), property_trees,
         update_layer_list_impl_.get());
@@ -268,6 +270,22 @@
     LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
   }
 
+  void ExecuteCalculateDrawPropertiesWithoutAdjustingRasterScales(
+      LayerImpl* root_layer) {
+    gfx::Size device_viewport_size =
+        gfx::Size(root_layer->bounds().width(), root_layer->bounds().height());
+    render_surface_layer_list_impl_.reset(new LayerImplList);
+
+    DCHECK(!root_layer->bounds().IsEmpty());
+    LayerTreeHostCommon::CalcDrawPropsImplInputsForTesting inputs(
+        root_layer, device_viewport_size,
+        render_surface_layer_list_impl_.get());
+    inputs.can_render_to_separate_surface = true;
+    inputs.can_adjust_raster_scales = false;
+
+    LayerTreeHostCommon::CalculateDrawPropertiesForTesting(&inputs);
+  }
+
   bool UpdateLayerListImplContains(int id) const {
     for (auto* layer : *update_layer_list_impl_) {
       if (layer->id() == id)
@@ -10823,5 +10841,38 @@
   EXPECT_EQ(scroll_root1.id, grand_child12->scroll_tree_index());
 }
 
+TEST_F(LayerTreeHostCommonTest, CanAdjustRasterScaleTest) {
+  LayerImpl* root = root_layer_for_testing();
+  LayerImpl* render_surface = AddChild<LayerImpl>(root);
+  LayerImpl* child = AddChild<LayerImpl>(render_surface);
+
+  root->SetBounds(gfx::Size(50, 50));
+
+  render_surface->SetBounds(gfx::Size(10, 10));
+  render_surface->test_properties()->force_render_surface = true;
+  gfx::Transform transform;
+  transform.Scale(5.f, 5.f);
+  render_surface->test_properties()->transform = transform;
+
+  child->SetDrawsContent(true);
+  child->SetMasksToBounds(true);
+  child->SetBounds(gfx::Size(10, 10));
+
+  ExecuteCalculateDrawPropertiesWithoutAdjustingRasterScales(root);
+
+  // Check surface draw properties.
+  EXPECT_EQ(gfx::Rect(10, 10),
+            render_surface->GetRenderSurface()->content_rect());
+  EXPECT_EQ(transform, render_surface->GetRenderSurface()->draw_transform());
+  EXPECT_EQ(gfx::RectF(50.0f, 50.0f),
+            render_surface->GetRenderSurface()->DrawableContentRect());
+
+  // Check child layer draw properties.
+  EXPECT_EQ(gfx::Rect(10, 10), child->visible_layer_rect());
+  EXPECT_EQ(gfx::Transform(), child->DrawTransform());
+  EXPECT_EQ(gfx::Rect(10, 10), child->clip_rect());
+  EXPECT_EQ(gfx::Rect(10, 10), child->drawable_content_rect());
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_copyrequest.cc b/cc/trees/layer_tree_host_unittest_copyrequest.cc
index c51f35b6..da83956 100644
--- a/cc/trees/layer_tree_host_unittest_copyrequest.cc
+++ b/cc/trees/layer_tree_host_unittest_copyrequest.cc
@@ -597,6 +597,10 @@
 class LayerTreeHostCopyRequestTestScaledLayer
     : public LayerTreeHostCopyRequestTest {
  protected:
+  void InitializeSettings(LayerTreeSettings* settings) override {
+    settings->layer_transforms_should_scale_layer_contents = true;
+  }
+
   void SetupTree() override {
     root_ = Layer::Create();
     root_->SetBounds(gfx::Size(20, 20));
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index bc4e736..e5aba10 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -847,9 +847,16 @@
       transform_tree.Node(effect_node->transform_id);
   if (transform_node->in_subtree_of_page_scale_layer)
     layer_scale_factor *= transform_tree.page_scale_factor();
+
+  // Note: Copy requests currently expect transform to effect output size.
+  bool use_transform_for_contents_scale =
+      property_trees()->can_adjust_raster_scales ||
+      effect_node->has_copy_request;
   effect_node->surface_contents_scale =
-      MathUtil::ComputeTransform2dScaleComponents(
-          transform_tree.ToScreen(transform_node->id), layer_scale_factor);
+      use_transform_for_contents_scale
+          ? MathUtil::ComputeTransform2dScaleComponents(
+                transform_tree.ToScreen(transform_node->id), layer_scale_factor)
+          : gfx::Vector2dF(layer_scale_factor, layer_scale_factor);
 }
 
 EffectNode* EffectTree::FindNodeFromElementId(ElementId id) {
@@ -1600,6 +1607,7 @@
 PropertyTrees::PropertyTrees()
     : needs_rebuild(true),
       non_root_surfaces_enabled(true),
+      can_adjust_raster_scales(true),
       changed(false),
       full_tree_damaged(false),
       sequence_number(0),
@@ -1630,6 +1638,7 @@
          is_main_thread == other.is_main_thread &&
          is_active == other.is_active &&
          non_root_surfaces_enabled == other.non_root_surfaces_enabled &&
+         can_adjust_raster_scales == other.can_adjust_raster_scales &&
          sequence_number == other.sequence_number;
 }
 
@@ -1647,6 +1656,7 @@
   changed = from.changed;
   full_tree_damaged = from.full_tree_damaged;
   non_root_surfaces_enabled = from.non_root_surfaces_enabled;
+  can_adjust_raster_scales = from.can_adjust_raster_scales;
   sequence_number = from.sequence_number;
   is_main_thread = from.is_main_thread;
   is_active = from.is_active;
@@ -1678,6 +1688,7 @@
   full_tree_damaged = false;
   changed = false;
   non_root_surfaces_enabled = true;
+  can_adjust_raster_scales = true;
   sequence_number++;
 
 #if DCHECK_IS_ON()
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index 7f22a0d..86ee684 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -650,6 +650,7 @@
   ScrollTree scroll_tree;
   bool needs_rebuild;
   bool non_root_surfaces_enabled;
+  bool can_adjust_raster_scales;
   // Change tracking done on property trees needs to be preserved across commits
   // (when they are not rebuild). We cache a global bool which stores whether
   // we did any change tracking so that we can skip copying the change status
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 088a9704..e4e2143a 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -214,7 +214,6 @@
     "//services/service_manager/public/interfaces:interfaces_java",
     "//services/service_manager/public/java:service_manager_java",
     "//services/shape_detection/public/interfaces:interfaces_java",
-    "//skia/public/interfaces:interfaces_java",
     "//third_party/WebKit/public:android_mojo_bindings_java",
     "//third_party/WebKit/public:blink_headers_java",
     "//third_party/WebKit/public:mojo_bindings_java",
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index b6d789c..167e290c 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -110,7 +110,7 @@
     <!-- Set android:largeHeap to "true" to allow more than the default
          Java heap limit (32Mb on Nexus S, 48Mb on Xoom). -->
     <application android:name="{% block application_name %}org.chromium.chrome.browser.ChromeApplication{% endblock %}"
-        android:icon="@mipmap/app_icon"
+        android:icon="@drawable/ic_launcher"
         android:label="@string/app_name"
         android:largeHeap="false"
         android:manageSpaceActivity="@string/manage_space_activity"
diff --git a/chrome/android/java/res/values/ic_launcher_alias.xml b/chrome/android/java/res/values/ic_launcher_alias.xml
new file mode 100644
index 0000000..7882e061b
--- /dev/null
+++ b/chrome/android/java/res/values/ic_launcher_alias.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<resources>
+    <drawable name="ic_launcher">@mipmap/app_icon</drawable>
+</resources>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java b/chrome/android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java
index d2f5e5a0..194e8e06 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java
@@ -191,6 +191,11 @@
         mDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
             @Override
             public void onDismiss(DialogInterface dialog) {
+                // For some reason this is ocassionally null. See crbug.com/708562.
+                if (mDialogDelegate == null) {
+                    scheduleDisplay();
+                }
+
                 mDialog = null;
                 if (mDecision == ACCEPTED) {
                     // Request Android permissions if necessary. This will call back into either
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java
index f7d8f73..6d46e5f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java
@@ -20,10 +20,11 @@
 import org.chromium.gfx.mojom.PointF;
 import org.chromium.gfx.mojom.RectF;
 import org.chromium.mojo.system.MojoException;
+import org.chromium.mojo.system.SharedBufferHandle;
+import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
 import org.chromium.services.service_manager.InterfaceFactory;
 import org.chromium.shape_detection.mojom.BarcodeDetection;
 import org.chromium.shape_detection.mojom.BarcodeDetectionResult;
-import org.chromium.skia.mojom.ColorType;
 
 import java.nio.ByteBuffer;
 
@@ -42,7 +43,8 @@
     }
 
     @Override
-    public void detect(org.chromium.skia.mojom.Bitmap bitmapData, DetectResponse callback) {
+    public void detect(
+            SharedBufferHandle frameData, int width, int height, DetectResponse callback) {
         if (!ExternalAuthUtils.getInstance().canUseGooglePlayServices(
                     mContext, new UserRecoverableErrorHandler.Silent())) {
             Log.e(TAG, "Google Play Services not available");
@@ -59,21 +61,9 @@
             return;
         }
 
-        // TODO(junwei.fu): Consider supporting other bitmap pixel formats,
-        // https://crbug.com/684921.
-        if (bitmapData.colorType != ColorType.RGBA_8888
-                && bitmapData.colorType != ColorType.BGRA_8888) {
-            Log.e(TAG, "Unsupported bitmap pixel format");
-            callback.call(new BarcodeDetectionResult[0]);
-            return;
-        }
-
-        int width = bitmapData.width;
-        int height = bitmapData.height;
         final long numPixels = (long) width * height;
         // TODO(mcasas): https://crbug.com/670028 homogeneize overflow checking.
-        if (bitmapData.pixelData == null || width <= 0 || height <= 0
-                || numPixels > (Long.MAX_VALUE / 4)) {
+        if (!frameData.isValid() || width <= 0 || height <= 0 || numPixels > (Long.MAX_VALUE / 4)) {
             callback.call(new BarcodeDetectionResult[0]);
             return;
         }
@@ -81,7 +71,7 @@
         // Mapping |frameData| will fail if the intended mapped size is larger
         // than its actual capacity, which is limited by the appropriate
         // mojo::edk::Configuration entry.
-        ByteBuffer imageBuffer = ByteBuffer.wrap(bitmapData.pixelData);
+        ByteBuffer imageBuffer = frameData.map(0, numPixels * 4, MapFlags.none());
         if (imageBuffer.capacity() <= 0) {
             callback.call(new BarcodeDetectionResult[0]);
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/TextDetectionImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/TextDetectionImpl.java
index 6af95153..2f4fab0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/TextDetectionImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/TextDetectionImpl.java
@@ -18,10 +18,11 @@
 import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler;
 import org.chromium.gfx.mojom.RectF;
 import org.chromium.mojo.system.MojoException;
+import org.chromium.mojo.system.SharedBufferHandle;
+import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
 import org.chromium.services.service_manager.InterfaceFactory;
 import org.chromium.shape_detection.mojom.TextDetection;
 import org.chromium.shape_detection.mojom.TextDetectionResult;
-import org.chromium.skia.mojom.ColorType;
 
 import java.nio.ByteBuffer;
 
@@ -40,7 +41,8 @@
     }
 
     @Override
-    public void detect(org.chromium.skia.mojom.Bitmap bitmapData, DetectResponse callback) {
+    public void detect(
+            SharedBufferHandle frameData, int width, int height, DetectResponse callback) {
         if (!ExternalAuthUtils.getInstance().canUseGooglePlayServices(
                     mContext, new UserRecoverableErrorHandler.Silent())) {
             Log.e(TAG, "Google Play Services not available");
@@ -57,21 +59,9 @@
             return;
         }
 
-        // TODO(junwei.fu): Consider supporting other bitmap pixel formats,
-        // https://crbug.com/684921.
-        if (bitmapData.colorType != ColorType.RGBA_8888
-                && bitmapData.colorType != ColorType.BGRA_8888) {
-            Log.e(TAG, "Unsupported bitmap pixel format");
-            callback.call(new TextDetectionResult[0]);
-            return;
-        }
-
-        int width = bitmapData.width;
-        int height = bitmapData.height;
         final long numPixels = (long) width * height;
         // TODO(xianglu): https://crbug.com/670028 homogeneize overflow checking.
-        if (bitmapData.pixelData == null || width <= 0 || height <= 0
-                || numPixels > (Long.MAX_VALUE / 4)) {
+        if (!frameData.isValid() || width <= 0 || height <= 0 || numPixels > (Long.MAX_VALUE / 4)) {
             callback.call(new TextDetectionResult[0]);
             return;
         }
@@ -79,7 +69,7 @@
         // Mapping |frameData| will fail if the intended mapped size is larger
         // than its actual capacity, which is limited by the appropriate
         // mojo::edk::Configuration entry.
-        ByteBuffer imageBuffer = ByteBuffer.wrap(bitmapData.pixelData);
+        ByteBuffer imageBuffer = frameData.map(0, numPixels * 4, MapFlags.none());
         if (imageBuffer.capacity() <= 0) {
             callback.call(new TextDetectionResult[0]);
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
index 6e80cf1..4d0c02c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContentController.java
@@ -52,12 +52,11 @@
 
     private final BottomSheetObserver mBottomSheetObserver = new EmptyBottomSheetObserver() {
         @Override
-        public void onTransitionPeekToHalf(float transitionFraction) {
+        public void onSheetOffsetChanged(float heightFraction) {
             float offsetY = (mBottomSheet.getMinOffset() - mBottomSheet.getSheetOffsetFromBottom())
                     + mDistanceBelowToolbarPx;
             setTranslationY((int) Math.max(offsetY, 0f));
-            setVisibility(
-                    MathUtils.areFloatsEqual(transitionFraction, 0f) ? View.GONE : View.VISIBLE);
+            setVisibility(MathUtils.areFloatsEqual(heightFraction, 0f) ? View.GONE : View.VISIBLE);
         }
 
         @Override
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 65abf852..b982327f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -8961,8 +8961,8 @@
       <message name="IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_BODY_CHILD_ACCOUNT" desc="Body of the personalize services section of the sync confirmation dialog in the tab modal signin flow for child accounts" formatter_data="android_java">
         Google may use your browsing history to personalize Search and other Google services
       </message>
-      <message name="IDS_SYNC_CONFIRMATION_SYNC_SETTINGS_LINK_BODY" desc="Label of the section containing the link to go to the sync setting page.">
-        Control how this works in <ph name="BEGIN_LINK">&lt;a id="settingsLink" href="chrome://settings"&gt;</ph>Settings<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>
+      <message name="IDS_SYNC_CONFIRMATION_SYNC_SETTINGS_LABEL" desc="Label of the checkbox that allows users to configure their sync settings on the settings page before signing in to Chrome.">
+        Control how this works in Settings
       </message>
       <message name="IDS_SYNC_CONFIRMATION_CONFIRM_BUTTON_LABEL" desc="Label of the confirmation button in the sync confirmation dialog of the tab modal signin flow">
         Ok, got it
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 124efb6a..84bed9ce 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1730,6 +1730,12 @@
          data_reduction_proxy::features::kDataReductionMainMenu,
          kDataReductionMainMenuFeatureVariations,
          "DataReductionProxyMainMenu")},
+    {"enable-data-reduction-proxy-site-breakdown",
+     flag_descriptions::kEnableDataReductionProxySiteBreakdownName,
+     flag_descriptions::kEnableDataReductionProxySiteBreakdownDescription,
+     kOsAndroid,
+     FEATURE_VALUE_TYPE(
+         data_reduction_proxy::features::kDataReductionSiteBreakdown)},
 #endif  // OS_ANDROID
     {"allow-insecure-localhost", flag_descriptions::kAllowInsecureLocalhost,
      flag_descriptions::kAllowInsecureLocalhostDescription, kOsAll,
@@ -2588,6 +2594,13 @@
      FEATURE_VALUE_TYPE(chrome::android::kCustomContextMenu)},
 #endif  // OS_ANDROID
 
+#if defined(USE_ASH)
+    {"ash-enable-smooth-screen-rotation",
+     flag_descriptions::kAshEnableSmoothScreenRotationName,
+     flag_descriptions::kAshEnableSmoothScreenRotationDescription, kOsCrOS,
+     SINGLE_VALUE_TYPE(ash::switches::kAshEnableSmoothScreenRotation)},
+#endif  // defined(USE_ASH)
+
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
     // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/vr_shell/animation.cc b/chrome/browser/android/vr_shell/animation.cc
index e62c24a..d193def6 100644
--- a/chrome/browser/android/vr_shell/animation.cc
+++ b/chrome/browser/android/vr_shell/animation.cc
@@ -15,8 +15,8 @@
                      std::unique_ptr<easing::Easing> easing,
                      std::vector<float> from,
                      std::vector<float> to,
-                     int64_t start,
-                     int64_t duration)
+                     const base::TimeTicks& start,
+                     const base::TimeDelta& duration)
     : id(id),
       property(property),
       easing(std::move(easing)),
diff --git a/chrome/browser/android/vr_shell/animation.h b/chrome/browser/android/vr_shell/animation.h
index 2f6304ad..084f4582 100644
--- a/chrome/browser/android/vr_shell/animation.h
+++ b/chrome/browser/android/vr_shell/animation.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/time/time.h"
 
 namespace vr_shell {
 
@@ -35,8 +36,8 @@
             std::unique_ptr<easing::Easing> easing,
             std::vector<float> from,
             std::vector<float> to,
-            int64_t start,
-            int64_t duration);
+            const base::TimeTicks& start,
+            const base::TimeDelta& duration);
   ~Animation();
 
   int id;
@@ -44,8 +45,8 @@
   std::unique_ptr<easing::Easing> easing;
   std::vector<float> from;
   std::vector<float> to;
-  int64_t start;
-  int64_t duration;
+  base::TimeTicks start;
+  base::TimeDelta duration;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Animation);
diff --git a/chrome/browser/android/vr_shell/ui_elements.cc b/chrome/browser/android/vr_shell/ui_elements.cc
index c779d37..82d1cdb0 100644
--- a/chrome/browser/android/vr_shell/ui_elements.cc
+++ b/chrome/browser/android/vr_shell/ui_elements.cc
@@ -7,6 +7,7 @@
 #include <limits>
 
 #include "base/logging.h"
+#include "base/time/time.h"
 #include "chrome/browser/android/vr_shell/animation.h"
 #include "chrome/browser/android/vr_shell/easing.h"
 
@@ -100,7 +101,7 @@
 
 ContentRectangle::~ContentRectangle() = default;
 
-void ContentRectangle::Animate(int64_t time) {
+void ContentRectangle::Animate(const base::TimeTicks& time) {
   for (auto& it : animations) {
     Animation& animation = *it;
     if (time < animation.start)
@@ -150,7 +151,8 @@
         continue;
       }
       double value = animation.easing->CalculateValue(
-          static_cast<double>(time - animation.start) / animation.duration);
+          (time - animation.start).InMillisecondsF() /
+          animation.duration.InMillisecondsF());
       values[i] =
           animation.from[i] + (value * (animation.to[i] - animation.from[i]));
     }
diff --git a/chrome/browser/android/vr_shell/ui_elements.h b/chrome/browser/android/vr_shell/ui_elements.h
index 3340345..b502f5d 100644
--- a/chrome/browser/android/vr_shell/ui_elements.h
+++ b/chrome/browser/android/vr_shell/ui_elements.h
@@ -13,6 +13,10 @@
 #include "chrome/browser/android/vr_shell/vr_math.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
 
+namespace base {
+class TimeTicks;
+}
+
 namespace vr_shell {
 
 class Animation;
@@ -87,7 +91,7 @@
   ContentRectangle();
   ~ContentRectangle();
 
-  void Animate(int64_t time);
+  void Animate(const base::TimeTicks& time);
 
   // Indicates whether the element should be visually rendered.
   bool IsVisible() const;
diff --git a/chrome/browser/android/vr_shell/ui_elements_unittest.cc b/chrome/browser/android/vr_shell/ui_elements_unittest.cc
index 83183dc..fd509d3 100644
--- a/chrome/browser/android/vr_shell/ui_elements_unittest.cc
+++ b/chrome/browser/android/vr_shell/ui_elements_unittest.cc
@@ -30,17 +30,29 @@
 
 namespace vr_shell {
 
+namespace {
+
+base::TimeTicks usToTicks(uint64_t us) {
+  return base::TimeTicks::FromInternalValue(us);
+}
+
+base::TimeDelta usToDelta(uint64_t us) {
+  return base::TimeDelta::FromInternalValue(us);
+}
+
+}  // namespace
+
 TEST(UiElements, AnimateCopyRect) {
   ContentRectangle rect;
   rect.copy_rect = {10, 100, 1000, 10000};
-  std::unique_ptr<Animation> animation(
-      new Animation(0, Animation::Property::COPYRECT,
-                    std::unique_ptr<easing::Easing>(new easing::Linear()), {},
-                    {20, 200, 2000, 20000}, 50000, 10000));
+  std::unique_ptr<Animation> animation(new Animation(
+      0, Animation::Property::COPYRECT,
+      std::unique_ptr<easing::Easing>(new easing::Linear()), {},
+      {20, 200, 2000, 20000}, usToTicks(50000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
-  rect.Animate(50000);
+  rect.Animate(usToTicks(50000));
   EXPECT_RECTF_EQ(rect.copy_rect, Rectf({10, 100, 1000, 10000}));
-  rect.Animate(60000);
+  rect.Animate(usToTicks(60000));
   EXPECT_RECTF_EQ(rect.copy_rect, Rectf({20, 200, 2000, 20000}));
 }
 
@@ -50,11 +62,11 @@
   std::unique_ptr<Animation> animation(
       new Animation(0, Animation::Property::SIZE,
                     std::unique_ptr<easing::Easing>(new easing::Linear()), {},
-                    {20, 200}, 50000, 10000));
+                    {20, 200}, usToTicks(50000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
-  rect.Animate(50000);
+  rect.Animate(usToTicks(50000));
   EXPECT_VEC3F_EQ(rect.size, gvr::Vec3f({10, 100}));
-  rect.Animate(60000);
+  rect.Animate(usToTicks(60000));
   EXPECT_VEC3F_EQ(rect.size, gvr::Vec3f({20, 200}));
 }
 
@@ -64,75 +76,75 @@
   std::unique_ptr<Animation> animation(
       new Animation(0, Animation::Property::TRANSLATION,
                     std::unique_ptr<easing::Easing>(new easing::Linear()), {},
-                    {20, 200, 2000}, 50000, 10000));
+                    {20, 200, 2000}, usToTicks(50000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
-  rect.Animate(50000);
+  rect.Animate(usToTicks(50000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({10, 100, 1000}));
-  rect.Animate(60000);
+  rect.Animate(usToTicks(60000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({20, 200, 2000}));
 }
 
 TEST(UiElements, AnimateRotation) {
   ContentRectangle rect;
   rect.rotation = {10, 100, 1000, 10000};
-  std::unique_ptr<Animation> animation(
-      new Animation(0, Animation::Property::ROTATION,
-                    std::unique_ptr<easing::Easing>(new easing::Linear()), {},
-                    {20, 200, 2000, 20000}, 50000, 10000));
+  std::unique_ptr<Animation> animation(new Animation(
+      0, Animation::Property::ROTATION,
+      std::unique_ptr<easing::Easing>(new easing::Linear()), {},
+      {20, 200, 2000, 20000}, usToTicks(50000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
-  rect.Animate(50000);
+  rect.Animate(usToTicks(50000));
   EXPECT_ROTATION(rect.rotation, RotationAxisAngle({10, 100, 1000, 10000}));
-  rect.Animate(60000);
+  rect.Animate(usToTicks(60000));
   EXPECT_ROTATION(rect.rotation, RotationAxisAngle({20, 200, 2000, 20000}));
 }
 
 TEST(UiElements, AnimationHasNoEffectBeforeScheduledStart) {
   ContentRectangle rect;
-  std::unique_ptr<Animation> animation(
-      new Animation(0, Animation::Property::TRANSLATION,
-                    std::unique_ptr<easing::Easing>(new easing::Linear()),
-                    {10, 100, 1000}, {20, 200, 2000}, 50000, 10000));
+  std::unique_ptr<Animation> animation(new Animation(
+      0, Animation::Property::TRANSLATION,
+      std::unique_ptr<easing::Easing>(new easing::Linear()), {10, 100, 1000},
+      {20, 200, 2000}, usToTicks(50000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
-  rect.Animate(49999);
+  rect.Animate(usToTicks(49999));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({0, 0, 0}));
 }
 
 TEST(UiElements, AnimationPurgedWhenDone) {
   ContentRectangle rect;
-  std::unique_ptr<Animation> animation(
-      new Animation(0, Animation::Property::TRANSLATION,
-                    std::unique_ptr<easing::Easing>(new easing::Linear()),
-                    {10, 100, 1000}, {20, 200, 2000}, 50000, 10000));
+  std::unique_ptr<Animation> animation(new Animation(
+      0, Animation::Property::TRANSLATION,
+      std::unique_ptr<easing::Easing>(new easing::Linear()), {10, 100, 1000},
+      {20, 200, 2000}, usToTicks(50000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
-  rect.Animate(60000);
+  rect.Animate(usToTicks(60000));
   EXPECT_EQ(0u, rect.animations.size());
 }
 
 TEST(UiElements, AnimationLinearEasing) {
   ContentRectangle rect;
-  std::unique_ptr<Animation> animation(
-      new Animation(0, Animation::Property::TRANSLATION,
-                    std::unique_ptr<easing::Easing>(new easing::Linear()),
-                    {10, 100, 1000}, {20, 200, 2000}, 50000, 10000));
+  std::unique_ptr<Animation> animation(new Animation(
+      0, Animation::Property::TRANSLATION,
+      std::unique_ptr<easing::Easing>(new easing::Linear()), {10, 100, 1000},
+      {20, 200, 2000}, usToTicks(50000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
-  rect.Animate(50000);
+  rect.Animate(usToTicks(50000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({10, 100, 1000}));
-  rect.Animate(55000);
+  rect.Animate(usToTicks(55000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({15, 150, 1500}));
-  rect.Animate(60000);
+  rect.Animate(usToTicks(60000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({20, 200, 2000}));
 }
 
 TEST(UiElements, AnimationStartFromSpecifiedLocation) {
   ContentRectangle rect;
-  std::unique_ptr<Animation> animation(
-      new Animation(0, Animation::Property::TRANSLATION,
-                    std::unique_ptr<easing::Easing>(new easing::Linear()),
-                    {10, 100, 1000}, {20, 200, 2000}, 50000, 10000));
+  std::unique_ptr<Animation> animation(new Animation(
+      0, Animation::Property::TRANSLATION,
+      std::unique_ptr<easing::Easing>(new easing::Linear()), {10, 100, 1000},
+      {20, 200, 2000}, usToTicks(50000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
-  rect.Animate(50000);
+  rect.Animate(usToTicks(50000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({10, 100, 1000}));
-  rect.Animate(60000);
+  rect.Animate(usToTicks(60000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({20, 200, 2000}));
 }
 
@@ -146,18 +158,18 @@
   std::unique_ptr<Animation> animation(
       new Animation(0, Animation::Property::TRANSLATION,
                     std::unique_ptr<easing::Easing>(new easing::Linear()), {},
-                    {20, 200, 2000}, 50000, 10000));
+                    {20, 200, 2000}, usToTicks(50000), usToDelta(10000)));
   std::unique_ptr<Animation> animation2(
       new Animation(0, Animation::Property::TRANSLATION,
                     std::unique_ptr<easing::Easing>(new easing::Linear()), {},
-                    {50, 500, 5000}, 55000, 10000));
+                    {50, 500, 5000}, usToTicks(55000), usToDelta(10000)));
   rect.animations.emplace_back(std::move(animation));
   rect.animations.emplace_back(std::move(animation2));
-  rect.Animate(55000);
+  rect.Animate(usToTicks(55000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({10, 100, 1000}));
-  rect.Animate(60000);
+  rect.Animate(usToTicks(60000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({30, 300, 3000}));
-  rect.Animate(65000);
+  rect.Animate(usToTicks(65000));
   EXPECT_VEC3F_EQ(rect.translation, gvr::Vec3f({50, 500, 5000}));
 }
 
diff --git a/chrome/browser/android/vr_shell/ui_scene.cc b/chrome/browser/android/vr_shell/ui_scene.cc
index fc46134..d1c387ae 100644
--- a/chrome/browser/android/vr_shell/ui_scene.cc
+++ b/chrome/browser/android/vr_shell/ui_scene.cc
@@ -8,6 +8,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/android/vr_shell/animation.h"
 #include "chrome/browser/android/vr_shell/easing.h"
@@ -229,7 +230,7 @@
 }
 
 void UiScene::AddAnimationFromDict(const base::DictionaryValue& dict,
-                                   int64_t time_in_micro) {
+                                   const base::TimeTicks& current_time) {
   int animation_id;
   int element_id;
   Animation::Property property;
@@ -261,8 +262,9 @@
     ParseEndpointToFloats(property, *from_dict, &from);
   }
 
-  int64_t start = time_in_micro + (start_time_ms * 1000.0);
-  int64_t duration = duration_ms * 1000.0;
+  base::TimeDelta delay = base::TimeDelta::FromMilliseconds(start_time_ms);
+  base::TimeTicks start = current_time + delay;
+  base::TimeDelta duration = base::TimeDelta::FromMilliseconds(duration_ms);
 
   ContentRectangle* element = GetUiElementById(element_id);
   CHECK_NE(element, nullptr);
@@ -285,7 +287,7 @@
 }
 
 void UiScene::HandleCommands(std::unique_ptr<base::ListValue> commands,
-                             int64_t time_in_micro) {
+                             const base::TimeTicks& time) {
   for (auto& item : *commands) {
     base::DictionaryValue* dict;
     CHECK(item->GetAsDictionary(&dict));
@@ -309,7 +311,7 @@
         break;
       }
       case Command::ADD_ANIMATION:
-        AddAnimationFromDict(*data, time_in_micro);
+        AddAnimationFromDict(*data, time);
         break;
       case Command::REMOVE_ANIMATION: {
         int element_id, animation_id;
@@ -327,10 +329,10 @@
   }
 }
 
-void UiScene::UpdateTransforms(int64_t time_in_micro) {
+void UiScene::UpdateTransforms(const base::TimeTicks& time) {
   for (auto& element : ui_elements_) {
     // Process all animations before calculating object transforms.
-    element->Animate(time_in_micro);
+    element->Animate(time);
     element->dirty = true;
   }
   for (auto& element : ui_elements_) {
diff --git a/chrome/browser/android/vr_shell/ui_scene.h b/chrome/browser/android/vr_shell/ui_scene.h
index 4bcb6d88..9d33480 100644
--- a/chrome/browser/android/vr_shell/ui_scene.h
+++ b/chrome/browser/android/vr_shell/ui_scene.h
@@ -14,6 +14,7 @@
 namespace base {
 class DictionaryValue;
 class ListValue;
+class TimeTicks;
 }
 
 namespace vr_shell {
@@ -50,7 +51,7 @@
 
   // Add an animation according to a dictionary passed from the UI HTML.
   void AddAnimationFromDict(const base::DictionaryValue& dict,
-                            int64_t time_in_micro);
+                            const base::TimeTicks& current_time);
 
   // Remove |animation_id| from element |element_id|.
   void RemoveAnimation(int element_id, int animation_id);
@@ -58,11 +59,11 @@
   // Update the positions of all elements in the scene, according to active
   // animations and time.  The units of time are arbitrary, but must match the
   // unit used in animations.
-  void UpdateTransforms(int64_t time_in_micro);
+  void UpdateTransforms(const base::TimeTicks& current_time);
 
   // Handle a batch of commands passed from the UI HTML.
   void HandleCommands(std::unique_ptr<base::ListValue> commands,
-                      int64_t time_in_micro);
+                      const base::TimeTicks& current_time);
 
   const std::vector<std::unique_ptr<ContentRectangle>>& GetUiElements() const;
 
diff --git a/chrome/browser/android/vr_shell/ui_scene_unittest.cc b/chrome/browser/android/vr_shell/ui_scene_unittest.cc
index cfcc3d6..36a1e52 100644
--- a/chrome/browser/android/vr_shell/ui_scene_unittest.cc
+++ b/chrome/browser/android/vr_shell/ui_scene_unittest.cc
@@ -28,6 +28,14 @@
 
 namespace {
 
+base::TimeTicks usToTicks(uint64_t us) {
+  return base::TimeTicks::FromInternalValue(us);
+}
+
+base::TimeDelta usToDelta(uint64_t us) {
+  return base::TimeDelta::FromInternalValue(us);
+}
+
 void addElement(UiScene* scene, int id) {
   auto element = base::MakeUnique<ContentRectangle>();
   element->id = id;
@@ -41,8 +49,9 @@
   std::unique_ptr<easing::Easing> easing = base::MakeUnique<easing::Linear>();
   std::vector<float> from = {};
   std::vector<float> to = {1, 1, 1, 1};
-  auto animation = base::MakeUnique<Animation>(
-      animation_id, property, std::move(easing), from, to, 0, 1);
+  auto animation =
+      base::MakeUnique<Animation>(animation_id, property, std::move(easing),
+                                  from, to, usToTicks(0), usToDelta(1));
   scene->AddAnimation(element_id, std::move(animation));
 }
 
@@ -126,7 +135,7 @@
   const gvr::Vec3f origin({0, 0, 0});
   const gvr::Vec3f point({1, 0, 0});
 
-  scene.UpdateTransforms(0);
+  scene.UpdateTransforms(usToTicks(0));
   auto new_origin = MatrixVectorMul(child->TransformMatrix(), origin);
   auto new_point = MatrixVectorMul(child->TransformMatrix(), point);
   EXPECT_VEC3F_NEAR(gvr::Vec3f({6, 10, 0}), new_origin);
@@ -147,7 +156,7 @@
   element->opacity = 0.5;
   scene.AddUiElement(std::move(element));
 
-  scene.UpdateTransforms(0);
+  scene.UpdateTransforms(usToTicks(0));
   EXPECT_EQ(scene.GetUiElementById(0)->computed_opacity, 0.5f);
   EXPECT_EQ(scene.GetUiElementById(1)->computed_opacity, 0.25f);
 }
@@ -166,7 +175,7 @@
   element->lock_to_fov = false;
   scene.AddUiElement(std::move(element));
 
-  scene.UpdateTransforms(0);
+  scene.UpdateTransforms(usToTicks(0));
   EXPECT_EQ(scene.GetUiElementById(0)->computed_lock_to_fov, true);
   EXPECT_EQ(scene.GetUiElementById(1)->computed_lock_to_fov, true);
 }
@@ -198,7 +207,7 @@
   element->y_anchoring = GetParam().y_anchoring;
   scene.AddUiElement(std::move(element));
 
-  scene.UpdateTransforms(0);
+  scene.UpdateTransforms(usToTicks(0));
   const ContentRectangle* child = scene.GetUiElementById(1);
   EXPECT_NEAR(child->GetCenter().x, GetParam().expected_x, TOLERANCE);
   EXPECT_NEAR(child->GetCenter().y, GetParam().expected_y, TOLERANCE);
@@ -420,25 +429,25 @@
   from->SetInteger("a", 303);
   dict.Set("from", std::move(from));
 
-  scene.AddAnimationFromDict(dict, 10000000);
+  scene.AddAnimationFromDict(dict, usToTicks(10000000));
   const auto* element = scene.GetUiElementById(0);
   const auto* animation = element->animations[0].get();
   EXPECT_NE(animation, nullptr);
 
   EXPECT_EQ(animation->id, 10);
 
-  EXPECT_FLOAT_EQ(animation->to[0], 200);
-  EXPECT_FLOAT_EQ(animation->to[1], 201);
-  EXPECT_FLOAT_EQ(animation->to[2], 202);
-  EXPECT_FLOAT_EQ(animation->to[3], 203);
+  EXPECT_FLOAT_EQ(200, animation->to[0]);
+  EXPECT_FLOAT_EQ(201, animation->to[1]);
+  EXPECT_FLOAT_EQ(202, animation->to[2]);
+  EXPECT_FLOAT_EQ(203, animation->to[3]);
 
-  EXPECT_FLOAT_EQ(animation->from[0], 300);
-  EXPECT_FLOAT_EQ(animation->from[1], 301);
-  EXPECT_FLOAT_EQ(animation->from[2], 302);
-  EXPECT_FLOAT_EQ(animation->from[3], 303);
+  EXPECT_FLOAT_EQ(300, animation->from[0]);
+  EXPECT_FLOAT_EQ(301, animation->from[1]);
+  EXPECT_FLOAT_EQ(302, animation->from[2]);
+  EXPECT_FLOAT_EQ(303, animation->from[3]);
 
-  EXPECT_EQ(animation->start, 22345000);
-  EXPECT_EQ(animation->duration, 54321000);
+  EXPECT_EQ(usToTicks(22345000), animation->start);
+  EXPECT_EQ(usToDelta(54321000), animation->duration);
 }
 
 }  // namespace vr_shell
diff --git a/chrome/browser/android/vr_shell/vr_shell_gl.cc b/chrome/browser/android/vr_shell/vr_shell_gl.cc
index 66b1499..2f6ca18 100644
--- a/chrome/browser/android/vr_shell/vr_shell_gl.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_gl.cc
@@ -127,12 +127,6 @@
   VIEWER_TYPE_MAX,
 };
 
-int64_t TimeInMicroseconds() {
-  return std::chrono::duration_cast<std::chrono::microseconds>(
-             std::chrono::steady_clock::now().time_since_epoch())
-      .count();
-}
-
 void RunVRDisplayInfoCallback(
     const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback,
     device::mojom::VRDisplayInfoPtr info) {
@@ -719,6 +713,8 @@
 void VrShellGl::DrawFrame(int16_t frame_index) {
   TRACE_EVENT1("gpu", "VrShellGl::DrawFrame", "frame", frame_index);
 
+  base::TimeTicks current_time = base::TimeTicks::Now();
+
   // Reset the viewport list to just the pair of viewports for the
   // primary buffer each frame. Head-locked viewports get added by
   // DrawVrShell if needed.
@@ -808,7 +804,7 @@
   }
 
   // Update the render position of all UI elements (including desktop).
-  scene_->UpdateTransforms(TimeInMicroseconds());
+  scene_->UpdateTransforms(current_time);
 
   {
     // TODO(crbug.com/704690): Acquire controller state in a way that's timely
@@ -1253,7 +1249,7 @@
 }
 
 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) {
-  scene_->HandleCommands(std::move(commands), TimeInMicroseconds());
+  scene_->HandleCommands(std::move(commands), base::TimeTicks::Now());
 }
 
 void VrShellGl::SendVSync(base::TimeDelta time,
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
index 2e870982..e95d61e 100644
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
@@ -2241,6 +2241,13 @@
   LoadAndLaunchPlatformApp("web_view/simple", "WebViewTest.LAUNCHED");
 }
 
+// Tests that an app can inject a content script into a webview, and that it can
+// send cross-origin requests with CORS headers.
+IN_PROC_BROWSER_TEST_P(WebViewTest, ContentScriptFetch) {
+  TestHelper("testContentScriptFetch", "web_view/content_script_fetch",
+             NEEDS_TEST_SERVER);
+}
+
 // In following GeolocationAPIEmbedderHasNoAccess* tests, embedder (i.e. the
 // platform app) does not have geolocation permission for this test.
 // No matter what the API does, geolocation permission would be denied.
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 0d3b565..1ef51b2 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -36,6 +36,7 @@
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_mode_idle_app_name_notification.h"
 #include "chrome/browser/chromeos/arc/arc_service_launcher.h"
+#include "chrome/browser/chromeos/ash_config.h"
 #include "chrome/browser/chromeos/boot_times_recorder.h"
 #include "chrome/browser/chromeos/dbus/chrome_console_service_provider_delegate.h"
 #include "chrome/browser/chromeos/dbus/chrome_display_power_service_provider_delegate.h"
@@ -215,9 +216,19 @@
  public:
   explicit DBusServices(const content::MainFunctionParams& parameters) {
     // Under mash, some D-Bus clients are owned by other processes.
-    DBusThreadManager::ProcessMask process_mask =
-        ash_util::IsRunningInMash() ? DBusThreadManager::PROCESS_BROWSER
-                                    : DBusThreadManager::PROCESS_ALL;
+    DBusThreadManager::ProcessMask process_mask;
+    switch (GetAshConfig()) {
+      case ash::Config::CLASSIC:
+        process_mask = DBusThreadManager::PROCESS_ALL;
+        break;
+      case ash::Config::MUS:
+        // TODO(jamescook|derat): We need another category for mushrome.
+        process_mask = DBusThreadManager::PROCESS_ALL;
+        break;
+      case ash::Config::MASH:
+        process_mask = DBusThreadManager::PROCESS_BROWSER;
+        break;
+    }
 
     // Initialize DBusThreadManager for the browser. This must be done after
     // the main message loop is started, as it uses the message loop.
@@ -234,25 +245,34 @@
     service_providers.push_back(
         base::MakeUnique<ProxyResolutionServiceProvider>(
             base::MakeUnique<ChromeProxyResolutionServiceProviderDelegate>()));
-    if (!ash_util::IsRunningInMash()) {
+    if (GetAshConfig() == ash::Config::CLASSIC) {
       // TODO(crbug.com/629707): revisit this with mustash dbus work.
       service_providers.push_back(base::MakeUnique<DisplayPowerServiceProvider>(
           base::MakeUnique<ChromeDisplayPowerServiceProviderDelegate>()));
     }
     service_providers.push_back(base::MakeUnique<LivenessServiceProvider>());
     service_providers.push_back(base::MakeUnique<ScreenLockServiceProvider>());
-    if (ash_util::IsRunningInMash()) {
-      service_providers.push_back(base::MakeUnique<ConsoleServiceProvider>(
-          base::MakeUnique<MusConsoleServiceProviderDelegate>()));
-    } else {
+    if (GetAshConfig() == ash::Config::CLASSIC) {
       service_providers.push_back(base::MakeUnique<ConsoleServiceProvider>(
           base::MakeUnique<ChromeConsoleServiceProviderDelegate>()));
+    } else {
+      service_providers.push_back(base::MakeUnique<ConsoleServiceProvider>(
+          base::MakeUnique<MusConsoleServiceProviderDelegate>()));
     }
-    service_providers.push_back(base::MakeUnique<KioskInfoService>());
+    service_providers.push_back(base::MakeUnique<KioskInfoService>(
+        kLibCrosServiceInterface,
+        kKioskAppServiceGetRequiredPlatformVersionMethod));
     cros_dbus_service_ = CrosDBusService::Create(
         kLibCrosServiceName, dbus::ObjectPath(kLibCrosServicePath),
         std::move(service_providers));
 
+    kiosk_info_service_ = CrosDBusService::Create(
+        kKioskAppServiceName, dbus::ObjectPath(kKioskAppServicePath),
+        CrosDBusService::CreateServiceProviderList(
+            base::MakeUnique<KioskInfoService>(
+                kKioskAppServiceInterface,
+                kKioskAppServiceGetRequiredPlatformVersionMethod)));
+
     // Initialize PowerDataCollector after DBusThreadManager is initialized.
     PowerDataCollector::Initialize();
 
@@ -302,6 +322,7 @@
     CertLoader::Shutdown();
     TPMTokenLoader::Shutdown();
     cros_dbus_service_.reset();
+    kiosk_info_service_.reset();
     PowerDataCollector::Shutdown();
     PowerPolicyController::Shutdown();
     device::BluetoothAdapterFactory::Shutdown();
@@ -319,6 +340,8 @@
   // split between different processes: http://crbug.com/692246
   std::unique_ptr<CrosDBusService> cros_dbus_service_;
 
+  std::unique_ptr<CrosDBusService> kiosk_info_service_;
+
   std::unique_ptr<NetworkConnectDelegateChromeOS> network_connect_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(DBusServices);
diff --git a/chrome/browser/chromeos/dbus/kiosk_info_service_provider.cc b/chrome/browser/chromeos/dbus/kiosk_info_service_provider.cc
index cae5003..ce5eef5 100644
--- a/chrome/browser/chromeos/dbus/kiosk_info_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/kiosk_info_service_provider.cc
@@ -15,14 +15,18 @@
 
 namespace chromeos {
 
-KioskInfoService::KioskInfoService() : weak_ptr_factory_(this) {}
+KioskInfoService::KioskInfoService(const std::string& service_interface,
+                                   const std::string& method_name)
+    : service_interface_(service_interface),
+      method_name_(method_name),
+      weak_ptr_factory_(this) {}
 
 KioskInfoService::~KioskInfoService() {}
 
 void KioskInfoService::Start(
     scoped_refptr<dbus::ExportedObject> exported_object) {
   exported_object->ExportMethod(
-      kLibCrosServiceInterface, kGetKioskAppRequiredPlatforVersion,
+      service_interface_, method_name_,
       base::Bind(&KioskInfoService::GetKioskAppRequiredPlatformVersion,
                  weak_ptr_factory_.GetWeakPtr()),
       base::Bind(&KioskInfoService::OnExported,
diff --git a/chrome/browser/chromeos/dbus/kiosk_info_service_provider.h b/chrome/browser/chromeos/dbus/kiosk_info_service_provider.h
index 61c4385..7034d9e1 100644
--- a/chrome/browser/chromeos/dbus/kiosk_info_service_provider.h
+++ b/chrome/browser/chromeos/dbus/kiosk_info_service_provider.h
@@ -24,7 +24,10 @@
 //
 class KioskInfoService : public CrosDBusService::ServiceProviderInterface {
  public:
-  KioskInfoService();
+  // TODO(teravest): Remove these extra parameters once this interface is fully
+  // migrated off of LibCrosService.
+  KioskInfoService(const std::string& service_interface,
+                   const std::string& method_name);
   ~KioskInfoService() override;
 
   // CrosDBusService::ServiceProviderInterface
@@ -42,6 +45,9 @@
       dbus::MethodCall* method_call,
       dbus::ExportedObject::ResponseSender response_sender);
 
+  std::string service_interface_;
+  std::string method_name_;
+
   base::WeakPtrFactory<KioskInfoService> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(KioskInfoService);
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index dca79055..f8e8ed1 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -22,6 +22,7 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/ash_config.h"
 #include "chrome/browser/chromeos/input_method/candidate_window_controller.h"
 #include "chrome/browser/chromeos/input_method/component_extension_ime_manager_impl.h"
 #include "chrome/browser/chromeos/input_method/input_method_switch_recorder.h"
@@ -29,7 +30,6 @@
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/ui/ash/ash_util.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/system/devicemode.h"
@@ -921,12 +921,14 @@
       component_extension_ime_manager_(new ComponentExtensionIMEManager()),
       enable_extension_loading_(enable_extension_loading),
       is_ime_menu_activated_(false) {
-  // TODO(mohsen): Revisit using FakeImeKeyboard with mash when InputController
-  // work is ready. http://crbug.com/601981
-  if (IsRunningAsSystemCompositor() && !ash_util::IsRunningInMash())
+  // TODO(crbug.com/642863): Revisit using FakeImeKeyboard with mash when
+  // InputController work is ready.
+  if (IsRunningAsSystemCompositor() &&
+      chromeos::GetAshConfig() == ash::Config::CLASSIC) {
     keyboard_.reset(ImeKeyboard::Create());
-  else
+  } else {
     keyboard_.reset(new FakeImeKeyboard());
+  }
 
   // Initializes the system IME list.
   std::unique_ptr<ComponentExtensionIMEManagerDelegate> comp_delegate(
diff --git a/chrome/browser/extensions/api/messaging/incognito_connectability.h b/chrome/browser/extensions/api/messaging/incognito_connectability.h
index 026ade9..9686db2 100644
--- a/chrome/browser/extensions/api/messaging/incognito_connectability.h
+++ b/chrome/browser/extensions/api/messaging/incognito_connectability.h
@@ -27,11 +27,10 @@
 // Tracks the web connectability of domains to extensions in incognito mode.
 //
 // The most important functionality is prompting the user to allow or disallow
-// connections from incognito tabs to extensions or apps. Even if an extension
-// hasn't been enabled in incognito mode, it's still useful for web sites to be
-// able to send messages to them, with user constent. For apps, it's essential
-// we have this functionality because there is no way for them to be enabled in
-// incognito.
+// connections from incognito tabs to extensions or apps. Users are not prompted
+// for extensions which can be enabled in incognito mode. However for apps, it's
+// essential we have this functionality because there is no way for them to be
+// enabled in incognito.
 class IncognitoConnectability : public BrowserContextKeyedAPI {
  public:
   // While in scope, immediately either accepts or denies the alerts that show
diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc
index d3cc637..801f3b6 100644
--- a/chrome/browser/extensions/api/messaging/message_service.cc
+++ b/chrome/browser/extensions/api/messaging/message_service.cc
@@ -329,7 +329,7 @@
       !util::IsIncognitoEnabled(target_extension_id, context)) {
     // Give the user a chance to accept an incognito connection from the web if
     // they haven't already, with the conditions:
-    // - Only for spanning-mode incognito. We don't want the complication of
+    // - Only for non-split mode incognito. We don't want the complication of
     //   spinning up an additional process here which might need to do some
     //   setup that we're not expecting.
     // - Only for extensions that can't normally be enabled in incognito, since
diff --git a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
index 6bf4596..8501851e 100644
--- a/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
+++ b/chrome/browser/extensions/chrome_content_browser_client_extensions_part.cc
@@ -202,15 +202,17 @@
     return content::HeaderInterceptorResult::FAIL;
 
   // Check for platform app origins.  These can only be committed by the app
-  // itself, or by one if its guests if there are accessible_resources.
+  // itself, or by one if its guests if it has the webview permission.
   // Processes that incorrectly claim to be an app should be killed.
   const ProcessMap& process_map = extension_info_map->process_map();
   if (extension->is_platform_app() &&
       !process_map.Contains(extension->id(), child_id)) {
-    // This is a platform app origin not in the app's own process.  If there
-    // are no accessible resources, this is illegal.
-    if (!extension->GetManifestData(manifest_keys::kWebviewAccessibleResources))
+    // This is a platform app origin not in the app's own process.  If it cannot
+    // create webviews, this is illegal.
+    if (!extension->permissions_data()->HasAPIPermission(
+            extensions::APIPermission::kWebView)) {
       return content::HeaderInterceptorResult::KILL;
+    }
 
     // If there are accessible resources, the origin is only legal if the
     // given process is a guest of the app.
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc
index 9bee026..e4bfe1c0 100644
--- a/chrome/browser/extensions/extension_messages_apitest.cc
+++ b/chrome/browser/extensions/extension_messages_apitest.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
 #include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/test_extension_dir.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/profiles/profile.h"
@@ -39,8 +40,11 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
+#include "extensions/browser/extension_util.h"
 #include "extensions/browser/process_manager.h"
+#include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/common/api/runtime.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/value_builder.h"
@@ -348,17 +352,16 @@
   }
 
   scoped_refptr<const Extension> LoadChromiumConnectableExtension() {
-    scoped_refptr<const Extension> extension =
-        LoadExtensionIntoDir(&web_connectable_dir_,
-                             base::StringPrintf(
-                                 "{"
-                                 "  \"name\": \"chromium_connectable\","
-                                 "  %s,"
-                                 "  \"externally_connectable\": {"
-                                 "    \"matches\": [\"*://*.chromium.org:*/*\"]"
-                                 "  }"
-                                 "}",
-                                 common_manifest()));
+    scoped_refptr<const Extension> extension = LoadExtensionIntoDir(
+        &web_connectable_dir_extension_,
+        base::StringPrintf("{"
+                           "  \"name\": \"chromium_connectable\","
+                           "  %s,"
+                           "  \"externally_connectable\": {"
+                           "    \"matches\": [\"*://*.chromium.org:*/*\"]"
+                           "  }"
+                           "}",
+                           common_manifest()));
     CHECK(extension.get());
     return extension;
   }
@@ -366,7 +369,7 @@
   scoped_refptr<const Extension> LoadChromiumConnectableApp(
       bool with_event_handlers = true) {
     scoped_refptr<const Extension> extension =
-        LoadExtensionIntoDir(&web_connectable_dir_,
+        LoadExtensionIntoDir(&web_connectable_dir_app_,
                              "{"
                              "  \"app\": {"
                              "    \"background\": {"
@@ -509,7 +512,8 @@
     return result;
   }
 
-  TestExtensionDir web_connectable_dir_;
+  TestExtensionDir web_connectable_dir_extension_;
+  TestExtensionDir web_connectable_dir_app_;
   TestExtensionDir not_connectable_dir_;
   TestExtensionDir tls_channel_id_connectable_dir_;
   TestExtensionDir hosted_app_dir_;
@@ -771,10 +775,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ExternallyConnectableMessagingTest,
-                       FromIncognitoDenyExtension) {
+                       FromIncognitoDenyExtensionAndApp) {
   InitializeTestServer();
 
   scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
+  EXPECT_FALSE(util::IsIncognitoEnabled(extension->id(), profile()));
 
   Browser* incognito_browser = OpenURLOffTheRecord(
       profile()->GetOffTheRecordProfile(), chromium_org_url());
@@ -783,22 +788,39 @@
           ->GetActiveWebContents()
           ->GetMainFrame();
 
-  {
-    IncognitoConnectability::ScopedAlertTracker alert_tracker(
-        IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
+  IncognitoConnectability::ScopedAlertTracker alert_tracker(
+      IncognitoConnectability::ScopedAlertTracker::ALWAYS_DENY);
 
-    // The alert doesn't show for extensions.
-    EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
-              CanConnectAndSendMessagesToFrame(
-                  incognito_frame, extension.get(), NULL));
-    EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
-  }
+  // |extension| won't be loaded in the incognito renderer since it's not
+  // enabled for incognito. Since there is no externally connectible extension
+  // loaded into the incognito renderer, the chrome.runtime API won't be
+  // defined.
+  EXPECT_EQ(NAMESPACE_NOT_DEFINED,
+            CanConnectAndSendMessagesToFrame(incognito_frame, extension.get(),
+                                             nullptr));
 
-  // Allowing the extension in incognito mode will bypass the deny.
-  ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension->id(), true);
-  EXPECT_EQ(
-      OK,
-      CanConnectAndSendMessagesToFrame(incognito_frame, extension.get(), NULL));
+  // Loading a platform app in the renderer should cause the chrome.runtime
+  // bindings to be generated in the renderer. A platform app is always loaded
+  // in the incognito renderer.
+  LoadChromiumConnectableApp();
+  EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
+            CanConnectAndSendMessagesToFrame(incognito_frame, extension.get(),
+                                             nullptr));
+
+  // Allowing the extension in incognito mode loads the extension in the
+  // incognito renderer, allowing it to receive connections.
+  TestExtensionRegistryObserver observer(
+      ExtensionRegistry::Get(profile()->GetOffTheRecordProfile()),
+      extension->id());
+  util::SetIsIncognitoEnabled(extension->id(),
+                              profile()->GetOffTheRecordProfile(), true);
+  const Extension* loaded_extension = observer.WaitForExtensionLoaded();
+  EXPECT_EQ(OK, CanConnectAndSendMessagesToFrame(incognito_frame,
+                                                 loaded_extension, nullptr));
+
+  // No alert is shown for extensions since they support being enabled in
+  // incognito mode.
+  EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
 }
 
 // Tests connection from incognito tabs when the extension doesn't have an event
@@ -950,6 +972,7 @@
   InitializeTestServer();
 
   scoped_refptr<const Extension> extension = LoadChromiumConnectableExtension();
+  EXPECT_FALSE(util::IsIncognitoEnabled(extension->id(), profile()));
 
   Browser* incognito_browser = OpenURLOffTheRecord(
       profile()->GetOffTheRecordProfile(), chromium_org_url());
@@ -958,22 +981,32 @@
           ->GetActiveWebContents()
           ->GetMainFrame();
 
-  {
-    IncognitoConnectability::ScopedAlertTracker alert_tracker(
-        IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
+  IncognitoConnectability::ScopedAlertTracker alert_tracker(
+      IncognitoConnectability::ScopedAlertTracker::ALWAYS_ALLOW);
 
-    // No alert is shown.
-    EXPECT_EQ(COULD_NOT_ESTABLISH_CONNECTION_ERROR,
-              CanConnectAndSendMessagesToFrame(
-                  incognito_frame, extension.get(), NULL));
-    EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
-  }
+  // |extension| won't be loaded in the incognito renderer since it's not
+  // enabled for incognito. Since there is no externally connectible extension
+  // loaded into the incognito renderer, the chrome.runtime API won't be
+  // defined.
+  EXPECT_EQ(NAMESPACE_NOT_DEFINED,
+            CanConnectAndSendMessagesToFrame(incognito_frame, extension.get(),
+                                             nullptr));
 
-  // Allowing the extension in incognito mode is what allows connections.
-  ExtensionPrefs::Get(profile())->SetIsIncognitoEnabled(extension->id(), true);
-  EXPECT_EQ(
-      OK,
-      CanConnectAndSendMessagesToFrame(incognito_frame, extension.get(), NULL));
+  // Allowing the extension in incognito mode loads the extension in the
+  // incognito renderer, causing the chrome.runtime bindings to be generated in
+  // the renderer and allowing the extension to receive connections.
+  TestExtensionRegistryObserver observer(
+      ExtensionRegistry::Get(profile()->GetOffTheRecordProfile()),
+      extension->id());
+  util::SetIsIncognitoEnabled(extension->id(),
+                              profile()->GetOffTheRecordProfile(), true);
+  const Extension* loaded_extension = observer.WaitForExtensionLoaded();
+  EXPECT_EQ(OK, CanConnectAndSendMessagesToFrame(incognito_frame,
+                                                 loaded_extension, nullptr));
+
+  // No alert is shown for extensions which support being enabled in incognito
+  // mode.
+  EXPECT_EQ(0, alert_tracker.GetAndResetAlertCount());
 }
 
 // Tests a connection from an iframe within a tab which doesn't have
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index ce5c323..c50dc27 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -734,6 +734,12 @@
     "Enable the mirrored screen mode. This mode flips the screen image "
     "horizontally.";
 
+const char kAshEnableSmoothScreenRotationName[] =
+    "Enable smooth rotation animations.";
+
+const char kAshEnableSmoothScreenRotationDescription[] =
+    "Enable smooth rotation animations.";
+
 const char kMaterialDesignInkDropAnimationFast[] = "Fast";
 
 const char kMaterialDesignInkDropAnimationSlow[] = "Slow";
@@ -1186,6 +1192,12 @@
     "Enables the Data Saver menu item in the main menu rather than under "
     "Settings.";
 
+const char kEnableDataReductionProxySiteBreakdownName[] =
+    "Data Saver Site Breakdown";
+
+const char kEnableDataReductionProxySiteBreakdownDescription[] =
+    "Enable the site breakdown on the Data Saver settings page.";
+
 #endif  // defined(OS_ANDROID)
 
 const char kLcdTextName[] = "LCD text antialiasing";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 03201119..6788471 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -800,6 +800,12 @@
 // Description for the flag to enable the mirrored screen mode.
 extern const char kAshEnableMirroredScreenDescription[];
 
+// Title for the flag to enable smooth rotation animations.
+extern const char kAshEnableSmoothScreenRotationName[];
+
+// Description for the flag to enable smooth rotation animations.
+extern const char kAshEnableSmoothScreenRotationDescription[];
+
 // Description for the flag that sets material design ink drop animation speed
 // of fast.
 extern const char kMaterialDesignInkDropAnimationFast[];
@@ -1304,6 +1310,14 @@
 // main menu rather than under settings on Android
 extern const char kEnableDataReductionProxyMainMenuDescription[];
 
+// An about:flags experiment title to enable the site breakdown on the Data
+// Saver settings page.
+extern const char kEnableDataReductionProxySiteBreakdownName[];
+
+// Describes an about:flags experiment to enable the site breakdown on the Data
+// Saver settings page.
+extern const char kEnableDataReductionProxySiteBreakdownDescription[];
+
 #endif  // defined(OS_ANDROID)
 
 // Name of about:flags option for LCD text.
diff --git a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
index 237ae6c..691ac8c 100644
--- a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
@@ -119,8 +119,6 @@
     video_mp4_codecs_.push_back("avc1.4D000C");  // Main profile.
     video_mp4_codecs_.push_back("avc3.64001F");  // High profile.
 
-    video_mp4_codecs_.push_back("vp09.00.10.08");
-
     video_mp4_hi10p_codecs_.push_back("avc1.6E001E");  // Hi10P profile
 
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
@@ -131,6 +129,9 @@
     invalid_codecs_.push_back("hev1.1.6.L93.B0");
 #endif
 
+    // Codecs allowed by both MP4 and WebM (with given command line flags).
+    video_common_codecs_.push_back("vp09.00.10.08");
+
     // Extended codecs are used, so make sure generic ones fail. These will be
     // tested against all initDataTypes as they should always fail to be
     // supported.
@@ -154,11 +155,15 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     InProcessBrowserTest::SetUpCommandLine(command_line);
     command_line->AppendSwitch(switches::kEnableVp9InMp4);
+    command_line->AppendSwitch(switches::kEnableNewVp9CodecString);
   }
 
   typedef std::vector<std::string> CodecVector;
 
   const CodecVector& no_codecs() const { return no_codecs_; }
+  const CodecVector& video_common_codecs() const {
+    return video_common_codecs_;
+  }
   const CodecVector& audio_webm_codecs() const { return audio_webm_codecs_; }
   const CodecVector& video_webm_codecs() const { return video_webm_codecs_; }
   const CodecVector& audio_mp4_codecs() const { return audio_mp4_codecs_; }
@@ -269,6 +274,7 @@
   CodecVector audio_mp4_codecs_;
   CodecVector video_mp4_codecs_;
   CodecVector video_mp4_hi10p_codecs_;
+  CodecVector video_common_codecs_;
   CodecVector invalid_codecs_;
 };
 
@@ -404,6 +410,8 @@
   // Valid video types.
   EXPECT_SUCCESS(AreCodecsSupportedByKeySystem(
       kVideoWebMMimeType, video_webm_codecs(), kClearKey));
+  EXPECT_SUCCESS(AreCodecsSupportedByKeySystem(
+      kVideoWebMMimeType, video_common_codecs(), kClearKey));
 
   // Non-video WebM codecs.
   EXPECT_NO_MATCH(AreCodecsSupportedByKeySystem(
@@ -440,6 +448,8 @@
   // Valid video types.
   EXPECT_PROPRIETARY(AreCodecsSupportedByKeySystem(
       kVideoMP4MimeType, video_mp4_codecs(), kClearKey));
+  EXPECT_SUCCESS(AreCodecsSupportedByKeySystem(
+      kVideoWebMMimeType, video_common_codecs(), kClearKey));
 
   // High 10-bit Profile is supported when using ClearKey if
   // it is supported for clear content on this platform.
@@ -548,6 +558,8 @@
   // Valid video types.
   EXPECT_ECK(AreCodecsSupportedByKeySystem(
       kVideoWebMMimeType, video_webm_codecs(), kExternalClearKey));
+  EXPECT_ECK(AreCodecsSupportedByKeySystem(
+      kVideoWebMMimeType, video_common_codecs(), kExternalClearKey));
 
   // Non-video WebM codecs.
   EXPECT_ECK_NO_MATCH(AreCodecsSupportedByKeySystem(
@@ -586,6 +598,8 @@
   // Valid video types.
   EXPECT_ECK_PROPRIETARY(AreCodecsSupportedByKeySystem(
       kVideoMP4MimeType, video_mp4_codecs(), kExternalClearKey));
+  EXPECT_ECK(AreCodecsSupportedByKeySystem(
+      kVideoWebMMimeType, video_common_codecs(), kExternalClearKey));
 
   // High 10-bit Profile is not supported when using ExternalClearKey.
   EXPECT_ECK_NO_MATCH(AreCodecsSupportedByKeySystem(
@@ -648,6 +662,8 @@
       kVideoMP4MimeType, video_mp4_codecs(), kWidevine));
   EXPECT_WV_PROPRIETARY(AreCodecsSupportedByKeySystem(
       kAudioMP4MimeType, audio_mp4_codecs(), kWidevine));
+  EXPECT_WV_PROPRIETARY(AreCodecsSupportedByKeySystem(
+      kAudioMP4MimeType, video_common_codecs(), kWidevine));
 }
 
 IN_PROC_BROWSER_TEST_F(EncryptedMediaSupportedTypesWidevineTest, NoCodecs) {
@@ -665,6 +681,8 @@
   // Valid video types.
   EXPECT_WV_SUCCESS(AreCodecsSupportedByKeySystem(
       kVideoWebMMimeType, video_webm_codecs(), kWidevine));
+  EXPECT_WV_SUCCESS(AreCodecsSupportedByKeySystem(
+      kVideoWebMMimeType, video_common_codecs(), kWidevine));
 
   // Non-video WebM codecs.
   EXPECT_WV_NO_MATCH(AreCodecsSupportedByKeySystem(
@@ -701,6 +719,8 @@
   // Valid video types.
   EXPECT_WV_PROPRIETARY(AreCodecsSupportedByKeySystem(
       kVideoMP4MimeType, video_mp4_codecs(), kWidevine));
+  EXPECT_WV_SUCCESS(AreCodecsSupportedByKeySystem(
+      kVideoWebMMimeType, video_common_codecs(), kWidevine));
 
   // High 10-bit Profile is not supported when using Widevine.
   EXPECT_WV_NO_MATCH(AreCodecsSupportedByKeySystem(
diff --git a/chrome/browser/resources/md_downloads/downloads.html b/chrome/browser/resources/md_downloads/downloads.html
index c299f81..789c1d5 100644
--- a/chrome/browser/resources/md_downloads/downloads.html
+++ b/chrome/browser/resources/md_downloads/downloads.html
@@ -1,18 +1,22 @@
 <!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}">
+<html dir="$i18n{textdirection}" lang="$i18n{language}" class="loading">
 <head>
   <meta charset="utf-8">
   <title>$i18n{title}</title>
   <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
-  <link rel="stylesheet" href="chrome://resources/css/md_colors.css">
   <style>
     html {
       --downloads-card-margin: 24px;
       --downloads-card-width: 640px;
-      background: var(--md-background-color);
+      background: #f1f1f1;
     }
 
-    html,
+    .loading {
+      /* --google-blue-700 disguised. Replaced when downloads-toolbar loads. */
+      border-top: 56px solid rgb(51, 103, 214);
+    }
+
+    html:not(.loading),
     body {
       height: 100%;
     }
diff --git a/chrome/browser/resources/md_downloads/item.html b/chrome/browser/resources/md_downloads/item.html
index 98d711f..f057735 100644
--- a/chrome/browser/resources/md_downloads/item.html
+++ b/chrome/browser/resources/md_downloads/item.html
@@ -7,6 +7,7 @@
 <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-progress/paper-progress.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
 <link rel="import" href="chrome://downloads/action_service.html">
 <link rel="import" href="chrome://downloads/constants.html">
diff --git a/chrome/browser/resources/md_downloads/manager.html b/chrome/browser/resources/md_downloads/manager.html
index 333273d..34aa9e9 100644
--- a/chrome/browser/resources/md_downloads/manager.html
+++ b/chrome/browser/resources/md_downloads/manager.html
@@ -10,7 +10,6 @@
 <link rel="import" href="chrome://downloads/i18n_setup.html">
 <link rel="import" href="chrome://downloads/item.html">
 <link rel="import" href="chrome://downloads/toolbar.html">
-<link rel="stylesheet" href="chrome://resources/css/md_colors.css">
 
 <dom-module id="downloads-manager">
   <template>
diff --git a/chrome/browser/resources/md_downloads/manager.js b/chrome/browser/resources/md_downloads/manager.js
index d01c3d3..ec56d51 100644
--- a/chrome/browser/resources/md_downloads/manager.js
+++ b/chrome/browser/resources/md_downloads/manager.js
@@ -40,6 +40,7 @@
     },
 
     hostAttributes: {
+      // TODO(dbeam): this should use a class instead.
       loading: true,
     },
 
@@ -52,6 +53,10 @@
       'itemsChanged_(items_.*)',
     ],
 
+    attached: function() {
+      document.documentElement.classList.remove('loading');
+    },
+
     /** @private {!PromiseResolver} */
     loaded_: new PromiseResolver,
 
diff --git a/chrome/browser/resources/md_downloads/toolbar.html b/chrome/browser/resources/md_downloads/toolbar.html
index da1cb35..bda557e 100644
--- a/chrome/browser/resources/md_downloads/toolbar.html
+++ b/chrome/browser/resources/md_downloads/toolbar.html
@@ -5,6 +5,7 @@
 <link rel="import" href="chrome://resources/html/util.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-icon-button/paper-icon-button-light.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.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_toolbar/cr_toolbar.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
@@ -14,7 +15,7 @@
     <style>
       :host {
         align-items: center;
-        background: var(--md-toolbar-color);
+        background: var(--google-blue-700);
         color: white;
         display: flex;
         min-height: 56px;
diff --git a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js
index 7d1509d..e9ca220 100644
--- a/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js
+++ b/chrome/browser/resources/settings/appearance_page/appearance_fonts_page.js
@@ -47,9 +47,6 @@
       /** @private */
       advancedExtensionUrl_: String,
 
-      /** @private {!settings.FontsBrowserProxy} */
-      browserProxy_: Object,
-
       /** @private {!DropdownMenuOptionList} */
       fontOptions_: Object,
 
@@ -92,6 +89,9 @@
       'fontSizeChanged_(prefs.webkit.webprefs.default_font_size.value)',
     ],
 
+    /** @private {?settings.FontsBrowserProxy} */
+    browserProxy_: null,
+
     /** @override */
     created: function() {
       this.browserProxy_ = settings.FontsBrowserProxyImpl.getInstance();
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js
index 898e479..5f0dee2 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js
@@ -57,7 +57,7 @@
    * @private
    */
   getConnectActionText_: function(connected) {
-    return this.i18n(connected ? 'bluetoothDisconnect' : 'bluetoothPair');
+    return this.i18n(connected ? 'bluetoothDisconnect' : 'bluetoothConnect');
   },
 
   /**
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
index 6e032ae..2174134 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -32,10 +32,13 @@
               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_" aria-label="$i18n{bluetoothPageTitle}"
-              aria-describedby="bluetoothSecondary">
-          </button>
+          <template is="dom-if" if="[[bluetoothEnabled_]]">
+            <button class="subpage-arrow" is="paper-icon-button-light"
+                on-tap="onSubpageArrowTap_"
+                aria-label="$i18n{bluetoothPageTitle}"
+                aria-describedby="bluetoothSecondary">
+            </button>
+          </template>
           <div class="secondary-action">
             <paper-toggle-button id="enableBluetooth"
                 checked="{{bluetoothEnabled_}}"
diff --git a/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js b/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js
index 5b5114d..3139be3 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js
+++ b/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js
@@ -12,9 +12,6 @@
   is: 'settings-ca-trust-edit-dialog',
 
   properties: {
-    /** @private {!settings.CertificatesBrowserProxy} */
-    browserProxy_: Object,
-
     /** @type {!CertificateSubnode|!NewCertificateSubNode} */
     model: Object,
 
@@ -25,6 +22,9 @@
     explanationText_: String,
   },
 
+  /** @private {?settings.CertificatesBrowserProxy} */
+  browserProxy_: null,
+
   /** @override */
   ready: function() {
     this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js b/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js
index 3167d45..0ed71801 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js
@@ -10,9 +10,6 @@
   is: 'settings-certificate-delete-confirmation-dialog',
 
   properties: {
-    /** @private {!settings.CertificatesBrowserProxy} */
-    browserProxy_: Object,
-
     /** @type {!CertificateSubnode} */
     model: Object,
 
@@ -20,6 +17,9 @@
     certificateType: String,
   },
 
+  /** @private {?settings.CertificatesBrowserProxy} */
+  browserProxy_: null,
+
   /** @override */
   ready: function() {
     this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js
index 368b0b1f..3ecc2f0 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js
@@ -10,9 +10,6 @@
   is: 'settings-certificate-password-decryption-dialog',
 
   properties: {
-    /** @private {!settings.CertificatesBrowserProxy} */
-    browserProxy_: Object,
-
     /** @private */
     password_: {
       type: String,
@@ -20,6 +17,9 @@
     },
   },
 
+  /** @private {?settings.CertificatesBrowserProxy} */
+  browserProxy_: null,
+
   /** @override */
   ready: function() {
     this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js
index 1f113b9..a768879 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js
@@ -10,9 +10,6 @@
   is: 'settings-certificate-password-encryption-dialog',
 
   properties: {
-    /** @private {!settings.CertificatesBrowserProxy} */
-    browserProxy_: Object,
-
     /** @type {!CertificateSubnode} */
     model: Object,
 
@@ -29,6 +26,9 @@
     },
   },
 
+  /** @private {?settings.CertificatesBrowserProxy} */
+  browserProxy_: null,
+
   /** @override */
   ready: function() {
     this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance();
diff --git a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
index 162641b..b276bf4 100644
--- a/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
+++ b/chrome/browser/resources/settings/languages_page/edit_dictionary_page.js
@@ -121,15 +121,8 @@
     var index = this.words_.indexOf(word);
     if (index == -1) {
       this.languageSettingsPrivate.addSpellcheckWord(word);
-      this.push('words_', word);
-      index = this.words_.length - 1;
+      this.unshift('words_', word);
     }
-
-    // Scroll to the word (usually the bottom, or to the index if the word
-    // is already present).
-    this.async(function(){
-      this.root.querySelector('#list').scrollToIndex(index);
-    });
   },
 
   /**
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
index e89623be..c17ed77 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
@@ -15,9 +15,6 @@
   properties: {
     prefs: Object,
 
-    /** @type {settings.StartupUrlsPageBrowserProxy} */
-    browserProxy_: Object,
-
     /**
      * Pages to load upon browser startup.
      * @private {!Array<!StartupPageInfo>}
@@ -34,6 +31,9 @@
     lastFocused_: Object,
   },
 
+  /** @private {?settings.StartupUrlsPageBrowserProxy} */
+  browserProxy_: null,
+
   /**
    * The element to return focus to, when the startup-url-dialog is closed.
    * @private {?HTMLElement}
diff --git a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
index 7be4018..41543e0 100644
--- a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
@@ -122,6 +122,7 @@
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
         'easy_unlock_browser_proxy',
         'easy_unlock_turn_off_dialog',
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index f217e571c..8cc134f 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -4,6 +4,7 @@
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/html/icon.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/util.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
diff --git a/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js b/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js
index 30600fd..25a90f0 100644
--- a/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js
+++ b/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js
@@ -12,11 +12,11 @@
   properties: {
     /** @type {!SearchEngine} */
     engine: Object,
-
-    /** @private {!settings.ExtensionControlBrowserProxy} */
-    browserProxy_: Object,
   },
 
+  /** @private {?settings.ExtensionControlBrowserProxy} */
+  browserProxy_: null,
+
   /** @override */
   created: function() {
     this.browserProxy_ =
diff --git a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js b/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
index 7196b784..ed83ad9 100644
--- a/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
+++ b/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js
@@ -15,12 +15,6 @@
 
   properties: {
     /**
-     * The browser proxy used to retrieve and change cookies.
-     * @type {settings.SiteSettingsPrefsBrowserProxy}
-     */
-    browserProxy: Object,
-
-    /**
      * The cookie entries for the given site.
      * @type {!Array<!CookieDetails>}
      * @private
@@ -40,9 +34,15 @@
     siteId_: String,
   },
 
+  /**
+   * The browser proxy used to retrieve and change cookies.
+   * @private {?settings.SiteSettingsPrefsBrowserProxy}
+   */
+  browserProxy_: null,
+
   /** @override */
   ready: function() {
-    this.browserProxy =
+    this.browserProxy_ =
         settings.SiteSettingsPrefsBrowserProxyImpl.getInstance();
 
     this.addWebUIListener('onTreeItemRemoved',
@@ -69,7 +69,7 @@
   getCookieDetails_: function() {
     if (!this.site_)
       return;
-    this.browserProxy.getCookieDetails(this.site_).then(
+    this.browserProxy_.getCookieDetails(this.site_).then(
         this.onCookiesLoaded_.bind(this),
         this.onCookiesLoadFailed_.bind(this));
   },
@@ -124,7 +124,7 @@
    * @private
    */
   onRemove_: function(event) {
-    this.browserProxy.removeCookie(
+    this.browserProxy_.removeCookie(
         /** @type {!CookieDetails} */(event.currentTarget.dataset).idPath);
   },
 
@@ -132,7 +132,7 @@
    * A handler for when the user opts to remove all cookies.
    */
   removeAll: function() {
-    this.browserProxy.removeCookie(this.siteId_);
+    this.browserProxy_.removeCookie(this.siteId_);
   },
 });
 
diff --git a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html
index ca7b87e..582a25a 100644
--- a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html
+++ b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html
@@ -1,9 +1,11 @@
 <!doctype html>
-<html i18n-values="dir:textdirection;lang:language">
+<html dir="$i18n{textdirection}" lang="$i18n{language}">
   <head>
     <meta charset="utf-8">
     <link rel="import" href="chrome://resources/html/polymer.html">
+    <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.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-checkbox/paper-checkbox.html">
     <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
     <link rel="import" href="signin_shared_css.html">
     <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
@@ -15,6 +17,15 @@
         -webkit-margin-start: 0;
       }
 </if>
+      /* TODO(dbeam): de-duplicate this style with MD Settings. */
+      paper-checkbox {
+        --paper-checkbox-checked-color: var(--google-blue-500);
+        --paper-checkbox-label-color: inherit;
+        --paper-checkbox-label-spacing: 18px;
+        --paper-checkbox-size: 16px;
+        --paper-checkbox-unchecked-color: var(--paper-grey-600);
+        -webkit-margin-start: 2px;
+      }
     </style>
   </head>
   <body>
@@ -56,8 +67,9 @@
           <div id="chrome-logo" class="logo"></div>
           <div>
             <div class="title">$i18n{syncConfirmationChromeSyncTitle}</div>
-            <div class="body text"
-                i18n-values=".innerHTML:syncConfirmationChromeSyncBody"></div>
+            <div class="body text">
+              $i18nRaw{syncConfirmationChromeSyncBody}
+            </div>
           </div>
         </div>
         <div class="message-container">
@@ -76,8 +88,10 @@
           </div>
         </div>
         <div class="message-container">
-          <div class="body"
-              i18n-values=".innerHTML:syncConfirmationSyncSettingsLinkBody">
+          <div class="body">
+            <paper-checkbox id="configure-before-signing-in">
+              $i18n{syncConfirmationSyncSettingsLabel}
+            </paper-checkbox>
           </div>
         </div>
       </div>
@@ -99,5 +113,4 @@
   <script src="chrome://resources/js/util.js"></script>
   <script src="sync_confirmation.js"></script>
   <script src="chrome://sync-confirmation/strings.js"></script>
-  <script src="chrome://resources/js/i18n_template.js"></script>
 </html>
diff --git a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.js b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.js
index 1f51ec8..c7f9c10 100644
--- a/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.js
+++ b/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.js
@@ -6,23 +6,18 @@
   'use strict';
 
   function onConfirm(e) {
-    chrome.send('confirm');
+    chrome.send('confirm', [$('configure-before-signing-in').checked]);
   }
 
   function onUndo(e) {
     chrome.send('undo');
   }
 
-  function onGoToSettings(e) {
-    chrome.send('goToSettings');
-  }
-
   function initialize() {
     document.addEventListener('keydown', onKeyDown);
     $('confirmButton').addEventListener('click', onConfirm);
     $('undoButton').addEventListener('click', onUndo);
     if (loadTimeData.getBoolean('isSyncAllowed')) {
-      $('settingsLink').addEventListener('click', onGoToSettings);
       $('profile-picture').addEventListener('load', onPictureLoaded);
       $('syncDisabledDetails').hidden = true;
     } else {
diff --git a/chrome/browser/sync/test/integration/printers_helper.cc b/chrome/browser/sync/test/integration/printers_helper.cc
index 084e1d0..c098e4f 100644
--- a/chrome/browser/sync/test/integration/printers_helper.cc
+++ b/chrome/browser/sync/test/integration/printers_helper.cc
@@ -13,10 +13,12 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/threading/sequenced_worker_pool.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"
+#include "content/public/browser/browser_thread.h"
 
 using sync_datatype_helper::test;
 
@@ -65,6 +67,24 @@
   return base::StringPrintf("printer%d", index);
 }
 
+chromeos::PrintersManager* GetPrinterStore(content::BrowserContext* context) {
+  chromeos::PrintersManager* manager =
+      chromeos::PrintersManagerFactory::GetForBrowserContext(context);
+
+  // TODO(sync): crbug.com/709094: Remove all of this once the bug is fixed.
+  // Must wait for ModelTypeStore initialization.
+  // Since PrintersManagerFactory::BuildServiceInstanceFor() uses
+  // content::BrowserThread::GetBlockingPool() to schedule ModelTypeStore
+  // initialization, tests need to wait for initialization to be completed and
+  // sent ModelTypeStore to UI thread.
+  content::BrowserThread::GetBlockingPool()->FlushForTesting();
+  // Wait for UI thread task completion to make sure PrintersSyncBridge received
+  // ModelTypeStore.
+  base::RunLoop().RunUntilIdle();
+
+  return manager;
+}
+
 }  // namespace
 
 void AddPrinter(chromeos::PrintersManager* manager,
@@ -107,20 +127,14 @@
 
 chromeos::PrintersManager* GetVerifierPrinterStore() {
   chromeos::PrintersManager* manager =
-      chromeos::PrintersManagerFactory::GetForBrowserContext(
-          sync_datatype_helper::test()->verifier());
-  // Must wait for ModelTypeStore initialization.
-  base::RunLoop().RunUntilIdle();
+      GetPrinterStore(sync_datatype_helper::test()->verifier());
 
   return manager;
 }
 
 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();
+      GetPrinterStore(sync_datatype_helper::test()->GetProfile(index));
 
   return manager;
 }
diff --git a/chrome/browser/sync/test/integration/single_client_printers_sync_test.cc b/chrome/browser/sync/test/integration/single_client_printers_sync_test.cc
index c7a6a0f7..f2fd8d2e 100644
--- a/chrome/browser/sync/test/integration/single_client_printers_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_printers_sync_test.cc
@@ -25,14 +25,6 @@
   SingleClientPrintersSyncTest() : SyncTest(SINGLE_CLIENT) {}
   ~SingleClientPrintersSyncTest() override {}
 
-  bool SetupSync() override {
-    if (!SyncTest::SetupSync())
-      return false;
-
-    // Wait for sync to complete initialization before proceeding.
-    return UpdatedProgressMarkerChecker(GetSyncService(0)).Wait();
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(SingleClientPrintersSyncTest);
 };
@@ -40,6 +32,12 @@
 // Verify that printers aren't added with a sync call.
 IN_PROC_BROWSER_TEST_F(SingleClientPrintersSyncTest, NoPrinters) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  // TODO(sync): Should not use UpdatedProgressMarkerChecker here since
+  // UpdatedProgressMarkerChecker is for SyncableService datatype, but
+  // syncer::PRINTERS is ModelTypeSyncBridge datatype. So maybe we should create
+  // another checker for ModelTypeSyncBridge, or some other things to wait for
+  // ModelTypeSyncBridge datatype.
+  ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
   EXPECT_TRUE(ProfileContainsSamePrintersAsVerifier(0));
 }
 
@@ -60,13 +58,7 @@
 }
 
 // Verify editing a printer doesn't add it.
-// Flaky on ChromeOS. http://crbug.com/701999
-#if defined(OS_CHROMEOS)
-#define MAYBE_EditPrinter DISABLED_EditPrinter
-#else
-#define MAYBE_EditPrinter EditPrinter
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientPrintersSyncTest, MAYBE_EditPrinter) {
+IN_PROC_BROWSER_TEST_F(SingleClientPrintersSyncTest, EditPrinter) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
   AddPrinter(GetPrinterStore(0), printers_helper::CreateTestPrinter(0));
@@ -92,13 +84,7 @@
 }
 
 // Verify that merging data added before sync works.
-// crbug.com/689662
-#if defined(OS_CHROMEOS)
-#define MAYBE_AddBeforeSetup DISABLED_AddBeforeSetup
-#else
-#define MAYBE_AddBeforeSetup AddBeforeSetup
-#endif
-IN_PROC_BROWSER_TEST_F(SingleClientPrintersSyncTest, MAYBE_AddBeforeSetup) {
+IN_PROC_BROWSER_TEST_F(SingleClientPrintersSyncTest, AddBeforeSetup) {
   ASSERT_TRUE(SetupClients());
 
   AddPrinter(GetPrinterStore(0), printers_helper::CreateTestPrinter(0));
diff --git a/chrome/browser/sync/test/integration/two_client_printers_sync_test.cc b/chrome/browser/sync/test/integration/two_client_printers_sync_test.cc
index 29ea6f0..9633883 100644
--- a/chrome/browser/sync/test/integration/two_client_printers_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_printers_sync_test.cc
@@ -128,13 +128,7 @@
   EXPECT_EQ(valid_message, GetPrinterStore(1)->GetPrinters()[0]->description());
 }
 
-// crbug.com/689662
-#if defined(OS_CHROMEOS)
-#define MAYBE_SimpleMerge DISABLED_SimpleMerge
-#else
-#define MAYBE_SimpleMerge SimpleMerge
-#endif
-IN_PROC_BROWSER_TEST_F(TwoClientPrintersSyncTest, MAYBE_SimpleMerge) {
+IN_PROC_BROWSER_TEST_F(TwoClientPrintersSyncTest, SimpleMerge) {
   ASSERT_TRUE(SetupClients());
   base::RunLoop().RunUntilIdle();
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 3144335..c37e7c1 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1502,6 +1502,8 @@
       "views/harmony/chrome_typography.h",
       "views/harmony/harmony_layout_delegate.cc",
       "views/harmony/harmony_layout_delegate.h",
+      "views/harmony/harmony_typography_provider.cc",
+      "views/harmony/harmony_typography_provider.h",
       "views/harmony/layout_delegate.cc",
       "views/harmony/layout_delegate.h",
       "views/location_bar/location_bar_bubble_delegate_view.cc",
@@ -3081,6 +3083,8 @@
       "views/network_profile_bubble_view.cc",
       "views/settings_reset_prompt_dialog.cc",
       "views/settings_reset_prompt_dialog.h",
+      "views/srt_prompt_dialog.cc",
+      "views/srt_prompt_dialog.h",
       "views/uninstall_view.cc",
       "views/uninstall_view.h",
       "webui/cleanup_tool/cleanup_action_handler.cc",
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
index f52c3f2..9efd0ce0 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
@@ -876,33 +876,46 @@
   int base_shelf_item_count = shelf_model()->item_count();
   ExtensionTestMessageListener completed_listener("Completed", false);
   LoadAndLaunchPlatformApp("app_icon", "Launched");
+
   ASSERT_TRUE(completed_listener.WaitUntilSatisfied());
 
   // Now wait until the WebContent has decoded the icons and chrome has
   // processed it. This needs to be in a loop since the renderer runs in a
   // different process.
-  while (test_observer.icon_updates() < 3) {
+  while (test_observer.icon_updates() < 4) {
     base::RunLoop run_loop;
     run_loop.RunUntilIdle();
   }
 
-  // This test creates one app window and one panel window.
+  // This test creates one app window, one app window with custom icon and one
+  // panel window.
   int shelf_item_count = shelf_model()->item_count();
-  ASSERT_EQ(base_shelf_item_count + 2, shelf_item_count);
+  ASSERT_EQ(base_shelf_item_count + 3, shelf_item_count);
   // The Panel will be the last item, the app second-to-last.
-  const ash::ShelfItem& app_item =
+  const ash::ShelfItem& app_item = shelf_model()->items()[shelf_item_count - 3];
+  const ash::ShelfItem& app_custom_icon_item =
       shelf_model()->items()[shelf_item_count - 2];
   const ash::ShelfItem& panel_item =
       shelf_model()->items()[shelf_item_count - 1];
+
   // Icons for Apps are set by the AppWindowLauncherController, so
   // image_set_by_controller() should be set.
   const ash::ShelfItemDelegate* app_item_delegate =
       GetShelfItemDelegate(app_item.id);
-  EXPECT_TRUE(app_item_delegate->image_set_by_controller());
+  ASSERT_TRUE(app_item_delegate);
+  EXPECT_FALSE(app_item_delegate->image_set_by_controller());
+
+  const ash::ShelfItemDelegate* app_custom_icon_item_delegate =
+      GetShelfItemDelegate(app_custom_icon_item.id);
+  ASSERT_TRUE(app_custom_icon_item_delegate);
+  EXPECT_TRUE(app_custom_icon_item_delegate->image_set_by_controller());
+
   // Panels are handled by ShelfWindowWatcher, not ChromeLauncherController.
   EXPECT_EQ(nullptr, GetShelfItemDelegate(panel_item.id));
   // Ensure icon heights are correct (see test.js in app_icon/ test directory)
-  EXPECT_EQ(ash::GetShelfConstant(ash::SHELF_SIZE), app_item.image.height());
+  EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALL, app_item.image.height());
+  EXPECT_EQ(extension_misc::EXTENSION_ICON_LARGE,
+            app_custom_icon_item.image.height());
   EXPECT_EQ(64, panel_item.image.height());
 }
 
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
index 669ce2e..7b1ed43 100644
--- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
@@ -92,6 +92,12 @@
   AppControllerMap::iterator iter = app_controller_map_.find(app_shelf_id);
   if (iter == app_controller_map_.end())
     return;
+
+  // Check if the window actually overrides its default icon. Otherwise use app
+  // icon loader provided by owner.
+  if (!app_window->HasCustomIcon() || app_window->app_icon().IsEmpty())
+    return;
+
   ExtensionAppWindowLauncherItemController* controller = iter->second;
   controller->set_image_set_by_controller(true);
   owner()->SetLauncherItemImage(controller->shelf_id(),
@@ -182,9 +188,9 @@
     if (shelf_id == 0) {
       shelf_id = owner()->CreateAppLauncherItem(std::move(controller), status);
       // Restore any existing app icon and flag as set.
-      const gfx::Image& app_icon = app_window->app_icon();
-      if (!app_icon.IsEmpty()) {
-        owner()->SetLauncherItemImage(shelf_id, app_icon.AsImageSkia());
+      if (app_window->HasCustomIcon() && !app_window->app_icon().IsEmpty()) {
+        owner()->SetLauncherItemImage(shelf_id,
+                                      app_window->app_icon().AsImageSkia());
         item_controller->set_image_set_by_controller(true);
       }
     } else {
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index 0a42c63..7bcd9c4 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -55,6 +55,10 @@
 class PaymentRequestDialog;
 }
 
+namespace safe_browsing {
+class SRTPromptController;
+}
+
 namespace security_state {
 struct SecurityInfo;
 }  // namespace security_state
@@ -189,6 +193,16 @@
 // Record an UMA metric counting the creation of a dialog box of this type.
 void RecordDialogCreation(DialogIdentifier identifier);
 
+#if defined(OS_WIN)
+
+// Shows the Chrome Cleanup dialog asking the user if they want to clean their
+// system from unwanted software. This is called when unwanted software has been
+// detected on the system.
+void ShowSRTPrompt(Browser* browser,
+                   safe_browsing::SRTPromptController* controller);
+
+#endif  // OS_WIN
+
 }  // namespace chrome
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/startup/startup_tab_provider.cc b/chrome/browser/ui/startup/startup_tab_provider.cc
index a68ea46..f8a25f3 100644
--- a/chrome/browser/ui/startup/startup_tab_provider.cc
+++ b/chrome/browser/ui/startup/startup_tab_provider.cc
@@ -56,6 +56,7 @@
   PrefService* prefs = profile->GetPrefs();
   bool has_seen_welcome_page =
       prefs && prefs->GetBoolean(prefs::kHasSeenWelcomePage);
+  bool is_signin_allowed = profile->IsSyncAllowed();
   SigninManagerBase* signin_manager =
       SigninManagerFactory::GetForProfile(profile);
   bool is_signed_in = signin_manager && signin_manager->IsAuthenticated();
@@ -82,13 +83,15 @@
         g_browser_process->CachedDefaultWebClientState() ==
         shell_integration::IS_DEFAULT;
     return GetWin10OnboardingTabsForState(
-        is_first_run, has_seen_welcome_page, has_seen_win10_promo, is_signed_in,
-        set_default_browser_allowed, is_default_browser, is_supervised_user);
+        is_first_run, has_seen_welcome_page, has_seen_win10_promo,
+        is_signin_allowed, is_signed_in, set_default_browser_allowed,
+        is_default_browser, is_supervised_user);
   }
 #endif  // defined(OS_WIN)
 
   return GetStandardOnboardingTabsForState(is_first_run, has_seen_welcome_page,
-                                           is_signed_in, is_supervised_user);
+                                           is_signin_allowed, is_signed_in,
+                                           is_supervised_user);
 #endif  // defined(OS_CHROMEOS)
 }
 
@@ -139,10 +142,12 @@
 StartupTabs StartupTabProviderImpl::GetStandardOnboardingTabsForState(
     bool is_first_run,
     bool has_seen_welcome_page,
+    bool is_signin_allowed,
     bool is_signed_in,
     bool is_supervised_user) {
   StartupTabs tabs;
-  if (!has_seen_welcome_page && !is_signed_in && !is_supervised_user)
+  if (!has_seen_welcome_page && is_signin_allowed && !is_signed_in &&
+      !is_supervised_user)
     tabs.emplace_back(GetWelcomePageUrl(!is_first_run), false);
   return tabs;
 }
@@ -153,6 +158,7 @@
     bool is_first_run,
     bool has_seen_welcome_page,
     bool has_seen_win10_promo,
+    bool is_signin_allowed,
     bool is_signed_in,
     bool set_default_browser_allowed,
     bool is_default_browser,
@@ -165,7 +171,7 @@
   if (set_default_browser_allowed && !has_seen_win10_promo &&
       !is_default_browser) {
     tabs.emplace_back(GetWin10WelcomePageUrl(!is_first_run), false);
-  } else if (!has_seen_welcome_page && !is_signed_in) {
+  } else if (!has_seen_welcome_page && is_signin_allowed && !is_signed_in) {
     tabs.emplace_back(GetWelcomePageUrl(!is_first_run), false);
   }
   return tabs;
diff --git a/chrome/browser/ui/startup/startup_tab_provider.h b/chrome/browser/ui/startup/startup_tab_provider.h
index 79bf524..4fd01b67 100644
--- a/chrome/browser/ui/startup/startup_tab_provider.h
+++ b/chrome/browser/ui/startup/startup_tab_provider.h
@@ -64,6 +64,7 @@
   static StartupTabs GetStandardOnboardingTabsForState(
       bool is_first_run,
       bool has_seen_welcome_page,
+      bool is_signin_allowed,
       bool is_signed_in,
       bool is_supervised_user);
 
@@ -74,6 +75,7 @@
       bool is_first_run,
       bool has_seen_welcome_page,
       bool has_seen_win10_promo,
+      bool is_signin_allowed,
       bool is_signed_in,
       bool set_default_browser_allowed,
       bool is_default_browser,
diff --git a/chrome/browser/ui/startup/startup_tab_provider_unittest.cc b/chrome/browser/ui/startup/startup_tab_provider_unittest.cc
index c03d8cc3..2822f6c 100644
--- a/chrome/browser/ui/startup/startup_tab_provider_unittest.cc
+++ b/chrome/browser/ui/startup/startup_tab_provider_unittest.cc
@@ -12,8 +12,8 @@
 TEST(StartupTabProviderTest, GetStandardOnboardingTabsForState) {
   // Show welcome page to new unauthenticated profile on first run.
   StartupTabs output =
-      StartupTabProviderImpl::GetStandardOnboardingTabsForState(true, false,
-                                                                false, false);
+      StartupTabProviderImpl::GetStandardOnboardingTabsForState(
+          true, false, true, false, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWelcomePageUrl(false), output[0].url);
@@ -21,7 +21,7 @@
 
   // After first run, display welcome page using variant view.
   output = StartupTabProviderImpl::GetStandardOnboardingTabsForState(
-      false, false, false, false);
+      false, false, true, false, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWelcomePageUrl(true), output[0].url);
@@ -31,20 +31,26 @@
 TEST(StartupTabProviderTest, GetStandardOnboardingTabsForState_Negative) {
   // Do not show the welcome page to the same profile twice.
   StartupTabs output =
-      StartupTabProviderImpl::GetStandardOnboardingTabsForState(true, true,
-                                                                false, false);
+      StartupTabProviderImpl::GetStandardOnboardingTabsForState(
+          true, true, true, false, false);
 
   EXPECT_TRUE(output.empty());
 
   // Do not show the welcome page to authenticated users.
   output = StartupTabProviderImpl::GetStandardOnboardingTabsForState(
-      true, false, true, false);
+      true, false, true, true, false);
+
+  EXPECT_TRUE(output.empty());
+
+  // Do not show the welcome page if sign-in is disabled.
+  output = StartupTabProviderImpl::GetStandardOnboardingTabsForState(
+      true, false, false, false, false);
 
   EXPECT_TRUE(output.empty());
 
   // Do not show the welcome page to supervised users.
   output = StartupTabProviderImpl::GetStandardOnboardingTabsForState(
-      true, false, false, true);
+      true, false, true, false, true);
 
   EXPECT_TRUE(output.empty());
 }
@@ -54,7 +60,7 @@
   // Show Win 10 Welcome page if it has not been seen, but the standard page
   // has.
   StartupTabs output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, true, false, false, true, false, false);
+      true, true, false, true, false, true, false, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWin10WelcomePageUrl(false),
@@ -64,7 +70,7 @@
   // Show standard Welcome page if the Win 10 Welcome page has been seen, but
   // the standard page has not.
   output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, false, true, false, true, false, false);
+      true, false, true, true, false, true, false, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWelcomePageUrl(false), output[0].url);
@@ -73,7 +79,7 @@
   // If neither page has been seen, the Win 10 Welcome page takes precedence
   // this launch.
   output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, false, false, false, true, false, false);
+      true, false, false, true, false, true, false, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWin10WelcomePageUrl(false),
@@ -85,7 +91,7 @@
   // Show a variant of the Win 10 Welcome page after first run, if it has not
   // been seen.
   StartupTabs output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      false, false, false, false, true, false, false);
+      false, false, false, true, false, true, false, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWin10WelcomePageUrl(true),
@@ -95,7 +101,7 @@
   // Show a variant of the standard Welcome page after first run, if the Win 10
   // Welcome page has already been seen but the standard has not.
   output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      false, false, true, false, true, false, false);
+      false, false, true, true, false, true, false, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWelcomePageUrl(true), output[0].url);
@@ -105,20 +111,20 @@
 TEST(StartupTabProviderTest, GetWin10OnboardingTabsForState_Negative) {
   // Do not show either page if it has already been shown.
   StartupTabs output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, true, true, false, true, false, false);
+      true, true, true, true, false, true, false, false);
 
   EXPECT_TRUE(output.empty());
 
   // Do not show either page to supervised users.
   output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, false, false, false, true, false, true);
+      true, false, false, true, false, true, false, true);
 
   EXPECT_TRUE(output.empty());
 
   // If Chrome is already the default browser, don't show the Win 10 Welcome
   // page, and don't preempt the standard Welcome page.
   output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, false, false, false, true, true, false);
+      true, false, false, true, false, true, true, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWelcomePageUrl(false), output[0].url);
@@ -126,7 +132,13 @@
 
   // If the user is signed in, block showing the standard Welcome page.
   output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, false, true, true, true, false, false);
+      true, false, true, true, true, true, false, false);
+
+  EXPECT_TRUE(output.empty());
+
+  // If sign-in is disabled, block showing the standard Welcome page.
+  output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
+      true, false, true, false, false, true, false, false);
 
   EXPECT_TRUE(output.empty());
 }
@@ -135,7 +147,7 @@
      GetWin10OnboardingTabsForState_SetDefaultBrowserNotAllowed) {
   // Skip the Win 10 promo if setting the default browser is not allowed.
   StartupTabs output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, false, false, false, false, false, false);
+      true, false, false, true, false, false, false, false);
 
   ASSERT_EQ(1U, output.size());
   EXPECT_EQ(StartupTabProviderImpl::GetWelcomePageUrl(false), output[0].url);
@@ -143,7 +155,7 @@
   // After first run, no onboarding content is displayed when setting the
   // default browser is not allowed.
   output = StartupTabProviderImpl::GetWin10OnboardingTabsForState(
-      true, true, false, false, false, false, false);
+      true, true, false, true, false, false, false, false);
 
   EXPECT_TRUE(output.empty());
 }
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
index ba493b5..5d331b46 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -428,7 +428,7 @@
     case LoginUIService::CONFIGURE_SYNC_FIRST:
       base::RecordAction(
           base::UserMetricsAction("Signin_Signin_WithAdvancedSyncSettings"));
-      chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage);
+      ShowSyncSetupSettingsSubpage();
       break;
     case LoginUIService::SYNC_WITH_DEFAULT_SETTINGS: {
       base::RecordAction(
@@ -573,6 +573,10 @@
   return browser;
 }
 
+void OneClickSigninSyncStarter::ShowSyncSetupSettingsSubpage() {
+  chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage);
+}
+
 void OneClickSigninSyncStarter::ShowSettingsPage(bool configure_sync) {
   // Give the user a chance to configure things. We don't clear the
   // ProfileSyncService::setup_in_progress flag because we don't want sync
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.h b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
index 0936bfa..7311d29 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.h
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.h
@@ -132,14 +132,18 @@
   // desktop, adds an empty tab and makes sure the browser is visible.
   static Browser* EnsureBrowser(Browser* browser, Profile* profile);
 
+ protected:
+  ~OneClickSigninSyncStarter() override;
+
+  // Overridden from tests.
+  virtual void ShowSyncSetupSettingsSubpage();
+
  private:
   friend class OneClickSigninSyncStarterTest;
   FRIEND_TEST_ALL_PREFIXES(OneClickSigninSyncStarterTest, CallbackSigninFailed);
   FRIEND_TEST_ALL_PREFIXES(OneClickSigninSyncStarterTest, CallbackNull);
   FRIEND_TEST_ALL_PREFIXES(OneClickSigninSyncStarterTest, LoadContinueUrl);
 
-  ~OneClickSigninSyncStarter() override;
-
   // Initializes the internals of the OneClickSigninSyncStarter object. Can also
   // be used to re-initialize the object to refer to a newly created profile.
   void Initialize(Profile* profile, Browser* browser);
diff --git a/chrome/browser/ui/views/harmony/harmony_layout_delegate.cc b/chrome/browser/ui/views/harmony/harmony_layout_delegate.cc
index 8afd203..5e333acc 100644
--- a/chrome/browser/ui/views/harmony/harmony_layout_delegate.cc
+++ b/chrome/browser/ui/views/harmony/harmony_layout_delegate.cc
@@ -96,3 +96,8 @@
   NOTREACHED();
   return 0;
 }
+
+const views::TypographyProvider& HarmonyLayoutDelegate::GetTypographyProvider()
+    const {
+  return typography_provider_;
+}
diff --git a/chrome/browser/ui/views/harmony/harmony_layout_delegate.h b/chrome/browser/ui/views/harmony/harmony_layout_delegate.h
index c750bff..3fd0907 100644
--- a/chrome/browser/ui/views/harmony/harmony_layout_delegate.h
+++ b/chrome/browser/ui/views/harmony/harmony_layout_delegate.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_HARMONY_HARMONY_LAYOUT_DELEGATE_H_
 #define CHROME_BROWSER_UI_VIEWS_HARMONY_HARMONY_LAYOUT_DELEGATE_H_
 
+#include "chrome/browser/ui/views/harmony/harmony_typography_provider.h"
 #include "chrome/browser/ui/views/harmony/layout_delegate.h"
 
 class HarmonyLayoutDelegate : public LayoutDelegate {
@@ -25,8 +26,11 @@
   bool IsHarmonyMode() const override;
   int GetDialogPreferredWidth(DialogWidth width) const override;
   bool ShouldShowWindowIcon() const override;
+  const views::TypographyProvider& GetTypographyProvider() const override;
 
  private:
+  const HarmonyTypographyProvider typography_provider_;
+
   DISALLOW_COPY_AND_ASSIGN(HarmonyLayoutDelegate);
 };
 
diff --git a/chrome/browser/ui/views/harmony/harmony_typography_provider.cc b/chrome/browser/ui/views/harmony/harmony_typography_provider.cc
new file mode 100644
index 0000000..21caf0c
--- /dev/null
+++ b/chrome/browser/ui/views/harmony/harmony_typography_provider.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 "chrome/browser/ui/views/harmony/harmony_typography_provider.h"
+
+#include "chrome/browser/ui/views/harmony/chrome_typography.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/platform_font.h"
+
+const gfx::FontList& HarmonyTypographyProvider::GetFont(int text_context,
+                                                        int text_style) const {
+  // "Target" font size constants from the Harmony spec.
+  constexpr int kHeadlineSize = 20;
+  constexpr int kTitleSize = 15;
+  constexpr int kBodyTextLargeSize = 13;
+  constexpr int kDefaultSize = 12;
+
+#if defined(OS_WIN)
+  constexpr gfx::Font::Weight kButtonFontWeight = gfx::Font::Weight::BOLD;
+#else
+  constexpr gfx::Font::Weight kButtonFontWeight = gfx::Font::Weight::MEDIUM;
+#endif
+
+  int size_delta = kDefaultSize - gfx::PlatformFont::kDefaultBaseFontSize;
+  gfx::Font::Weight font_weight = gfx::Font::Weight::NORMAL;
+  switch (text_context) {
+    case CONTEXT_HEADLINE:
+      size_delta = kHeadlineSize - gfx::PlatformFont::kDefaultBaseFontSize;
+      break;
+    case views::style::CONTEXT_DIALOG_TITLE:
+      size_delta = kTitleSize - gfx::PlatformFont::kDefaultBaseFontSize;
+      break;
+    case CONTEXT_BODY_TEXT_LARGE:
+      size_delta = kBodyTextLargeSize - gfx::PlatformFont::kDefaultBaseFontSize;
+      break;
+    case views::style::CONTEXT_BUTTON:
+      font_weight = kButtonFontWeight;
+      break;
+    default:
+      break;
+  }
+
+  // Ignore |text_style| since it only affects color in the Harmony spec.
+  return ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta(
+      size_delta, gfx::Font::NORMAL, font_weight);
+}
+
+SkColor HarmonyTypographyProvider::GetColor(int text_context,
+                                            int text_style) const {
+  // TODO(tapted): Look up colors from the spec.
+  return SK_ColorBLACK;
+}
+
+int HarmonyTypographyProvider::GetLineHeight(int text_context,
+                                             int text_style) const {
+  // "Target" line height constants from the Harmony spec. A default OS
+  // configuration should use these heights. However, if the user overrides OS
+  // defaults, then GetLineHeight() should return the height that would add the
+  // same extra space between lines as the default configuration would have.
+  constexpr int kHeadlineHeight = 32;
+  constexpr int kTitleHeight = 22;
+  constexpr int kBodyHeight = 20;  // For both large and small.
+
+  // Button text should always use the minimum line height for a font to avoid
+  // unnecessarily influencing the height of a button.
+  constexpr int kButtonAbsoluteHeight = 0;
+
+// The platform-specific heights (i.e. gfx::Font::GetHeight()) that result when
+// asking for the target size constants in HarmonyTypographyProvider::GetFont()
+// in a default OS configuration.
+// TODO(tapted): Update these with constants specific to an OS point version.
+#if defined(OS_MACOSX)
+  constexpr int kHeadlinePlatformHeight = 25;
+  constexpr int kTitlePlatformHeight = 19;
+  constexpr int kBodyTextLargePlatformHeight = 16;
+  constexpr int kBodyTextSmallPlatformHeight = 15;
+#elif defined(OS_WIN)
+  constexpr int kHeadlinePlatformHeight = 28;
+  constexpr int kTitlePlatformHeight = 20;
+  constexpr int kBodyTextLargePlatformHeight = 17;
+  constexpr int kBodyTextSmallPlatformHeight = 15;
+#else
+  constexpr int kHeadlinePlatformHeight = 24;
+  constexpr int kTitlePlatformHeight = 18;
+  constexpr int kBodyTextLargePlatformHeight = 17;
+  constexpr int kBodyTextSmallPlatformHeight = 15;
+#endif
+
+  // The style of the system font used to determine line heights.
+  constexpr int kTemplateStyle = views::style::STYLE_PRIMARY;
+
+  // TODO(tapted): These statics should be cleared out when something invokes
+  // ResourceBundle::ReloadFonts(). Currently that only happens on ChromeOS.
+  // See http://crbug.com/708943.
+  static const int headline_height =
+      GetFont(CONTEXT_HEADLINE, kTemplateStyle).GetHeight() -
+      kHeadlinePlatformHeight + kHeadlineHeight;
+  static const int title_height =
+      GetFont(views::style::CONTEXT_DIALOG_TITLE, kTemplateStyle).GetHeight() -
+      kTitlePlatformHeight + kTitleHeight;
+  static const int body_large_height =
+      GetFont(CONTEXT_BODY_TEXT_LARGE, kTemplateStyle).GetHeight() -
+      kBodyTextLargePlatformHeight + kBodyHeight;
+  static const int default_height =
+      GetFont(CONTEXT_BODY_TEXT_SMALL, kTemplateStyle).GetHeight() -
+      kBodyTextSmallPlatformHeight + kBodyHeight;
+
+  switch (text_context) {
+    case CONTEXT_HEADLINE:
+      return headline_height;
+    case views::style::CONTEXT_DIALOG_TITLE:
+      return title_height;
+    case CONTEXT_BODY_TEXT_LARGE:
+      return body_large_height;
+    case views::style::CONTEXT_BUTTON:
+      return kButtonAbsoluteHeight;
+    default:
+      return default_height;
+  }
+}
diff --git a/chrome/browser/ui/views/harmony/harmony_typography_provider.h b/chrome/browser/ui/views/harmony/harmony_typography_provider.h
new file mode 100644
index 0000000..7885f2ce
--- /dev/null
+++ b/chrome/browser/ui/views/harmony/harmony_typography_provider.h
@@ -0,0 +1,25 @@
+// 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_VIEWS_HARMONY_HARMONY_TYPOGRAPHY_PROVIDER_H_
+#define CHROME_BROWSER_UI_VIEWS_HARMONY_HARMONY_TYPOGRAPHY_PROVIDER_H_
+
+#include "base/macros.h"
+#include "ui/views/style/typography_provider.h"
+
+// TypographyProvider implementing the Harmony spec.
+class HarmonyTypographyProvider : public views::TypographyProvider {
+ public:
+  HarmonyTypographyProvider() = default;
+
+  // TypographyProvider:
+  const gfx::FontList& GetFont(int text_context, int text_style) const override;
+  SkColor GetColor(int context, int style) const override;
+  int GetLineHeight(int context, int style) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HarmonyTypographyProvider);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_HARMONY_HARMONY_TYPOGRAPHY_PROVIDER_H_
diff --git a/chrome/browser/ui/views/harmony/layout_delegate_unittest.cc b/chrome/browser/ui/views/harmony/layout_delegate_unittest.cc
index 89306aa..a265ae7d 100644
--- a/chrome/browser/ui/views/harmony/layout_delegate_unittest.cc
+++ b/chrome/browser/ui/views/harmony/layout_delegate_unittest.cc
@@ -7,6 +7,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/default_style.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/gfx/font_list.h"
 #include "ui/views/style/typography.h"
 #include "ui/views/style/typography_provider.h"
@@ -229,3 +230,42 @@
             GetFont(CONTEXT_DEPRECATED_SMALL, kStyle).GetFontSize());
 #endif
 }
+
+// Ensure that line height can be overridden by Chrome's TypographyProvider for
+// for the standard set of styles. This varies by platform and test machine
+// configuration. Generally, for a particular platform configuration, there
+// should be a consistent increase in line height when compared to the height of
+// a given font.
+TEST(LayoutDelegateTest, TypographyLineHeight) {
+  constexpr int kStyle = views::style::STYLE_PRIMARY;
+
+  // Only MD overrides the default line spacing.
+  ui::test::MaterialDesignControllerTestAPI md_test_api(
+      ui::MaterialDesignController::MATERIAL_NORMAL);
+  md_test_api.SetSecondaryUiMaterial(true);
+
+  ChromeViewsDelegate views_delegate;
+
+  constexpr struct {
+    int context;
+    int min;
+    int max;
+  } kExpectedIncreases[] = {{CONTEXT_HEADLINE, 4, 8},
+                            {views::style::CONTEXT_DIALOG_TITLE, 2, 4},
+                            {CONTEXT_BODY_TEXT_LARGE, 3, 4},
+                            {CONTEXT_BODY_TEXT_SMALL, 5, 5}};
+
+  for (size_t i = 0; i < arraysize(kExpectedIncreases); ++i) {
+    SCOPED_TRACE(testing::Message() << "Testing index: " << i);
+    const auto& increase = kExpectedIncreases[i];
+    const gfx::FontList& font = views::style::GetFont(increase.context, kStyle);
+    int line_spacing = views::style::GetLineHeight(increase.context, kStyle);
+    EXPECT_GE(increase.max, line_spacing - font.GetHeight());
+    EXPECT_LE(increase.min, line_spacing - font.GetHeight());
+  }
+
+  // Buttons should specify zero line height (i.e. use the font's height) so
+  // buttons have flexibility to configure their own spacing.
+  EXPECT_EQ(0,
+            views::style::GetLineHeight(views::style::CONTEXT_BUTTON, kStyle));
+}
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 8a8ae03..bc71cdf 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -128,15 +128,15 @@
               gfx::NORMAL_BASELINE};
     case SuggestionAnswer::ANSWER_TEXT_MEDIUM:
       return {ui::ResourceBundle::BaseFont,
-              {NativeTheme::kColorId_ResultsTableNormalText,
-               NativeTheme::kColorId_ResultsTableHoveredText,
-               NativeTheme::kColorId_ResultsTableSelectedText},
+              {NativeTheme::kColorId_ResultsTableNormalDimmedText,
+               NativeTheme::kColorId_ResultsTableHoveredDimmedText,
+               NativeTheme::kColorId_ResultsTableSelectedDimmedText},
               gfx::NORMAL_BASELINE};
     case SuggestionAnswer::ANSWER_TEXT_LARGE:
       return {ui::ResourceBundle::LargeFont,
-              {NativeTheme::kColorId_ResultsTableNormalText,
-               NativeTheme::kColorId_ResultsTableHoveredText,
-               NativeTheme::kColorId_ResultsTableSelectedText},
+              {NativeTheme::kColorId_ResultsTableNormalDimmedText,
+               NativeTheme::kColorId_ResultsTableHoveredDimmedText,
+               NativeTheme::kColorId_ResultsTableSelectedDimmedText},
               gfx::NORMAL_BASELINE};
     case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_SMALL:
       return {ui::ResourceBundle::LargeFont,
diff --git a/chrome/browser/ui/views/srt_prompt_dialog.cc b/chrome/browser/ui/views/srt_prompt_dialog.cc
new file mode 100644
index 0000000..1c33b70
--- /dev/null
+++ b/chrome/browser/ui/views/srt_prompt_dialog.cc
@@ -0,0 +1,300 @@
+// 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/srt_prompt_dialog.h"
+
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/safe_browsing/srt_prompt_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/chrome_web_modal_dialog_manager_delegate.h"
+#include "components/constrained_window/constrained_window_views.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/events/event.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/gfx/text_constants.h"
+#include "ui/native_theme/native_theme.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/scroll_view.h"
+#include "ui/views/controls/separator.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
+#include "ui/views/widget/widget.h"
+
+namespace chrome {
+
+void ShowSRTPrompt(Browser* browser,
+                   safe_browsing::SRTPromptController* controller) {
+  SRTPromptDialog* dialog = new SRTPromptDialog(controller);
+  dialog->Show(browser);
+}
+
+}  // namespace chrome
+
+namespace {
+
+using LabelInfo = safe_browsing::SRTPromptController::LabelInfo;
+
+constexpr int kDialogWidth = 448;
+constexpr int kDetailsSectionMaxHeight = 150;
+constexpr int kBulletColumnWidth = 10;
+// Constants used for the layout of the label views.
+constexpr int kMainColumSetId = 0;
+constexpr int kBulletColumnSetId = 1;
+
+// Returns a view containing |item| with insets defined by |top|, |left|,
+// |bottom|, and |right|.
+views::View* CreateViewWithInsets(views::View* item,
+                                  int top,
+                                  int left,
+                                  int bottom,
+                                  int right) {
+  views::View* view = new views::View();
+  view->SetLayoutManager(new views::FillLayout());
+  view->SetBorder(views::CreateEmptyBorder(top, left, bottom, right));
+  view->AddChildView(item);
+  return view;
+}
+
+// Helper function used by |CreateLabelView()| below that adds |labels| to
+// |label_view|.
+void AddLabelsToLabelView(views::View* label_view,
+                          views::GridLayout* layout,
+                          const std::vector<LabelInfo>& labels) {
+  static constexpr base::char16 kBulletPoint[] = {0x2022, 0};
+
+  bool first_label = true;
+  bool last_label_was_bullet = false;
+  for (const LabelInfo& label_info : labels) {
+    const bool is_bullet = label_info.type == LabelInfo::BULLET_ITEM;
+    views::Label* label = new views::Label(label_info.text);
+    label->SetMultiLine(true);
+    label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+
+    // Do not add a padding row if
+    // - this is the first label being added, or
+    // - a bullet item is being added and the last label was also a bullet item.
+    bool skip_padding = first_label || (is_bullet && last_label_was_bullet);
+    if (!skip_padding)
+      layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
+    layout->StartRow(0, is_bullet ? kBulletColumnSetId : kMainColumSetId);
+    if (is_bullet) {
+      views::Label* bullet = new views::Label(base::string16(kBulletPoint));
+      layout->AddView(bullet);
+    }
+    layout->AddView(label);
+
+    last_label_was_bullet = is_bullet;
+    first_label = false;
+  }
+}
+
+// Creates a view that displays two types of labels: multiline labels
+// representing whole paragraphs or indented labels that are start with a bullet
+// point.
+//
+// A vertical padding of size |top_vertical_space| is added before the labels.
+views::View* CreateLabelView(int top_vertical_space,
+                             const std::vector<LabelInfo>& labels) {
+  views::View* label_view = new views::View();
+  views::GridLayout* layout = new views::GridLayout(label_view);
+  layout->SetInsets(0, views::kButtonHEdgeMarginNew, 0,
+                    views::kButtonHEdgeMarginNew);
+
+  label_view->SetLayoutManager(layout);
+
+  views::ColumnSet* main_column_set = layout->AddColumnSet(kMainColumSetId);
+  main_column_set->AddColumn(views::GridLayout::FILL,
+                             views::GridLayout::LEADING,
+                             /*resize_percent=*/1, views::GridLayout::USE_PREF,
+                             /*fixed_width=*/0,
+                             /*min_width=*/0);
+
+  views::ColumnSet* bullet_column_set_ =
+      layout->AddColumnSet(kBulletColumnSetId);
+  bullet_column_set_->AddPaddingColumn(
+      /*resize_percent=*/0, views::kUnrelatedControlLargeHorizontalSpacing);
+  bullet_column_set_->AddColumn(
+      views::GridLayout::FILL, views::GridLayout::LEADING,
+      /*resize_percent=*/0, views::GridLayout::USE_PREF,
+      /*fixed_width=*/0,
+      /*min_width=*/0);
+  bullet_column_set_->AddPaddingColumn(/*resize_percent=*/0,
+                                       kBulletColumnWidth);
+  bullet_column_set_->AddColumn(
+      views::GridLayout::FILL, views::GridLayout::LEADING,
+      /*resize_percent=*/1, views::GridLayout::USE_PREF,
+      /*fixed_width=*/0,
+      /*min_width=*/0);
+
+  if (top_vertical_space > 0)
+    layout->AddPaddingRow(/*vertical_resize=*/0, top_vertical_space);
+
+  AddLabelsToLabelView(label_view, layout, labels);
+
+  layout->AddPaddingRow(/*vertical_resize=*/0,
+                        views::kUnrelatedControlLargeHorizontalSpacing);
+  return label_view;
+}
+
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// SRTPromptDialog
+
+SRTPromptDialog::SRTPromptDialog(safe_browsing::SRTPromptController* controller)
+    : browser_(nullptr),
+      controller_(controller),
+      details_view_(new views::View()),
+      details_button_(nullptr) {
+  DCHECK(controller_);
+
+  SetLayoutManager(new views::BoxLayout(
+      /*orientation=*/views::BoxLayout::kVertical,
+      /*inside_border_horizontal_spacing=*/0,
+      /*inside_border_vertical_spacing=*/views::kPanelVertMargin,
+      /*between_child_spacing=*/0));
+
+  AddChildView(CreateLabelView(0, controller_->GetMainText()));
+  AddChildView(new views::Separator());
+
+  // The details section starts off empty and will be populated when the user
+  // clicks the button to expand the details section. Its child views are
+  // removed when the section is closed.
+  details_view_->SetLayoutManager(new views::FillLayout());
+  details_view_->SetVisible(false);
+  AddChildView(details_view_);
+
+  details_button_ =
+      new views::LabelButton(this, controller_->GetShowDetailsLabel());
+  details_button_->SetEnabledTextColors(GetDetailsButtonColor());
+  UpdateDetailsButton();
+  AddChildView(CreateViewWithInsets(
+      details_button_, views::kPanelVertMargin, views::kButtonHEdgeMarginNew,
+      views::kPanelVertMargin, views::kButtonHEdgeMarginNew));
+  AddChildView(new views::Separator());
+}
+
+SRTPromptDialog::~SRTPromptDialog() {
+  // Make sure the controller is correctly notified in case the dialog widget is
+  // closed by some other means than the dialog buttons.
+  if (controller_)
+    controller_->Cancel();
+}
+
+void SRTPromptDialog::Show(Browser* browser) {
+  DCHECK(browser);
+  DCHECK(!browser_);
+
+  browser_ = browser;
+  constrained_window::CreateBrowserModalDialogViews(
+      this, browser_->window()->GetNativeWindow())
+      ->Show();
+  controller_->DialogShown();
+}
+
+// DialogModel overrides.
+
+bool SRTPromptDialog::ShouldDefaultButtonBeBlue() const {
+  return true;
+}
+
+// WidgetDelegate overrides.
+
+ui::ModalType SRTPromptDialog::GetModalType() const {
+  return ui::MODAL_TYPE_WINDOW;
+}
+
+base::string16 SRTPromptDialog::GetWindowTitle() const {
+  return controller_->GetWindowTitle();
+}
+
+// DialogDelegate overrides.
+
+base::string16 SRTPromptDialog::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  DCHECK(button == ui::DIALOG_BUTTON_OK || button == ui::DIALOG_BUTTON_CANCEL);
+
+  if (button == ui::DIALOG_BUTTON_OK)
+    return controller_->GetAcceptButtonLabel();
+  return DialogDelegate::GetDialogButtonLabel(button);
+}
+
+bool SRTPromptDialog::Accept() {
+  if (controller_) {
+    controller_->Accept();
+    controller_ = nullptr;
+  }
+  return true;
+}
+
+bool SRTPromptDialog::Cancel() {
+  if (controller_) {
+    controller_->Cancel();
+    controller_ = nullptr;
+  }
+  return true;
+}
+
+// View overrides.
+
+gfx::Size SRTPromptDialog::GetPreferredSize() const {
+  return gfx::Size(kDialogWidth, GetHeightForWidth(kDialogWidth));
+}
+
+// views::ButtonListener overrides.
+
+void SRTPromptDialog::ButtonPressed(views::Button* sender,
+                                    const ui::Event& event) {
+  DCHECK_EQ(sender, details_button_);
+  DCHECK(browser_);
+
+  details_view_->SetVisible(!details_view_->visible());
+  if (details_view_->visible()) {
+    // Populate the details view adding the main message view inside a scroll
+    // view.
+    views::View* label_view =
+        CreateLabelView(views::kUnrelatedControlLargeHorizontalSpacing,
+                        controller_->GetDetailsText());
+    views::ScrollView* scroll_view = new views::ScrollView();
+    scroll_view->ClipHeightTo(/*min_height=*/0, kDetailsSectionMaxHeight);
+    scroll_view->SetContents(label_view);
+    details_view_->AddChildView(scroll_view);
+  } else {
+    details_view_->RemoveAllChildViews(/*delete_children=*/true);
+  }
+
+  UpdateDetailsButton();
+
+  ChromeWebModalDialogManagerDelegate* manager = browser_;
+  constrained_window::UpdateWidgetModalDialogPosition(
+      GetWidget(), manager->GetWebContentsModalDialogHost());
+}
+
+SkColor SRTPromptDialog::GetDetailsButtonColor() {
+  return GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_LinkEnabled);
+}
+
+void SRTPromptDialog::UpdateDetailsButton() {
+  details_button_->SetText(details_view_->visible()
+                               ? controller_->GetHideDetailsLabel()
+                               : controller_->GetShowDetailsLabel());
+  details_button_->SetImage(
+      views::Button::STATE_NORMAL,
+      details_view_->visible()
+          ? gfx::CreateVectorIcon(kCaretUpIcon, GetDetailsButtonColor())
+          : gfx::CreateVectorIcon(kCaretDownIcon, GetDetailsButtonColor()));
+}
diff --git a/chrome/browser/ui/views/srt_prompt_dialog.h b/chrome/browser/ui/views/srt_prompt_dialog.h
new file mode 100644
index 0000000..9e2f4bb
--- /dev/null
+++ b/chrome/browser/ui/views/srt_prompt_dialog.h
@@ -0,0 +1,80 @@
+// 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_VIEWS_SRT_PROMPT_DIALOG_H_
+#define CHROME_BROWSER_UI_VIEWS_SRT_PROMPT_DIALOG_H_
+
+#include "base/macros.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/window/dialog_delegate.h"
+
+class Browser;
+
+namespace safe_browsing {
+class SRTPromptController;
+}
+
+// A modal dialog asking the user if they want to run the Chrome Cleanup
+// tool. The dialog will have the following sections:
+//
+// 1. Main section with general information about unwanted software that has
+// been found on the user's system.
+// 2. Expandable details section with more details about unwanted software that
+// will be removed and Chrome settings that will be reset.
+// 3. Checkbox asking for permissions to upload logs (not yet implemented).
+//
+// The strings and icons used in the dialog are provided by a
+// |SRTPromptController| object, which will also receive information about how
+// the user interacts with the dialog. The controller object owns itself and
+// will delete itself once it has received information about the user's
+// interaction with the dialog. See the |SRTPromptController| class's
+// description for more details.
+class SRTPromptDialog : public views::DialogDelegateView,
+                        public views::ButtonListener {
+ public:
+  // The |controller| object manages its own lifetime and is not owned by
+  // |SRTPromptDialog|. See the description of the |SRTPromptController| class
+  // for details.
+  explicit SRTPromptDialog(safe_browsing::SRTPromptController* controller);
+  ~SRTPromptDialog() override;
+
+  void Show(Browser* browser);
+
+  // ui::DialogModel overrides.
+  bool ShouldDefaultButtonBeBlue() const override;
+
+  // views::WidgetDelegate overrides.
+  ui::ModalType GetModalType() const override;
+  base::string16 GetWindowTitle() const override;
+
+  // views::DialogDelegate overrides.
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
+  bool Accept() override;
+  bool Cancel() override;
+
+  // views::View overrides.
+  gfx::Size GetPreferredSize() const override;
+
+  // views::ButtonListener overrides.
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+ private:
+  SkColor GetDetailsButtonColor();
+  void UpdateDetailsButton();
+
+  Browser* browser_;
+  // The pointer will be set to nullptr once the controller has been notified of
+  // user interaction since the controller can delete itself after that point.
+  safe_browsing::SRTPromptController* controller_;
+
+  views::View* details_view_;
+  views::LabelButton* details_button_;
+
+  DISALLOW_COPY_AND_ASSIGN(SRTPromptDialog);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_SRT_PROMPT_DIALOG_H_
diff --git a/chrome/browser/ui/views/srt_prompt_dialog_browsertest.cc b/chrome/browser/ui/views/srt_prompt_dialog_browsertest.cc
new file mode 100644
index 0000000..ab0aca24
--- /dev/null
+++ b/chrome/browser/ui/views/srt_prompt_dialog_browsertest.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 "chrome/browser/ui/views/srt_prompt_dialog.h"
+
+#include "base/macros.h"
+#include "chrome/browser/safe_browsing/srt_prompt_controller.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/test/test_browser_dialog.h"
+#include "content/public/test/browser_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SRTPromptDialogTest : public DialogBrowserTest {
+ public:
+  SRTPromptDialogTest() {}
+
+  void ShowDialog(const std::string& name) override {
+    chrome::ShowSRTPrompt(browser(), new safe_browsing::SRTPromptController());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SRTPromptDialogTest);
+};
+
+IN_PROC_BROWSER_TEST_F(SRTPromptDialogTest, InvokeDialog_default) {
+  RunDialog();
+}
+
+}  // namespace
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 409e09f7..180c2fa 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
@@ -361,6 +361,7 @@
       {"bluetoothDeviceListPaired", IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_PAIRED},
       {"bluetoothDeviceListUnpaired",
        IDS_SETTINGS_BLUETOOTH_DEVICE_LIST_UNPAIRED},
+      {"bluetoothConnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT},
       {"bluetoothDisconnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISCONNECT},
       {"bluetoothDismiss", IDS_OPTIONS_SETTINGS_BLUETOOTH_DISMISS_ERROR},
       {"bluetoothToggleA11yLabel",
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc b/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc
index e643dd6..df79adbc 100644
--- a/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc
+++ b/chrome/browser/ui/webui/signin/sync_confirmation_handler.cc
@@ -56,9 +56,6 @@
                  base::Unretained(this)));
   web_ui()->RegisterMessageCallback("undo",
       base::Bind(&SyncConfirmationHandler::HandleUndo, base::Unretained(this)));
-  web_ui()->RegisterMessageCallback("goToSettings",
-      base::Bind(&SyncConfirmationHandler::HandleGoToSettings,
-                 base::Unretained(this)));
   web_ui()->RegisterMessageCallback("initializedWithSize",
       base::Bind(&SyncConfirmationHandler::HandleInitializedWithSize,
                  base::Unretained(this)));
@@ -66,12 +63,11 @@
 
 void SyncConfirmationHandler::HandleConfirm(const base::ListValue* args) {
   did_user_explicitly_interact = true;
-  CloseModalSigninWindow(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS);
-}
-
-void SyncConfirmationHandler::HandleGoToSettings(const base::ListValue* args) {
-  did_user_explicitly_interact = true;
-  CloseModalSigninWindow(LoginUIService::CONFIGURE_SYNC_FIRST);
+  bool configure_sync_first = false;
+  CHECK(args->GetBoolean(0, &configure_sync_first));
+  CloseModalSigninWindow(configure_sync_first
+                             ? LoginUIService::CONFIGURE_SYNC_FIRST
+                             : LoginUIService::SYNC_WITH_DEFAULT_SETTINGS);
 }
 
 void SyncConfirmationHandler::HandleUndo(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_handler.h b/chrome/browser/ui/webui/signin/sync_confirmation_handler.h
index 8953681e..7de6334 100644
--- a/chrome/browser/ui/webui/signin/sync_confirmation_handler.h
+++ b/chrome/browser/ui/webui/signin/sync_confirmation_handler.h
@@ -36,7 +36,8 @@
  protected:
   // Handles "confirm" message from the page. No arguments.
   // This message is sent when the user confirms that they want complete sign in
-  // with default sync settings.
+  // with default sync settings. Passed a single boolean argument: whether to
+  // configure settings before signing in.
   virtual void HandleConfirm(const base::ListValue* args);
 
   // Handles "undo" message from the page. No arguments.
@@ -44,12 +45,6 @@
   // dialog, which aborts signin and prevents sync from starting.
   virtual void HandleUndo(const base::ListValue* args);
 
-  // Handles "goToSettings" message from the page. No arguments.
-  // This message is sent when the user clicks on the "Settings" link in the
-  // sync confirmation dialog, which completes sign in but takes the user to the
-  // sync settings page for configuration before starting sync.
-  virtual void HandleGoToSettings(const base::ListValue* args);
-
   // Handles the web ui message sent when the html content is done being laid
   // out and it's time to resize the native view hosting it to fit. |args| is
   // a single integer value for the height the native view should resize to.
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_handler_unittest.cc b/chrome/browser/ui/webui/signin/sync_confirmation_handler_unittest.cc
index cc71936..c1373eb 100644
--- a/chrome/browser/ui/webui/signin/sync_confirmation_handler_unittest.cc
+++ b/chrome/browser/ui/webui/signin/sync_confirmation_handler_unittest.cc
@@ -43,14 +43,55 @@
   using SyncConfirmationHandler::HandleConfirm;
   using SyncConfirmationHandler::HandleUndo;
   using SyncConfirmationHandler::HandleInitializedWithSize;
-  using SyncConfirmationHandler::HandleGoToSettings;
   using SyncConfirmationHandler::SetUserImageURL;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestingSyncConfirmationHandler);
+};
+
+class TestingOneClickSigninSyncStarter : public OneClickSigninSyncStarter {
+ public:
+  TestingOneClickSigninSyncStarter(Profile* profile,
+                                   Browser* browser,
+                                   const std::string& gaia_id,
+                                   const std::string& email,
+                                   const std::string& password,
+                                   const std::string& refresh_token,
+                                   ProfileMode profile_mode,
+                                   StartSyncMode start_mode,
+                                   content::WebContents* web_contents,
+                                   ConfirmationRequired display_confirmation,
+                                   const GURL& current_url,
+                                   const GURL& continue_url,
+                                   Callback callback)
+      : OneClickSigninSyncStarter(profile,
+                                  browser,
+                                  gaia_id,
+                                  email,
+                                  password,
+                                  refresh_token,
+                                  profile_mode,
+                                  start_mode,
+                                  web_contents,
+                                  display_confirmation,
+                                  current_url,
+                                  continue_url,
+                                  callback) {}
+
+ protected:
+  void ShowSyncSetupSettingsSubpage() override {
+    // Intentionally don't open a tab to settings.
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestingOneClickSigninSyncStarter);
 };
 
 class SyncConfirmationHandlerTest : public BrowserWithTestWindowTest {
  public:
-  SyncConfirmationHandlerTest() : did_user_explicitly_interact(false),
-                                  web_ui_(new content::TestWebUI) {}
+  SyncConfirmationHandlerTest()
+      : did_user_explicitly_interact(false), web_ui_(new content::TestWebUI) {}
+
   void SetUp() override {
     BrowserWithTestWindowTest::SetUp();
     chrome::NewTab(browser());
@@ -65,7 +106,7 @@
 
     // This dialog assumes the signin flow was completed, which kicks off the
     // SigninManager.
-    new OneClickSigninSyncStarter(
+    new TestingOneClickSigninSyncStarter(
         profile(), browser(), "gaia", "foo@example.com", "password",
         "refresh_token", OneClickSigninSyncStarter::CURRENT_PROFILE,
         OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS, nullptr,
@@ -78,11 +119,10 @@
     web_ui_.reset();
     BrowserWithTestWindowTest::TearDown();
 
-    if (did_user_explicitly_interact) {
+    if (did_user_explicitly_interact)
       EXPECT_EQ(0, user_action_tester()->GetActionCount("Signin_Abort_Signin"));
-    } else {
+    else
       EXPECT_EQ(1, user_action_tester()->GetActionCount("Signin_Abort_Signin"));
-    }
   }
 
   TestingSyncConfirmationHandler* handler() {
@@ -125,14 +165,16 @@
     return builder.Build().release();
   }
 
-protected:
- bool did_user_explicitly_interact;
+ protected:
+  bool did_user_explicitly_interact;
 
-private:
- std::unique_ptr<content::TestWebUI> web_ui_;
- std::unique_ptr<SyncConfirmationUI> sync_confirmation_ui_;
- TestingSyncConfirmationHandler* handler_;  // Not owned.
- base::UserActionTester user_action_tester_;
+ private:
+  std::unique_ptr<content::TestWebUI> web_ui_;
+  std::unique_ptr<SyncConfirmationUI> sync_confirmation_ui_;
+  TestingSyncConfirmationHandler* handler_;  // Not owned.
+  base::UserActionTester user_action_tester_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyncConfirmationHandlerTest);
 };
 
 TEST_F(SyncConfirmationHandlerTest, TestSetImageIfPrimaryAccountReady) {
@@ -276,7 +318,9 @@
   EXPECT_FALSE(sync()->IsFirstSetupComplete());
   EXPECT_TRUE(sync()->IsFirstSetupInProgress());
 
-  handler()->HandleConfirm(nullptr);
+  base::ListValue args;
+  args.AppendBoolean(false /* show advanced */);
+  handler()->HandleConfirm(&args);
   did_user_explicitly_interact = true;
 
   EXPECT_FALSE(sync()->IsFirstSetupInProgress());
@@ -289,3 +333,23 @@
   EXPECT_EQ(0, user_action_tester()->GetActionCount(
       "Signin_Signin_WithAdvancedSyncSettings"));
 }
+
+TEST_F(SyncConfirmationHandlerTest, TestHandleConfirmWithAdvancedSyncSettings) {
+  EXPECT_FALSE(sync()->IsFirstSetupComplete());
+  EXPECT_TRUE(sync()->IsFirstSetupInProgress());
+
+  base::ListValue args;
+  args.AppendBoolean(true /* show advanced */);
+  handler()->HandleConfirm(&args);
+  did_user_explicitly_interact = true;
+
+  EXPECT_FALSE(sync()->IsFirstSetupInProgress());
+  EXPECT_FALSE(sync()->IsFirstSetupComplete());
+  EXPECT_TRUE(
+      SigninManagerFactory::GetForProfile(profile())->IsAuthenticated());
+  EXPECT_EQ(0, user_action_tester()->GetActionCount("Signin_Undo_Signin"));
+  EXPECT_EQ(0, user_action_tester()->GetActionCount(
+                   "Signin_Signin_WithDefaultSyncSettings"));
+  EXPECT_EQ(1, user_action_tester()->GetActionCount(
+                   "Signin_Signin_WithAdvancedSyncSettings"));
+}
diff --git a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
index e4525b9..f0103cd1 100644
--- a/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
+++ b/chrome/browser/ui/webui/signin/sync_confirmation_ui.cc
@@ -38,8 +38,8 @@
       IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_TITLE);
   source->AddLocalizedString("syncConfirmationPersonalizeServicesBody",
       IDS_SYNC_CONFIRMATION_PERSONALIZE_SERVICES_BODY);
-  source->AddLocalizedString("syncConfirmationSyncSettingsLinkBody",
-      IDS_SYNC_CONFIRMATION_SYNC_SETTINGS_LINK_BODY);
+  source->AddLocalizedString("syncConfirmationSyncSettingsLabel",
+                             IDS_SYNC_CONFIRMATION_SYNC_SETTINGS_LABEL);
   source->AddLocalizedString("syncDisabledConfirmationDetails",
                              IDS_SYNC_DISABLED_CONFIRMATION_DETAILS);
 
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index de68108..2f51d297 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -196,13 +196,13 @@
   for (size_t i = 0; i < codecs.size(); ++i) {
     if (codecs[i] == kCdmSupportedCodecVp8)
       supported_codecs |= media::EME_CODEC_WEBM_VP8;
-    if (codecs[i] == kCdmSupportedCodecVp9)
+    if (codecs[i] == kCdmSupportedCodecVp9) {
       supported_codecs |= media::EME_CODEC_WEBM_VP9;
+      supported_codecs |= media::EME_CODEC_COMMON_VP9;
+    }
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
     if (codecs[i] == kCdmSupportedCodecAvc1)
       supported_codecs |= media::EME_CODEC_MP4_AVC1;
-    if (codecs[i] == kCdmSupportedCodecVp9)
-      supported_codecs |= media::EME_CODEC_MP4_VP9;
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
   }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 778daa9..8c25fec 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2592,6 +2592,7 @@
       sources += [
         "../browser/extensions/api/networking_private/networking_private_credentials_getter_browsertest.cc",
         "../browser/ui/views/settings_reset_prompt_dialog_browsertest.cc",
+        "../browser/ui/views/srt_prompt_dialog_browsertest.cc",
       ]
     }
     if (is_mac || is_win) {
diff --git a/chrome/test/data/extensions/platform_apps/app_icon/test.js b/chrome/test/data/extensions/platform_apps/app_icon/test.js
index afb3eb88..3b3887a 100644
--- a/chrome/test/data/extensions/platform_apps/app_icon/test.js
+++ b/chrome/test/data/extensions/platform_apps/app_icon/test.js
@@ -15,7 +15,16 @@
       chrome.app.window.create(
         'main.html', { type: "shell" },
         function (win) {
-          chrome.test.sendMessage("Completed");
+          // Create the shell window which is shown in shelf; it should use
+          // another custom app icon.
+          chrome.app.window.create(
+            'main.html', { id: "win_with_icon",
+                           type: "shell",
+                           icon: "icon48.png",
+                           showInShelf: true },
+            function (win) {
+              chrome.test.sendMessage("Completed");
+            });
         });
     });
 });
diff --git a/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/content_script.js b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/content_script.js
new file mode 100644
index 0000000..b5258cb
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/content_script.js
@@ -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.
+
+var embedder = null;
+
+function reportResult(result) {
+  var msg = ['fetch-' + result];
+  embedder.postMessage(JSON.stringify(msg), '*');
+}
+
+window.addEventListener('message', function(e) {
+  embedder = e.source;
+  var data = JSON.parse(e.data);
+  if (data[0] == 'start-fetch') {
+    fetch('http://127.0.0.1:' + location.port + '/extensions/xhr.txt')
+        .then((result) => result.text())
+        .then((text) => {
+          reportResult(
+              (text == 'File to request via XHR.\n') ? 'success' : 'failure');
+        })
+        .catch(err => {
+          reportResult('failure');
+        });
+  } else {
+    reportResult('unexpected-message');
+  }
+});
+
+window.console.log('Script has been successfully injected.');
diff --git a/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/embedder.html b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/embedder.html
new file mode 100644
index 0000000..5387cce
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/embedder.html
@@ -0,0 +1,11 @@
+<!--
+ * 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.
+-->
+<html>
+<body>
+  <div id="webview-tag-container"></div>
+  <script src="embedder.js"></script>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/embedder.js
new file mode 100644
index 0000000..6624e97d
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/embedder.js
@@ -0,0 +1,86 @@
+// 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.
+
+var embedder = {};
+embedder.test = {};
+embedder.baseGuestURL = '';
+embedder.guestURL = '';
+
+window.runTest = function(testName) {
+  if (!embedder.test.testList[testName]) {
+    console.log('Incorrect testName: ' + testName);
+    embedder.test.fail();
+    return;
+  }
+
+  // Run the test.
+  embedder.test.testList[testName]();
+};
+// window.* exported functions end.
+
+
+embedder.test.succeed = function() {
+  chrome.test.sendMessage('TEST_PASSED');
+};
+
+embedder.test.fail = function() {
+  chrome.test.sendMessage('TEST_FAILED');
+};
+
+embedder.setUp = function(config) {
+  embedder.baseGuestURL = 'http://localhost:' + config.testServer.port;
+  embedder.guestURL = embedder.baseGuestURL +
+      '/extensions/platform_apps/web_view/content_script_fetch/guest.html';
+};
+
+/** @private */
+embedder.setUpGuest_ = function() {
+  document.querySelector('#webview-tag-container').innerHTML =
+      '<webview style="width: 100px; height: 100px;"></webview>';
+  var webview = document.querySelector('webview');
+  if (!webview) {
+    console.log('No <webview> element created');
+    embedder.test.fail();
+  }
+  return webview;
+};
+
+// Tests begin.
+
+function testContentScriptFetch() {
+  var webview = embedder.setUpGuest_();
+  webview.addContentScripts([{
+      name: 'rule',
+      matches: ['http://localhost/*'],
+      js: { files: ['content_script.js'] },
+      run_at: 'document_start'}]);
+
+  webview.addEventListener('loadstop', function() {
+    var msg = ['start-fetch'];
+    webview.contentWindow.postMessage(JSON.stringify(msg), '*');
+  });
+
+  window.addEventListener('message', function(e) {
+    var data = JSON.parse(e.data);
+    if (data == 'fetch-success') {
+      embedder.test.succeed();
+      return;
+    }
+    console.log('Unexpected message: \'' + data[0]  + '\'');
+    embedder.test.fail();
+  });
+
+  webview.src = embedder.guestURL;
+}
+
+embedder.test.testList = {
+  testContentScriptFetch: testContentScriptFetch
+};
+
+onload = function() {
+  chrome.test.getConfig(function(config) {
+    embedder.setUp(config);
+    chrome.test.sendMessage('Launched');
+  });
+};
diff --git a/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/guest.html b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/guest.html
new file mode 100644
index 0000000..83fef98
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/guest.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<!--
+ * 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.
+-->
+<html>
+<head>
+  <title>A simple guest that does nothing.</title>
+</head>
+<body>
+</body>
+</html>
diff --git a/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/manifest.json b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/manifest.json
new file mode 100644
index 0000000..4e2d233
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "Platform App Test: <webview> content script fetch",
+  "description": "Loads a guest which does a fetch from a content script",
+  "version": "1",
+  "permissions": [
+    "webview"
+  ],
+  "app": {
+    "background": {
+      "scripts": ["test.js"]
+    }
+  }
+}
diff --git a/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/test.js b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/test.js
new file mode 100644
index 0000000..048d1b5c
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/web_view/content_script_fetch/test.js
@@ -0,0 +1,7 @@
+// 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.
+
+chrome.app.runtime.onLaunched.addListener(function() {
+  chrome.app.window.create('embedder.html', {}, function () {});
+});
diff --git a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
index 635bd09..d36f8e9 100644
--- a/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_action_menu_test.js
@@ -127,4 +127,30 @@
   test('close on Escape', function() {
     return testFocusAfterClosing('Escape');
   });
+
+  test('mouse movement focus options', function() {
+    function makeMouseoverEvent(node) {
+      var e = new MouseEvent('mouseover', {bubbles: true});
+      node.dispatchEvent(e);
+    }
+
+    menu.showAt(document.querySelector('#dots'));
+
+    // Moving mouse on option 1 should focus it.
+    assertNotEquals(items[0], menu.root.activeElement);
+    makeMouseoverEvent(items[0]);
+    assertEquals(items[0], menu.root.activeElement);
+
+    // Moving mouse on the menu (not on option) should focus the menu.
+    makeMouseoverEvent(menu);
+    assertNotEquals(items[0], menu.root.activeElement);
+    assertEquals(menu, document.activeElement);
+
+    // Mouse movements should override keyboard focus.
+    down();
+    down();
+    assertEquals(items[1], menu.root.activeElement);
+    makeMouseoverEvent(items[0]);
+    assertEquals(items[0], menu.root.activeElement);
+  });
 });
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 3ee7d8e..762a43ac 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -470,6 +470,7 @@
 
 copy("dbus_service_files") {
   sources = [
+    "dbus/services/org.chromium.KioskAppService.conf",
     "dbus/services/org.chromium.LibCrosService.conf",
     "dbus/services/org.chromium.LivenessService.conf",
     "dbus/services/org.chromium.NetworkProxyService.conf",
diff --git a/chromeos/components/tether/BUILD.gn b/chromeos/components/tether/BUILD.gn
index 18502af7..7474fa2 100644
--- a/chromeos/components/tether/BUILD.gn
+++ b/chromeos/components/tether/BUILD.gn
@@ -22,6 +22,8 @@
     "ble_scanner.h",
     "connect_tethering_operation.cc",
     "connect_tethering_operation.h",
+    "device_id_tether_network_guid_map.cc",
+    "device_id_tether_network_guid_map.h",
     "host_scan_device_prioritizer.cc",
     "host_scan_device_prioritizer.h",
     "host_scan_scheduler.cc",
@@ -45,6 +47,8 @@
     "notification_presenter.h",
     "pref_names.cc",
     "pref_names.h",
+    "tether_connector.cc",
+    "tether_connector.h",
     "tether_host_fetcher.cc",
     "tether_host_fetcher.h",
     "wifi_hotspot_connector.cc",
@@ -123,6 +127,7 @@
     "local_device_data_provider_unittest.cc",
     "message_transfer_operation_unittest.cc",
     "message_wrapper_unittest.cc",
+    "tether_connector_unittest.cc",
     "tether_host_fetcher_unittest.cc",
     "wifi_hotspot_connector_unittest.cc",
   ]
diff --git a/chromeos/components/tether/ble_connection_manager.cc b/chromeos/components/tether/ble_connection_manager.cc
index b486079..221449b 100644
--- a/chromeos/components/tether/ble_connection_manager.cc
+++ b/chromeos/components/tether/ble_connection_manager.cc
@@ -6,6 +6,7 @@
 
 #include "chromeos/components/tether/ble_constants.h"
 #include "components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h"
+#include "components/cryptauth/cryptauth_service.h"
 #include "components/proximity_auth/logging/logging.h"
 #include "device/bluetooth/bluetooth_uuid.h"
 
@@ -101,6 +102,10 @@
   manager_->OnConnectionAttemptTimeout(remote_device_);
 }
 
+bool BleConnectionManager::ConnectionMetadata::HasSecureChannel() {
+  return secure_channel_ != nullptr;
+}
+
 void BleConnectionManager::ConnectionMetadata::SetSecureChannel(
     std::unique_ptr<cryptauth::SecureChannel> secure_channel) {
   DCHECK(!secure_channel_);
@@ -165,13 +170,13 @@
 }
 
 BleConnectionManager::BleConnectionManager(
-    std::unique_ptr<Delegate> delegate,
+    cryptauth::CryptAuthService* cryptauth_service,
     scoped_refptr<device::BluetoothAdapter> adapter,
     const LocalDeviceDataProvider* local_device_data_provider,
     const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher,
     cryptauth::BluetoothThrottler* bluetooth_throttler)
     : BleConnectionManager(
-          std::move(delegate),
+          cryptauth_service,
           adapter,
           // TODO(khorimoto): Inject |adapter| into |BleScanner|.
           base::MakeUnique<BleScanner>(local_device_data_provider),
@@ -183,14 +188,14 @@
           bluetooth_throttler) {}
 
 BleConnectionManager::BleConnectionManager(
-    std::unique_ptr<Delegate> delegate,
+    cryptauth::CryptAuthService* cryptauth_service,
     scoped_refptr<device::BluetoothAdapter> adapter,
     std::unique_ptr<BleScanner> ble_scanner,
     std::unique_ptr<BleAdvertiser> ble_advertiser,
     std::unique_ptr<BleAdvertisementDeviceQueue> device_queue,
     std::unique_ptr<TimerFactory> timer_factory,
     cryptauth::BluetoothThrottler* bluetooth_throttler)
-    : delegate_(std::move(delegate)),
+    : cryptauth_service_(cryptauth_service),
       adapter_(adapter),
       ble_scanner_(std::move(ble_scanner)),
       ble_advertiser_(std::move(ble_advertiser)),
@@ -314,7 +319,17 @@
     // ignore it.
     PA_LOG(WARNING) << "Received an advertisement from a device which is not "
                     << "registered. Bluetooth address: " << device_address
-                    << ", Remote Device ID: " << remote_device.GetDeviceId();
+                    << ", Remote Device ID: "
+                    << remote_device.GetTruncatedDeviceIdForLogs();
+    return;
+  }
+
+  if (connection_metadata->HasSecureChannel()) {
+    PA_LOG(WARNING) << "Received another advertisement from a registered "
+                    << "device which is already being actively communicated "
+                    << "with. Bluetooth address: " << device_address
+                    << ", Remote Device ID: "
+                    << remote_device.GetTruncatedDeviceIdForLogs();
     return;
   }
 
@@ -329,8 +344,8 @@
                       device::BluetoothUUID(std::string(kGattServerUuid)),
                       bluetooth_throttler_);
   std::unique_ptr<cryptauth::SecureChannel> secure_channel =
-      cryptauth::SecureChannel::Factory::NewInstance(
-          std::move(connection), delegate_->CreateSecureChannelDelegate());
+      cryptauth::SecureChannel::Factory::NewInstance(std::move(connection),
+                                                     cryptauth_service_);
   connection_metadata->SetSecureChannel(std::move(secure_channel));
 
   // Stop trying to connect to that device, since a connection already exists.
diff --git a/chromeos/components/tether/ble_connection_manager.h b/chromeos/components/tether/ble_connection_manager.h
index 96a01b88..a62057a 100644
--- a/chromeos/components/tether/ble_connection_manager.h
+++ b/chromeos/components/tether/ble_connection_manager.h
@@ -22,6 +22,7 @@
 
 namespace cryptauth {
 class BluetoothThrottler;
+class CryptAuthService;
 }  // namespace cryptauth
 
 namespace chromeos {
@@ -65,14 +66,8 @@
                                    const std::string& payload) = 0;
   };
 
-  class Delegate {
-   public:
-    virtual std::unique_ptr<cryptauth::SecureChannel::Delegate>
-    CreateSecureChannelDelegate() = 0;
-  };
-
   BleConnectionManager(
-      std::unique_ptr<Delegate> delegate,
+      cryptauth::CryptAuthService* cryptauth_service,
       scoped_refptr<device::BluetoothAdapter> adapter,
       const LocalDeviceDataProvider* local_device_data_provider,
       const cryptauth::RemoteBeaconSeedFetcher* remote_beacon_seed_fetcher,
@@ -147,6 +142,7 @@
     cryptauth::SecureChannel::Status GetStatus() const;
 
     void StartConnectionAttemptTimer(bool use_short_error_timeout);
+    bool HasSecureChannel();
     void SetSecureChannel(
         std::unique_ptr<cryptauth::SecureChannel> secure_channel);
     void SendMessage(const std::string& payload);
@@ -180,7 +176,7 @@
   };
 
   BleConnectionManager(
-      std::unique_ptr<Delegate> delegate,
+      cryptauth::CryptAuthService* cryptauth_service,
       scoped_refptr<device::BluetoothAdapter> adapter,
       std::unique_ptr<BleScanner> ble_scanner,
       std::unique_ptr<BleAdvertiser> ble_advertiser,
@@ -206,7 +202,7 @@
       const cryptauth::SecureChannel::Status& old_status,
       const cryptauth::SecureChannel::Status& new_status);
 
-  std::unique_ptr<Delegate> delegate_;
+  cryptauth::CryptAuthService* cryptauth_service_;
   scoped_refptr<device::BluetoothAdapter> adapter_;
   std::unique_ptr<BleScanner> ble_scanner_;
   std::unique_ptr<BleAdvertiser> ble_advertiser_;
diff --git a/chromeos/components/tether/ble_connection_manager_unittest.cc b/chromeos/components/tether/ble_connection_manager_unittest.cc
index 6ce9b41a..403eb2dc 100644
--- a/chromeos/components/tether/ble_connection_manager_unittest.cc
+++ b/chromeos/components/tether/ble_connection_manager_unittest.cc
@@ -12,6 +12,7 @@
 #include "components/cryptauth/bluetooth_throttler.h"
 #include "components/cryptauth/connection.h"
 #include "components/cryptauth/fake_connection.h"
+#include "components/cryptauth/fake_cryptauth_service.h"
 #include "components/cryptauth/fake_secure_channel.h"
 #include "components/cryptauth/fake_secure_message_delegate.h"
 #include "components/cryptauth/remote_device_test_util.h"
@@ -37,28 +38,6 @@
 const char kBluetoothAddress2[] = "22:33:44:55:66:77";
 const char kBluetoothAddress3[] = "33:44:55:66:77:88";
 
-class FakeSecureChannelDelegate : public cryptauth::SecureChannel::Delegate {
- public:
-  FakeSecureChannelDelegate() {}
-  ~FakeSecureChannelDelegate() override {}
-
-  std::unique_ptr<cryptauth::SecureMessageDelegate>
-  CreateSecureMessageDelegate() override {
-    return base::MakeUnique<cryptauth::FakeSecureMessageDelegate>();
-  }
-};
-
-class TestDelegate : public BleConnectionManager::Delegate {
- public:
-  TestDelegate() {}
-  ~TestDelegate() {}
-
-  std::unique_ptr<cryptauth::SecureChannel::Delegate>
-  CreateSecureChannelDelegate() override {
-    return base::WrapUnique(new FakeSecureChannelDelegate());
-  }
-};
-
 struct SecureChannelStatusChange {
   SecureChannelStatusChange(const cryptauth::RemoteDevice& remote_device,
                             const cryptauth::SecureChannel::Status& old_status,
@@ -209,11 +188,10 @@
  protected:
   class FakeSecureChannel : public cryptauth::FakeSecureChannel {
    public:
-    FakeSecureChannel(
-        std::unique_ptr<cryptauth::Connection> connection,
-        std::unique_ptr<cryptauth::SecureChannel::Delegate> delegate)
+    FakeSecureChannel(std::unique_ptr<cryptauth::Connection> connection,
+                      cryptauth::CryptAuthService* cryptauth_service)
         : cryptauth::FakeSecureChannel(std::move(connection),
-                                       std::move(delegate)) {}
+                                       cryptauth_service) {}
     ~FakeSecureChannel() override {}
 
     void AddObserver(Observer* observer) override {
@@ -238,12 +216,12 @@
 
     std::unique_ptr<cryptauth::SecureChannel> BuildInstance(
         std::unique_ptr<cryptauth::Connection> connection,
-        std::unique_ptr<cryptauth::SecureChannel::Delegate> delegate) override {
+        cryptauth::CryptAuthService* cryptauth_service) override {
       FakeConnectionWithAddress* fake_connection =
           static_cast<FakeConnectionWithAddress*>(connection.get());
       EXPECT_EQ(expected_device_address_, fake_connection->GetDeviceAddress());
       return base::WrapUnique(
-          new FakeSecureChannel(std::move(connection), std::move(delegate)));
+          new FakeSecureChannel(std::move(connection), cryptauth_service));
     }
 
    private:
@@ -268,7 +246,8 @@
     verified_status_changes_.clear();
     verified_received_messages_.clear();
 
-    delegate_ = new TestDelegate();
+    fake_cryptauth_service_ =
+        base::MakeUnique<cryptauth::FakeCryptAuthService>();
     mock_adapter_ =
         make_scoped_refptr(new NiceMock<device::MockBluetoothAdapter>());
 
@@ -300,7 +279,7 @@
         fake_secure_channel_factory_.get());
 
     manager_ = base::WrapUnique(new BleConnectionManager(
-        base::WrapUnique(delegate_), mock_adapter_,
+        fake_cryptauth_service_.get(), mock_adapter_,
         base::WrapUnique(mock_ble_scanner_),
         base::WrapUnique(mock_ble_advertiser_), base::WrapUnique(device_queue_),
         base::WrapUnique(mock_timer_factory_),
@@ -483,7 +462,7 @@
 
   const std::vector<cryptauth::RemoteDevice> test_devices_;
 
-  BleConnectionManager::Delegate* delegate_;
+  std::unique_ptr<cryptauth::FakeCryptAuthService> fake_cryptauth_service_;
   scoped_refptr<NiceMock<device::MockBluetoothAdapter>> mock_adapter_;
   MockBleScanner* mock_ble_scanner_;
   MockBleAdvertiser* mock_ble_advertiser_;
@@ -685,6 +664,43 @@
   VerifyDeviceNotRegistered(test_devices_[0]);
 }
 
+// Test for fix to crbug.com/706640. This test will crash without the fix.
+TEST_F(BleConnectionManagerTest,
+       TestSuccessfulConnection_MultipleAdvertisementsReceived) {
+  EXPECT_CALL(*mock_ble_scanner_,
+              RegisterScanFilterForDevice(test_devices_[0]));
+  EXPECT_CALL(*mock_ble_advertiser_,
+              StartAdvertisingToDevice(test_devices_[0]));
+  EXPECT_CALL(*mock_ble_scanner_,
+              UnregisterScanFilterForDevice(test_devices_[0]));
+  EXPECT_CALL(*mock_ble_advertiser_, StopAdvertisingToDevice(test_devices_[0]));
+
+  manager_->RegisterRemoteDevice(test_devices_[0],
+                                 MessageType::TETHER_AVAILABILITY_REQUEST);
+  VerifyAdvertisingTimeoutSet(test_devices_[0]);
+  VerifyConnectionStateChanges(std::vector<SecureChannelStatusChange>{
+      {test_devices_[0], cryptauth::SecureChannel::Status::DISCONNECTED,
+       cryptauth::SecureChannel::Status::CONNECTING}});
+
+  fake_secure_channel_factory_->SetExpectedDeviceAddress(
+      std::string(kBluetoothAddress1));
+
+  // Simulate multiple advertisements being received:
+  mock_ble_scanner_->SimulateScanResults(std::string(kBluetoothAddress1),
+                                         test_devices_[0]);
+  FakeSecureChannel* channel = GetChannelForDevice(test_devices_[0]);
+
+  mock_ble_scanner_->SimulateScanResults(std::string(kBluetoothAddress1),
+                                         test_devices_[0]);
+  // Verify that a new channel has not been created:
+  EXPECT_EQ(channel, GetChannelForDevice(test_devices_[0]));
+
+  mock_ble_scanner_->SimulateScanResults(std::string(kBluetoothAddress1),
+                                         test_devices_[0]);
+  // Verify that a new channel has not been created:
+  EXPECT_EQ(channel, GetChannelForDevice(test_devices_[0]));
+}
+
 TEST_F(BleConnectionManagerTest,
        TestSuccessfulConnection_MultipleConnectionReasons) {
   EXPECT_CALL(*mock_ble_scanner_,
diff --git a/chromeos/components/tether/connect_tethering_operation.cc b/chromeos/components/tether/connect_tethering_operation.cc
index b7723b7..f63f105 100644
--- a/chromeos/components/tether/connect_tethering_operation.cc
+++ b/chromeos/components/tether/connect_tethering_operation.cc
@@ -52,8 +52,11 @@
     : MessageTransferOperation(
           std::vector<cryptauth::RemoteDevice>{device_to_connect},
           connection_manager),
+      remote_device_(device_to_connect),
       host_scan_device_prioritizer_(host_scan_device_prioritizer),
-      has_authenticated_(false) {}
+      error_code_to_return_(
+          ConnectTetheringResponse_ResponseCode::
+              ConnectTetheringResponse_ResponseCode_UNKNOWN_ERROR) {}
 
 ConnectTetheringOperation::~ConnectTetheringOperation() {}
 
@@ -68,8 +71,6 @@
 void ConnectTetheringOperation::OnDeviceAuthenticated(
     const cryptauth::RemoteDevice& remote_device) {
   DCHECK(remote_devices().size() == 1u && remote_devices()[0] == remote_device);
-  has_authenticated_ = true;
-
   SendMessageToDevice(remote_device, base::MakeUnique<MessageWrapper>(
                                          ConnectTetheringRequest()));
 }
@@ -83,6 +84,11 @@
     return;
   }
 
+  if (!(remote_device == remote_device_)) {
+    // If the message came from another device, ignore it.
+    return;
+  }
+
   ConnectTetheringResponse* response =
       static_cast<ConnectTetheringResponse*>(message_wrapper->GetProto().get());
   if (response->response_code() ==
@@ -98,22 +104,19 @@
       host_scan_device_prioritizer_->RecordSuccessfulConnectTetheringResponse(
           remote_device);
 
-      NotifyObserversOfSuccessfulResponse(response->ssid(),
-                                          response->password());
+      ssid_to_return_ = response->ssid();
+      password_to_return_ = response->password();
     } else {
       PA_LOG(ERROR) << "Received ConnectTetheringResponse from device with ID "
                     << remote_device.GetTruncatedDeviceIdForLogs() << " and "
                     << "response_code == SUCCESS, but the response did not "
                     << "contain a Wi-Fi SSID and/or password.";
-      NotifyObserversOfConnectionFailure(
-          ConnectTetheringResponse_ResponseCode::
-              ConnectTetheringResponse_ResponseCode_UNKNOWN_ERROR);
     }
   } else {
     PA_LOG(INFO) << "Received ConnectTetheringResponse from device with ID "
                  << remote_device.GetTruncatedDeviceIdForLogs() << " and "
                  << "response_code == " << response->response_code() << ".";
-    NotifyObserversOfConnectionFailure(response->response_code());
+    error_code_to_return_ = response->response_code();
   }
 
   // Now that a response has been received, the device can be unregistered.
@@ -121,13 +124,18 @@
 }
 
 void ConnectTetheringOperation::OnOperationFinished() {
-  if (!has_authenticated_) {
-    // If the operation finished but the device never authenticated, there was
-    // some sort of problem connecting to the device. In this case, notify
-    // observers of a failure.
-    NotifyObserversOfConnectionFailure(
-        ConnectTetheringResponse_ResponseCode::
-            ConnectTetheringResponse_ResponseCode_UNKNOWN_ERROR);
+  // Notify observers of the results of this operation in OnOperationFinished()
+  // instead of in OnMessageReceived() because observers may delete this
+  // ConnectTetheringOperation instance. If this happens, the UnregisterDevice()
+  // call in OnMessageReceived() will cause a crash.
+
+  if (!ssid_to_return_.empty()) {
+    NotifyObserversOfSuccessfulResponse(ssid_to_return_, password_to_return_);
+  } else {
+    // At this point, either the operation finished with a failed response or
+    // no connection succeeded at all. In these cases, notify observers of a
+    // failure.
+    NotifyObserversOfConnectionFailure(error_code_to_return_);
   }
 }
 
@@ -139,14 +147,15 @@
     const std::string& ssid,
     const std::string& password) {
   for (auto& observer : observer_list_) {
-    observer.OnSuccessfulConnectTetheringResponse(ssid, password);
+    observer.OnSuccessfulConnectTetheringResponse(remote_device_, ssid,
+                                                  password);
   }
 }
 
 void ConnectTetheringOperation::NotifyObserversOfConnectionFailure(
     ConnectTetheringResponse_ResponseCode error_code) {
   for (auto& observer : observer_list_) {
-    observer.OnConnectTetheringFailure(error_code);
+    observer.OnConnectTetheringFailure(remote_device_, error_code);
   }
 }
 
diff --git a/chromeos/components/tether/connect_tethering_operation.h b/chromeos/components/tether/connect_tethering_operation.h
index d7135b9..fdcc226 100644
--- a/chromeos/components/tether/connect_tethering_operation.h
+++ b/chromeos/components/tether/connect_tethering_operation.h
@@ -50,9 +50,11 @@
   class Observer {
    public:
     virtual void OnSuccessfulConnectTetheringResponse(
+        const cryptauth::RemoteDevice& remote_device,
         const std::string& ssid,
         const std::string& password) = 0;
     virtual void OnConnectTetheringFailure(
+        const cryptauth::RemoteDevice& remote_device,
         ConnectTetheringResponse_ResponseCode error_code) = 0;
   };
 
@@ -73,17 +75,23 @@
                          const cryptauth::RemoteDevice& remote_device) override;
   void OnOperationFinished() override;
   MessageType GetMessageTypeForConnection() override;
-
- private:
-  friend class ConnectTetheringOperationTest;
-
   void NotifyObserversOfSuccessfulResponse(const std::string& ssid,
                                            const std::string& password);
   void NotifyObserversOfConnectionFailure(
       ConnectTetheringResponse_ResponseCode error_code);
 
+ private:
+  friend class ConnectTetheringOperationTest;
+
+  cryptauth::RemoteDevice remote_device_;
   HostScanDevicePrioritizer* host_scan_device_prioritizer_;
-  bool has_authenticated_;
+
+  // These values are saved in OnMessageReceived() and returned in
+  // OnOperationFinished().
+  std::string ssid_to_return_;
+  std::string password_to_return_;
+  ConnectTetheringResponse_ResponseCode error_code_to_return_;
+
   base::ObserverList<Observer> observer_list_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectTetheringOperation);
diff --git a/chromeos/components/tether/connect_tethering_operation_unittest.cc b/chromeos/components/tether/connect_tethering_operation_unittest.cc
index b75c224..85f09ebf 100644
--- a/chromeos/components/tether/connect_tethering_operation_unittest.cc
+++ b/chromeos/components/tether/connect_tethering_operation_unittest.cc
@@ -34,18 +34,23 @@
   TestObserver() : has_received_failure(false) {}
 
   void OnSuccessfulConnectTetheringResponse(
+      const cryptauth::RemoteDevice& remote_device,
       const std::string& ssid,
       const std::string& password) override {
+    this->remote_device = remote_device;
     this->ssid = ssid;
     this->password = password;
   }
 
   void OnConnectTetheringFailure(
+      const cryptauth::RemoteDevice& remote_device,
       ConnectTetheringResponse_ResponseCode error_code) override {
     has_received_failure = true;
+    this->remote_device = remote_device;
     this->error_code = error_code;
   }
 
+  cryptauth::RemoteDevice remote_device;
   std::string ssid;
   std::string password;
 
@@ -152,6 +157,7 @@
     if (expected_response_code ==
         ConnectTetheringResponse_ResponseCode::
             ConnectTetheringResponse_ResponseCode_SUCCESS) {
+      EXPECT_EQ(test_device_, test_observer_->remote_device);
       EXPECT_EQ(std::string(kTestSsid), test_observer_->ssid);
       EXPECT_EQ(std::string(kTestPassword), test_observer_->password);
     } else {
diff --git a/chromeos/components/tether/device_id_tether_network_guid_map.cc b/chromeos/components/tether/device_id_tether_network_guid_map.cc
new file mode 100644
index 0000000..9f22153
--- /dev/null
+++ b/chromeos/components/tether/device_id_tether_network_guid_map.cc
@@ -0,0 +1,29 @@
+// 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 "chromeos/components/tether/device_id_tether_network_guid_map.h"
+
+namespace chromeos {
+
+namespace tether {
+
+DeviceIdTetherNetworkGuidMap::DeviceIdTetherNetworkGuidMap() {}
+
+DeviceIdTetherNetworkGuidMap::~DeviceIdTetherNetworkGuidMap() {}
+
+std::string DeviceIdTetherNetworkGuidMap::GetDeviceIdForTetherNetworkGuid(
+    const std::string& tether_network_guid) {
+  // TODO(hansberry): Use real implementation.
+  return tether_network_guid;
+}
+
+std::string DeviceIdTetherNetworkGuidMap::GetTetherNetworkGuidForDeviceId(
+    const std::string& device_id) {
+  // TODO(hansberry): Use real implementation.
+  return device_id;
+}
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/device_id_tether_network_guid_map.h b/chromeos/components/tether/device_id_tether_network_guid_map.h
new file mode 100644
index 0000000..2d78ca2
--- /dev/null
+++ b/chromeos/components/tether/device_id_tether_network_guid_map.h
@@ -0,0 +1,42 @@
+// 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 CHROMEOS_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
+#define CHROMEOS_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+namespace chromeos {
+
+namespace tether {
+
+// Keeps a mapping between device ID and the tether network GUID associated with
+// tethering to that device.
+// TODO(hansberry): Currently, this class is stubbed out by simply returning the
+//                  same value for both device ID and tether network GUID.
+//                  Figure out a real mapping system.
+class DeviceIdTetherNetworkGuidMap {
+ public:
+  DeviceIdTetherNetworkGuidMap();
+  virtual ~DeviceIdTetherNetworkGuidMap();
+
+  // Returns the device ID for a given tether network GUID.
+  virtual std::string GetDeviceIdForTetherNetworkGuid(
+      const std::string& tether_network_guid);
+
+  // Returns the tether network GUID for a given device ID.
+  virtual std::string GetTetherNetworkGuidForDeviceId(
+      const std::string& device_id);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DeviceIdTetherNetworkGuidMap);
+};
+
+}  // namespace tether
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TETHER_DEVICE_ID_TETHER_NETWORK_GUID_MAP_H_
diff --git a/chromeos/components/tether/fake_wifi_hotspot_connector.cc b/chromeos/components/tether/fake_wifi_hotspot_connector.cc
index cd32548..d6a90e0 100644
--- a/chromeos/components/tether/fake_wifi_hotspot_connector.cc
+++ b/chromeos/components/tether/fake_wifi_hotspot_connector.cc
@@ -12,16 +12,9 @@
 
 namespace tether {
 
-// static
-std::unique_ptr<FakeWifiHotspotConnector> FakeWifiHotspotConnector::Create() {
-  return base::WrapUnique(
-      new FakeWifiHotspotConnector(NetworkStateHandler::InitializeForTest()));
-}
-
 FakeWifiHotspotConnector::FakeWifiHotspotConnector(
-    std::unique_ptr<NetworkStateHandler> network_state_handler)
-    : WifiHotspotConnector(network_state_handler.get(), nullptr),
-      network_state_handler_(std::move(network_state_handler)) {}
+    NetworkStateHandler* network_state_handler)
+    : WifiHotspotConnector(network_state_handler, nullptr) {}
 
 FakeWifiHotspotConnector::~FakeWifiHotspotConnector() {}
 
diff --git a/chromeos/components/tether/fake_wifi_hotspot_connector.h b/chromeos/components/tether/fake_wifi_hotspot_connector.h
index 1f4c172..6518eab 100644
--- a/chromeos/components/tether/fake_wifi_hotspot_connector.h
+++ b/chromeos/components/tether/fake_wifi_hotspot_connector.h
@@ -17,7 +17,7 @@
 // Test double for WifiHotspotConnector.
 class FakeWifiHotspotConnector : public WifiHotspotConnector {
  public:
-  static std::unique_ptr<FakeWifiHotspotConnector> Create();
+  FakeWifiHotspotConnector(NetworkStateHandler* network_state_handler);
   ~FakeWifiHotspotConnector() override;
 
   // Pass an empty string for |wifi_guid| to signify a failed connection.
@@ -34,18 +34,10 @@
       const WifiHotspotConnector::WifiConnectionCallback& callback) override;
 
  private:
-  FakeWifiHotspotConnector(
-      std::unique_ptr<NetworkStateHandler> network_state_handler);
-
   std::string most_recent_ssid_;
   std::string most_recent_password_;
   WifiHotspotConnector::WifiConnectionCallback most_recent_callback_;
 
-  // Not actually used. Only stored to keep the pointer valid for the lifetime
-  // of the object so that AddObserver() and RemoteObserver() can be called in
-  // the base class constructor/destructor.
-  std::unique_ptr<NetworkStateHandler> network_state_handler_;
-
   DISALLOW_COPY_AND_ASSIGN(FakeWifiHotspotConnector);
 };
 
diff --git a/chromeos/components/tether/tether_connector.cc b/chromeos/components/tether/tether_connector.cc
new file mode 100644
index 0000000..d7429a1
--- /dev/null
+++ b/chromeos/components/tether/tether_connector.cc
@@ -0,0 +1,247 @@
+// 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 "chromeos/components/tether/tether_connector.h"
+
+#include "base/bind.h"
+#include "chromeos/components/tether/active_host.h"
+#include "chromeos/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/components/tether/tether_host_fetcher.h"
+#include "chromeos/components/tether/wifi_hotspot_connector.h"
+#include "chromeos/network/network_handler.h"
+#include "chromeos/network/network_state_handler.h"
+#include "components/proximity_auth/logging/logging.h"
+
+namespace chromeos {
+
+namespace tether {
+
+TetherConnector::TetherConnector(
+    WifiHotspotConnector* wifi_hotspot_connector,
+    ActiveHost* active_host,
+    TetherHostFetcher* tether_host_fetcher,
+    BleConnectionManager* connection_manager,
+    HostScanDevicePrioritizer* host_scan_device_prioritizer,
+    DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map)
+    : TetherConnector(NetworkConnect::Get(),
+                      NetworkHandler::Get()->network_state_handler(),
+                      wifi_hotspot_connector,
+                      active_host,
+                      tether_host_fetcher,
+                      connection_manager,
+                      host_scan_device_prioritizer,
+                      device_id_tether_network_guid_map) {}
+
+TetherConnector::TetherConnector(
+    NetworkConnect* network_connect,
+    NetworkStateHandler* network_state_handler,
+    WifiHotspotConnector* wifi_hotspot_connector,
+    ActiveHost* active_host,
+    TetherHostFetcher* tether_host_fetcher,
+    BleConnectionManager* connection_manager,
+    HostScanDevicePrioritizer* host_scan_device_prioritizer,
+    DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map)
+    : network_connect_(network_connect),
+      network_state_handler_(network_state_handler),
+      wifi_hotspot_connector_(wifi_hotspot_connector),
+      active_host_(active_host),
+      tether_host_fetcher_(tether_host_fetcher),
+      connection_manager_(connection_manager),
+      host_scan_device_prioritizer_(host_scan_device_prioritizer),
+      device_id_tether_network_guid_map_(device_id_tether_network_guid_map),
+      weak_ptr_factory_(this) {
+  network_connect_->SetTetherDelegate(this);
+}
+
+TetherConnector::~TetherConnector() {
+  network_connect_->SetTetherDelegate(nullptr);
+  if (connect_tethering_operation_) {
+    connect_tethering_operation_->RemoveObserver(this);
+  }
+}
+
+void TetherConnector::ConnectToNetwork(const std::string& guid) {
+  PA_LOG(INFO) << "Attempting to connect to network with GUID " << guid << ".";
+
+  std::string device_id =
+      device_id_tether_network_guid_map_->GetDeviceIdForTetherNetworkGuid(guid);
+
+  if (device_id_pending_connection_ == device_id) {
+    PA_LOG(INFO) << "Connection attempt requested for network with GUID "
+                 << guid << ", but a connection attempt is already in "
+                 << "progress. Continuing with the existing attempt.";
+    return;
+  }
+
+  if (connect_tethering_operation_) {
+    DCHECK(!device_id_pending_connection_.empty());
+
+    PA_LOG(INFO) << "A connection attempt was already in progress to device "
+                 << "with ID " << device_id_pending_connection_ << ". "
+                 << "Canceling that connection attempt before continuing.";
+
+    // If a connection to a *different* device is pending, stop the connection
+    // attempt.
+    connect_tethering_operation_->RemoveObserver(this);
+    connect_tethering_operation_.reset();
+  }
+
+  device_id_pending_connection_ = device_id;
+
+  tether_host_fetcher_->FetchTetherHost(
+      device_id_pending_connection_,
+      base::Bind(&TetherConnector::OnTetherHostToConnectFetched,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 device_id_pending_connection_));
+}
+
+void TetherConnector::OnSuccessfulConnectTetheringResponse(
+    const cryptauth::RemoteDevice& remote_device,
+    const std::string& ssid,
+    const std::string& password) {
+  if (device_id_pending_connection_ != remote_device.GetDeviceId()) {
+    // If the success was part of a previous attempt for a different device,
+    // ignore it.
+    PA_LOG(INFO) << "Received successful ConnectTetheringResponse from "
+                 << "device with ID "
+                 << remote_device.GetTruncatedDeviceIdForLogs()
+                 << ", but a connection to another device was started while "
+                 << "the response was being received.";
+    return;
+  }
+
+  PA_LOG(INFO) << "Received successful ConnectTetheringResponse from device "
+               << "with ID " << remote_device.GetTruncatedDeviceIdForLogs()
+               << ". SSID: \"" << ssid << "\", Password: \"" << password
+               << "\"";
+
+  // Make a copy of the device ID, SSID, and password to pass below before
+  // destroying |connect_tethering_operation_|.
+  std::string remote_device_id = remote_device.GetDeviceId();
+  std::string ssid_copy = ssid;
+  std::string password_copy = password;
+
+  connect_tethering_operation_->RemoveObserver(this);
+  connect_tethering_operation_.reset();
+
+  wifi_hotspot_connector_->ConnectToWifiHotspot(
+      ssid_copy, password_copy,
+      base::Bind(&TetherConnector::OnWifiConnection,
+                 weak_ptr_factory_.GetWeakPtr(), remote_device_id));
+}
+
+void TetherConnector::OnConnectTetheringFailure(
+    const cryptauth::RemoteDevice& remote_device,
+    ConnectTetheringResponse_ResponseCode error_code) {
+  if (device_id_pending_connection_ != remote_device.GetDeviceId()) {
+    // If the failure was part of a previous attempt for a different device,
+    // ignore it.
+    PA_LOG(INFO) << "Received failed ConnectTetheringResponse from device with "
+                 << "ID " << remote_device.GetTruncatedDeviceIdForLogs()
+                 << ", but a connection to another device has already started.";
+    return;
+  }
+
+  PA_LOG(WARNING) << "Connection to device with ID "
+                  << remote_device.GetTruncatedDeviceIdForLogs()
+                  << " could not connect. Error code: " << error_code;
+
+  connect_tethering_operation_->RemoveObserver(this);
+  connect_tethering_operation_.reset();
+  SetDisconnected();
+}
+
+void TetherConnector::OnTetherHostToConnectFetched(
+    const std::string& device_id,
+    std::unique_ptr<cryptauth::RemoteDevice> tether_host_to_connect) {
+  if (!tether_host_to_connect) {
+    PA_LOG(ERROR) << "Could not fetch tether host with device ID "
+                  << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id)
+                  << ". Cannot connect.";
+    return;
+  }
+
+  if (device_id_pending_connection_ != tether_host_to_connect->GetDeviceId()) {
+    PA_LOG(INFO) << "Device to connect to has changed while device with ID "
+                 << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id)
+                 << " was being fetched.";
+    return;
+  }
+
+  active_host_->SetActiveHostConnecting(
+      device_id_pending_connection_,
+      device_id_tether_network_guid_map_->GetTetherNetworkGuidForDeviceId(
+          device_id_pending_connection_));
+
+  connect_tethering_operation_ =
+      ConnectTetheringOperation::Factory::NewInstance(
+          *tether_host_to_connect, connection_manager_,
+          host_scan_device_prioritizer_);
+  connect_tethering_operation_->AddObserver(this);
+  connect_tethering_operation_->Initialize();
+}
+
+void TetherConnector::SetDisconnected() {
+  device_id_pending_connection_ = "";
+  active_host_->SetActiveHostDisconnected();
+}
+
+void TetherConnector::SetConnected(const std::string& device_id,
+                                   const std::string& wifi_network_guid) {
+  device_id_pending_connection_ = "";
+  active_host_->SetActiveHostConnected(
+      device_id,
+      device_id_tether_network_guid_map_->GetTetherNetworkGuidForDeviceId(
+          device_id),
+      wifi_network_guid);
+}
+
+void TetherConnector::OnWifiConnection(const std::string& device_id,
+                                       const std::string& wifi_network_guid) {
+  if (device_id != device_id_pending_connection_) {
+    // If the device ID does not match the ID of the device pending connection,
+    // this is a stale attempt.
+    PA_LOG(ERROR) << "Cannot connect to device with ID "
+                  << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id)
+                  << " because another connection attempt has been started to "
+                  << "a different device.";
+
+    // TODO(khorimoto): Disconnect from the network.
+    return;
+  }
+
+  if (wifi_network_guid.empty()) {
+    // If the Wi-Fi network ID is empty, then the connection did not succeed.
+    PA_LOG(ERROR) << "Failed to connect to the hotspot belonging to the device "
+                  << "with ID "
+                  << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id)
+                  << ".";
+
+    SetDisconnected();
+    return;
+  }
+
+  bool successful_association =
+      network_state_handler_->AssociateTetherNetworkStateWithWifiNetwork(
+          device_id, wifi_network_guid);
+  if (successful_association) {
+    PA_LOG(INFO) << "Successfully connected to host device with ID "
+                 << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(device_id)
+                 << ". Tether network ID: \"" << device_id
+                 << "\", Wi-Fi network ID: \"" << wifi_network_guid << "\"";
+  } else {
+    PA_LOG(WARNING) << "Successfully connected to host device with ID "
+                    << cryptauth::RemoteDevice::TruncateDeviceIdForLogs(
+                           device_id)
+                    << ", but failed to associate tether network with ID \""
+                    << device_id << "\" to Wi-Fi network with ID \""
+                    << wifi_network_guid << "\".";
+  }
+
+  SetConnected(device_id, wifi_network_guid);
+}
+
+}  // namespace tether
+
+}  // namespace chromeos
diff --git a/chromeos/components/tether/tether_connector.h b/chromeos/components/tether/tether_connector.h
new file mode 100644
index 0000000..1282f16b
--- /dev/null
+++ b/chromeos/components/tether/tether_connector.h
@@ -0,0 +1,98 @@
+// 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 CHROMEOS_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
+#define CHROMEOS_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/components/tether/connect_tethering_operation.h"
+#include "chromeos/network/network_connect.h"
+
+namespace chromeos {
+
+class NetworkStateHandler;
+
+namespace tether {
+
+class ActiveHost;
+class BleConnectionManager;
+class DeviceIdTetherNetworkGuidMap;
+class HostScanDevicePrioritizer;
+class TetherHostFetcher;
+class WifiHotspotConnector;
+
+// Connects to a tether network. When the user initiates a connection via the
+// UI, TetherConnector receives a callback from NetworkConnect and initiates a
+// connection by starting a ConnectTetheringOperation. When a response has been
+// received from the tether host, TetherConnector connects to the associated
+// Wi-Fi network.
+class TetherConnector : public NetworkConnect::TetherDelegate,
+                        public ConnectTetheringOperation::Observer {
+ public:
+  TetherConnector(
+      WifiHotspotConnector* wifi_hotspot_connector,
+      ActiveHost* active_host,
+      TetherHostFetcher* tether_host_fetcher,
+      BleConnectionManager* connection_manager,
+      HostScanDevicePrioritizer* host_scan_device_prioritizer,
+      DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map);
+  ~TetherConnector() override;
+
+  // NetworkConnect::TetherDelegate:
+  void ConnectToNetwork(const std::string& guid) override;
+
+  // ConnectTetheringOperation::Observer:
+  void OnSuccessfulConnectTetheringResponse(
+      const cryptauth::RemoteDevice& remote_device,
+      const std::string& ssid,
+      const std::string& password) override;
+  void OnConnectTetheringFailure(
+      const cryptauth::RemoteDevice& remote_device,
+      ConnectTetheringResponse_ResponseCode error_code) override;
+
+ private:
+  friend class TetherConnectorTest;
+
+  TetherConnector(
+      NetworkConnect* network_connect,
+      NetworkStateHandler* network_state_handler,
+      WifiHotspotConnector* wifi_hotspot_connector,
+      ActiveHost* active_host,
+      TetherHostFetcher* tether_host_fetcher,
+      BleConnectionManager* connection_manager,
+      HostScanDevicePrioritizer* host_scan_device_prioritizer,
+      DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map);
+
+  void SetDisconnected();
+  void SetConnected(const std::string& device_id,
+                    const std::string& wifi_network_guid);
+
+  void OnTetherHostToConnectFetched(
+      const std::string& device_id,
+      std::unique_ptr<cryptauth::RemoteDevice> tether_host_to_connect);
+  void OnWifiConnection(const std::string& device_id,
+                        const std::string& wifi_network_guid);
+
+  NetworkConnect* network_connect_;
+  NetworkStateHandler* network_state_handler_;
+  WifiHotspotConnector* wifi_hotspot_connector_;
+  ActiveHost* active_host_;
+  TetherHostFetcher* tether_host_fetcher_;
+  BleConnectionManager* connection_manager_;
+  HostScanDevicePrioritizer* host_scan_device_prioritizer_;
+  DeviceIdTetherNetworkGuidMap* device_id_tether_network_guid_map_;
+
+  std::string device_id_pending_connection_;
+  std::unique_ptr<ConnectTetheringOperation> connect_tethering_operation_;
+  base::WeakPtrFactory<TetherConnector> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TetherConnector);
+};
+
+}  // namespace tether
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_COMPONENTS_TETHER_TETHER_CONNECTOR_H_
diff --git a/chromeos/components/tether/tether_connector_unittest.cc b/chromeos/components/tether/tether_connector_unittest.cc
new file mode 100644
index 0000000..bace055
--- /dev/null
+++ b/chromeos/components/tether/tether_connector_unittest.cc
@@ -0,0 +1,486 @@
+// 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 "chromeos/components/tether/tether_connector.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "chromeos/components/tether/connect_tethering_operation.h"
+#include "chromeos/components/tether/device_id_tether_network_guid_map.h"
+#include "chromeos/components/tether/fake_active_host.h"
+#include "chromeos/components/tether/fake_ble_connection_manager.h"
+#include "chromeos/components/tether/fake_tether_host_fetcher.h"
+#include "chromeos/components/tether/fake_wifi_hotspot_connector.h"
+#include "chromeos/components/tether/mock_host_scan_device_prioritizer.h"
+#include "chromeos/components/tether/tether_connector.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/network/network_connect.h"
+#include "chromeos/network/network_state.h"
+#include "chromeos/network/network_state_handler.h"
+#include "chromeos/network/network_state_test.h"
+#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"
+
+namespace chromeos {
+
+namespace tether {
+
+namespace {
+
+const char kSsid[] = "ssid";
+const char kPassword[] = "password";
+
+const char kWifiNetworkGuid[] = "wifiNetworkGuid";
+
+const char kTetherNetwork1Name[] = "tetherNetwork1Name";
+const char kTetherNetwork2Name[] = "tetherNetwork2Name";
+
+std::string CreateWifiConfigurationJsonString() {
+  std::stringstream ss;
+  ss << "{"
+     << "  \"GUID\": \"" << kWifiNetworkGuid << "\","
+     << "  \"Type\": \"" << shill::kTypeWifi << "\","
+     << "  \"State\": \"" << shill::kStateIdle << "\""
+     << "}";
+  return ss.str();
+}
+
+class TestNetworkConnect : public NetworkConnect {
+ public:
+  TestNetworkConnect() : tether_delegate_(nullptr) {}
+  ~TestNetworkConnect() override {}
+
+  void CallTetherDelegate(const std::string& tether_network_guid) {
+    tether_delegate_->ConnectToNetwork(tether_network_guid);
+  }
+
+  // NetworkConnect:
+  void SetTetherDelegate(
+      NetworkConnect::TetherDelegate* tether_delegate) override {
+    tether_delegate_ = tether_delegate;
+  }
+
+  void DisconnectFromNetworkId(const std::string& network_id) override {}
+  bool MaybeShowConfigureUI(const std::string& network_id,
+                            const std::string& connect_error) override {
+    return false;
+  }
+  void SetTechnologyEnabled(const chromeos::NetworkTypePattern& technology,
+                            bool enabled_state) override {}
+  void ShowMobileSetup(const std::string& network_id) override {}
+  void ConfigureNetworkIdAndConnect(
+      const std::string& network_id,
+      const base::DictionaryValue& shill_properties,
+      bool shared) override {}
+  void CreateConfigurationAndConnect(base::DictionaryValue* shill_properties,
+                                     bool shared) override {}
+  void CreateConfiguration(base::DictionaryValue* shill_properties,
+                           bool shared) override {}
+  void ConnectToNetworkId(const std::string& network_id) override {}
+
+ private:
+  NetworkConnect::TetherDelegate* tether_delegate_;
+};
+
+class FakeConnectTetheringOperation : public ConnectTetheringOperation {
+ public:
+  FakeConnectTetheringOperation(
+      const cryptauth::RemoteDevice& device_to_connect,
+      BleConnectionManager* connection_manager,
+      HostScanDevicePrioritizer* host_scan_device_prioritizer)
+      : ConnectTetheringOperation(device_to_connect,
+                                  connection_manager,
+                                  host_scan_device_prioritizer) {}
+
+  ~FakeConnectTetheringOperation() override {}
+
+  void SendSuccessfulResponse(const std::string& ssid,
+                              const std::string& password) {
+    NotifyObserversOfSuccessfulResponse(ssid, password);
+  }
+
+  void SendFailedResponse(ConnectTetheringResponse_ResponseCode error_code) {
+    NotifyObserversOfConnectionFailure(error_code);
+  }
+
+  cryptauth::RemoteDevice GetRemoteDevice() {
+    EXPECT_EQ(1u, remote_devices().size());
+    return remote_devices()[0];
+  }
+};
+
+class FakeConnectTetheringOperationFactory
+    : public ConnectTetheringOperation::Factory {
+ public:
+  FakeConnectTetheringOperationFactory() {}
+  virtual ~FakeConnectTetheringOperationFactory() {}
+
+  std::vector<FakeConnectTetheringOperation*>& created_operations() {
+    return created_operations_;
+  }
+
+ protected:
+  // ConnectTetheringOperation::Factory:
+  std::unique_ptr<ConnectTetheringOperation> BuildInstance(
+      const cryptauth::RemoteDevice& device_to_connect,
+      BleConnectionManager* connection_manager,
+      HostScanDevicePrioritizer* host_scan_device_prioritizer) override {
+    FakeConnectTetheringOperation* operation =
+        new FakeConnectTetheringOperation(device_to_connect, connection_manager,
+                                          host_scan_device_prioritizer);
+    created_operations_.push_back(operation);
+    return base::WrapUnique(operation);
+  }
+
+ private:
+  std::vector<FakeConnectTetheringOperation*> created_operations_;
+};
+
+}  // namespace
+
+class TetherConnectorTest : public NetworkStateTest {
+ public:
+  TetherConnectorTest()
+      : test_devices_(cryptauth::GenerateTestRemoteDevices(2u)) {}
+  ~TetherConnectorTest() override {}
+
+  void SetUp() override {
+    DBusThreadManager::Initialize();
+    NetworkStateTest::SetUp();
+
+    fake_operation_factory_ =
+        base::WrapUnique(new FakeConnectTetheringOperationFactory());
+    ConnectTetheringOperation::Factory::SetInstanceForTesting(
+        fake_operation_factory_.get());
+
+    test_network_connect_ = base::WrapUnique(new TestNetworkConnect());
+    fake_wifi_hotspot_connector_ =
+        base::MakeUnique<FakeWifiHotspotConnector>(network_state_handler());
+    fake_active_host_ = base::MakeUnique<FakeActiveHost>();
+    fake_tether_host_fetcher_ = base::MakeUnique<FakeTetherHostFetcher>(
+        test_devices_, false /* synchronously_reply_with_results */);
+    fake_ble_connection_manager_ = base::MakeUnique<FakeBleConnectionManager>();
+    mock_host_scan_device_prioritizer_ =
+        base::MakeUnique<MockHostScanDevicePrioritizer>();
+    device_id_tether_network_guid_map_ =
+        base::MakeUnique<DeviceIdTetherNetworkGuidMap>();
+
+    tether_connector_ = base::WrapUnique(new TetherConnector(
+        test_network_connect_.get(), network_state_handler(),
+        fake_wifi_hotspot_connector_.get(), fake_active_host_.get(),
+        fake_tether_host_fetcher_.get(), fake_ble_connection_manager_.get(),
+        mock_host_scan_device_prioritizer_.get(),
+        device_id_tether_network_guid_map_.get()));
+
+    SetUpTetherNetworks();
+  }
+
+  void TearDown() override {
+    // Must delete |fake_wifi_hotspot_connector_| before NetworkStateHandler is
+    // destroyed to ensure that NetworkStateHandler has zero observers by the
+    // time it reaches its destructor.
+    fake_wifi_hotspot_connector_.reset();
+
+    ShutdownNetworkState();
+    NetworkStateTest::TearDown();
+    DBusThreadManager::Shutdown();
+  }
+
+  std::string GetTetherNetworkGuid(const std::string& device_id) {
+    return device_id_tether_network_guid_map_->GetTetherNetworkGuidForDeviceId(
+        device_id);
+  }
+
+  void SetUpTetherNetworks() {
+    // Add a tether network corresponding to both of the test devices. These
+    // networks are expected to be added already before TetherConnector receives
+    // its ConnectToNetwork() callback.
+    network_state_handler()->AddTetherNetworkState(
+        GetTetherNetworkGuid(test_devices_[0].GetDeviceId()),
+        kTetherNetwork1Name);
+    network_state_handler()->AddTetherNetworkState(
+        GetTetherNetworkGuid(test_devices_[1].GetDeviceId()),
+        kTetherNetwork2Name);
+  }
+
+  void SuccessfullyJoinWifiNetwork() {
+    ConfigureService(CreateWifiConfigurationJsonString());
+    fake_wifi_hotspot_connector_->CallMostRecentCallback(kWifiNetworkGuid);
+  }
+
+  void VerifyTetherAndWifiNetworkAssociation(
+      const std::string& tether_network_guid) {
+    const NetworkState* tether_network_state =
+        network_state_handler()->GetNetworkStateFromGuid(tether_network_guid);
+    EXPECT_TRUE(tether_network_state);
+    EXPECT_EQ(kWifiNetworkGuid, tether_network_state->tether_guid());
+
+    const NetworkState* wifi_network_state =
+        network_state_handler()->GetNetworkStateFromGuid(kWifiNetworkGuid);
+    EXPECT_TRUE(wifi_network_state);
+    EXPECT_EQ(tether_network_guid, wifi_network_state->tether_guid());
+  }
+
+  const std::vector<cryptauth::RemoteDevice> test_devices_;
+  const base::MessageLoop message_loop_;
+
+  std::unique_ptr<FakeConnectTetheringOperationFactory> fake_operation_factory_;
+  std::unique_ptr<TestNetworkConnect> test_network_connect_;
+  std::unique_ptr<FakeWifiHotspotConnector> fake_wifi_hotspot_connector_;
+  std::unique_ptr<FakeActiveHost> fake_active_host_;
+  std::unique_ptr<FakeTetherHostFetcher> fake_tether_host_fetcher_;
+  std::unique_ptr<FakeBleConnectionManager> fake_ble_connection_manager_;
+  std::unique_ptr<MockHostScanDevicePrioritizer>
+      mock_host_scan_device_prioritizer_;
+  // TODO(hansberry): Use a fake for this when a real mapping scheme is created.
+  std::unique_ptr<DeviceIdTetherNetworkGuidMap>
+      device_id_tether_network_guid_map_;
+
+  std::unique_ptr<TetherConnector> tether_connector_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TetherConnectorTest);
+};
+
+TEST_F(TetherConnectorTest, TestCannotFetchDevice) {
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid("nonexistentDeviceId"));
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+
+  // Since an invalid device ID was used, no connection should have been
+  // started.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::DISCONNECTED,
+            fake_active_host_->GetActiveHostStatus());
+}
+
+TEST_F(TetherConnectorTest, TestConnectTetheringOperationFails) {
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+
+  // The connection should have started.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(test_devices_[0].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+  EXPECT_EQ(GetTetherNetworkGuid(test_devices_[0].GetDeviceId()),
+            fake_active_host_->GetTetherNetworkGuid());
+  EXPECT_TRUE(fake_active_host_->GetWifiNetworkGuid().empty());
+
+  // Simulate a failed connection attempt (either the host cannot provide
+  // tethering at this time or a timeout occurs).
+  EXPECT_EQ(1u, fake_operation_factory_->created_operations().size());
+  fake_operation_factory_->created_operations()[0]->SendFailedResponse(
+      ConnectTetheringResponse_ResponseCode::
+          ConnectTetheringResponse_ResponseCode_UNKNOWN_ERROR);
+
+  // The failure should have resulted in the host being disconnected.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::DISCONNECTED,
+            fake_active_host_->GetActiveHostStatus());
+}
+
+TEST_F(TetherConnectorTest, TestConnectingToWifiFails) {
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+
+  // The connection should have started.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(test_devices_[0].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+  EXPECT_EQ(GetTetherNetworkGuid(test_devices_[0].GetDeviceId()),
+            fake_active_host_->GetTetherNetworkGuid());
+  EXPECT_TRUE(fake_active_host_->GetWifiNetworkGuid().empty());
+
+  // Receive a successful response. We should still be connecting.
+  EXPECT_EQ(1u, fake_operation_factory_->created_operations().size());
+  fake_operation_factory_->created_operations()[0]->SendSuccessfulResponse(
+      kSsid, kPassword);
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+
+  // |fake_wifi_hotspot_connector_| should have received the SSID and password
+  // above. Verify this, then return an empty string, signaling a failure to
+  // connect.
+  EXPECT_EQ(kSsid, fake_wifi_hotspot_connector_->most_recent_ssid());
+  EXPECT_EQ(kPassword, fake_wifi_hotspot_connector_->most_recent_password());
+  fake_wifi_hotspot_connector_->CallMostRecentCallback("");
+
+  // The failure should have resulted in the host being disconnected.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::DISCONNECTED,
+            fake_active_host_->GetActiveHostStatus());
+}
+
+TEST_F(TetherConnectorTest, TestSuccessfulConnection) {
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+
+  // The connection should have started.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(test_devices_[0].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+  EXPECT_EQ(GetTetherNetworkGuid(test_devices_[0].GetDeviceId()),
+            fake_active_host_->GetTetherNetworkGuid());
+  EXPECT_TRUE(fake_active_host_->GetWifiNetworkGuid().empty());
+
+  // Receive a successful response. We should still be connecting.
+  EXPECT_EQ(1u, fake_operation_factory_->created_operations().size());
+  fake_operation_factory_->created_operations()[0]->SendSuccessfulResponse(
+      kSsid, kPassword);
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+
+  // |fake_wifi_hotspot_connector_| should have received the SSID and password
+  // above. Verify this, then return the GUID corresponding to the connected
+  // Wi-Fi network.
+  EXPECT_EQ(kSsid, fake_wifi_hotspot_connector_->most_recent_ssid());
+  EXPECT_EQ(kPassword, fake_wifi_hotspot_connector_->most_recent_password());
+  SuccessfullyJoinWifiNetwork();
+
+  // The active host should now be connected, and the tether and Wi-Fi networks
+  // should be associated.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTED,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(test_devices_[0].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+  EXPECT_EQ(GetTetherNetworkGuid(test_devices_[0].GetDeviceId()),
+            fake_active_host_->GetTetherNetworkGuid());
+  EXPECT_EQ(kWifiNetworkGuid, fake_active_host_->GetWifiNetworkGuid());
+  VerifyTetherAndWifiNetworkAssociation(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+}
+
+TEST_F(TetherConnectorTest, TestNewConnectionAttemptDuringFetch_SameDevice) {
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+
+  // Instead of invoking the pending callbacks on |fake_tether_host_fetcher_|,
+  // attempt another connection attempt.
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+
+  // Now invoke the callbacks. Only one operation should have been created,
+  // even though the callback occurred twice.
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+  EXPECT_EQ(1u, fake_operation_factory_->created_operations().size());
+}
+
+TEST_F(TetherConnectorTest,
+       TestNewConnectionAttemptDuringFetch_DifferentDevice) {
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+
+  // Instead of invoking the pending callbacks on |fake_tether_host_fetcher_|,
+  // attempt another connection attempt, this time to another device.
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[1].GetDeviceId()));
+
+  // Now invoke the callbacks. An operation should have been created for the
+  // device 1, not device 0.
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+  EXPECT_EQ(1u, fake_operation_factory_->created_operations().size());
+  EXPECT_EQ(
+      test_devices_[1],
+      fake_operation_factory_->created_operations()[0]->GetRemoteDevice());
+}
+
+TEST_F(TetherConnectorTest,
+       TestNewConnectionAttemptDuringOperation_DifferentDevice) {
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+
+  // The active host should be device 0.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(test_devices_[0].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+  EXPECT_EQ(GetTetherNetworkGuid(test_devices_[0].GetDeviceId()),
+            fake_active_host_->GetTetherNetworkGuid());
+  EXPECT_TRUE(fake_active_host_->GetWifiNetworkGuid().empty());
+
+  // An operation should have been created.
+  EXPECT_EQ(1u, fake_operation_factory_->created_operations().size());
+
+  // Before the created operation replies, start a new connection to device 1.
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[1].GetDeviceId()));
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+
+  // Now, the active host should be the second device.
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(test_devices_[1].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+  EXPECT_EQ(GetTetherNetworkGuid(test_devices_[1].GetDeviceId()),
+            fake_active_host_->GetTetherNetworkGuid());
+  EXPECT_TRUE(fake_active_host_->GetWifiNetworkGuid().empty());
+
+  // A second operation should have been created.
+  EXPECT_EQ(2u, fake_operation_factory_->created_operations().size());
+
+  // The first operation replies successfully, but this response should be
+  // ignored since the active host has changed.
+  fake_operation_factory_->created_operations()[0]->SendSuccessfulResponse(
+      kSsid, kPassword);
+  EXPECT_EQ(test_devices_[1].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+
+  // No connection should have been started.
+  EXPECT_TRUE(fake_wifi_hotspot_connector_->most_recent_ssid().empty());
+  EXPECT_TRUE(fake_wifi_hotspot_connector_->most_recent_password().empty());
+
+  // The second operation replies successfully, and this response should
+  // result in a Wi-Fi connection attempt.
+  fake_operation_factory_->created_operations()[1]->SendSuccessfulResponse(
+      kSsid, kPassword);
+  EXPECT_EQ(kSsid, fake_wifi_hotspot_connector_->most_recent_ssid());
+  EXPECT_EQ(kPassword, fake_wifi_hotspot_connector_->most_recent_password());
+}
+
+TEST_F(TetherConnectorTest,
+       TestNewConnectionAttemptDuringWifiConnection_DifferentDevice) {
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[0].GetDeviceId()));
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(test_devices_[0].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+  EXPECT_EQ(1u, fake_operation_factory_->created_operations().size());
+
+  fake_operation_factory_->created_operations()[0]->SendSuccessfulResponse(
+      kSsid, kPassword);
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(kSsid, fake_wifi_hotspot_connector_->most_recent_ssid());
+  EXPECT_EQ(kPassword, fake_wifi_hotspot_connector_->most_recent_password());
+
+  // While the connection to the Wi-Fi network is in progress, start a new
+  // connection attempt.
+  test_network_connect_->CallTetherDelegate(
+      GetTetherNetworkGuid(test_devices_[1].GetDeviceId()));
+  fake_tether_host_fetcher_->InvokePendingCallbacks();
+
+  // Connect successfully to the first Wi-Fi network. Even though a temporary
+  // connection has succeeded, the active host should be CONNECTING to device 1.
+  SuccessfullyJoinWifiNetwork();
+  EXPECT_EQ(ActiveHost::ActiveHostStatus::CONNECTING,
+            fake_active_host_->GetActiveHostStatus());
+  EXPECT_EQ(test_devices_[1].GetDeviceId(),
+            fake_active_host_->GetActiveHostDeviceId());
+  EXPECT_EQ(GetTetherNetworkGuid(test_devices_[1].GetDeviceId()),
+            fake_active_host_->GetTetherNetworkGuid());
+  EXPECT_TRUE(fake_active_host_->GetWifiNetworkGuid().empty());
+}
+
+}  // namespace tether
+
+}  // namespace cryptauth
diff --git a/chromeos/components/tether/tether_host_fetcher.cc b/chromeos/components/tether/tether_host_fetcher.cc
index f033cf9..4f13a3c8 100644
--- a/chromeos/components/tether/tether_host_fetcher.cc
+++ b/chromeos/components/tether/tether_host_fetcher.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "components/cryptauth/cryptauth_device_manager.h"
+#include "components/cryptauth/cryptauth_service.h"
 #include "components/cryptauth/remote_device_loader.h"
 #include "components/cryptauth/secure_message_delegate.h"
 
@@ -34,11 +35,11 @@
 TetherHostFetcher::TetherHostFetcher(
     const std::string& user_id,
     const std::string& user_private_key,
-    std::unique_ptr<Delegate> delegate,
+    cryptauth::CryptAuthService* cryptauth_service,
     cryptauth::CryptAuthDeviceManager* device_manager)
     : user_id_(user_id),
       user_private_key_(user_private_key),
-      delegate_(std::move(delegate)),
+      cryptauth_service_(cryptauth_service),
       device_manager_(device_manager),
       weak_ptr_factory_(this) {}
 
@@ -64,7 +65,7 @@
 
   remote_device_loader_ = cryptauth::RemoteDeviceLoader::Factory::NewInstance(
       device_manager_->GetTetherHosts(), user_id_, user_private_key_,
-      delegate_->CreateSecureMessageDelegate());
+      cryptauth_service_->CreateSecureMessageDelegate());
   remote_device_loader_->Load(
       base::Bind(&TetherHostFetcher::OnRemoteDevicesLoaded,
                  weak_ptr_factory_.GetWeakPtr()));
diff --git a/chromeos/components/tether/tether_host_fetcher.h b/chromeos/components/tether/tether_host_fetcher.h
index 3555af3..d190758 100644
--- a/chromeos/components/tether/tether_host_fetcher.h
+++ b/chromeos/components/tether/tether_host_fetcher.h
@@ -16,8 +16,8 @@
 
 namespace cryptauth {
 class CryptAuthDeviceManager;
+class CryptAuthService;
 class RemoteDeviceLoader;
-class SecureMessageDelegate;
 }  // namespace cryptauth
 
 namespace chromeos {
@@ -28,15 +28,9 @@
 // synced via CryptAuth.
 class TetherHostFetcher {
  public:
-  class Delegate {
-   public:
-    virtual std::unique_ptr<cryptauth::SecureMessageDelegate>
-    CreateSecureMessageDelegate() = 0;
-  };
-
   TetherHostFetcher(const std::string& user_id,
                     const std::string& user_private_key,
-                    std::unique_ptr<Delegate> delegate,
+                    cryptauth::CryptAuthService* cryptauth_service,
                     cryptauth::CryptAuthDeviceManager* device_manager);
   virtual ~TetherHostFetcher();
 
@@ -78,7 +72,8 @@
 
   const std::string user_id_;
   const std::string user_private_key_;
-  std::unique_ptr<Delegate> delegate_;
+
+  cryptauth::CryptAuthService* cryptauth_service_;
   cryptauth::CryptAuthDeviceManager* device_manager_;
 
   std::unique_ptr<cryptauth::RemoteDeviceLoader> remote_device_loader_;
diff --git a/chromeos/components/tether/tether_host_fetcher_unittest.cc b/chromeos/components/tether/tether_host_fetcher_unittest.cc
index 01c5755..6c4a927 100644
--- a/chromeos/components/tether/tether_host_fetcher_unittest.cc
+++ b/chromeos/components/tether/tether_host_fetcher_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "components/cryptauth/cryptauth_device_manager.h"
+#include "components/cryptauth/fake_cryptauth_service.h"
 #include "components/cryptauth/fake_secure_message_delegate.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 #include "components/cryptauth/remote_device_loader.h"
@@ -31,8 +32,10 @@
 const char kTestUserId[] = "testUserId";
 const char kTestUserPrivateKey[] = "kTestUserPrivateKey";
 
-class TestDelegate : public TetherHostFetcher::Delegate {
+class FakeCryptAuthServiceWithTracking
+    : public cryptauth::FakeCryptAuthService {
  public:
+  // FakeCryptAuthService:
   std::unique_ptr<cryptauth::SecureMessageDelegate>
   CreateSecureMessageDelegate() override {
     cryptauth::FakeSecureMessageDelegate* delegate =
@@ -105,9 +108,10 @@
       EXPECT_EQ(test_->test_device_infos_.size(), device_info_list.size());
       EXPECT_EQ(std::string(kTestUserId), user_id);
       EXPECT_EQ(std::string(kTestUserPrivateKey), user_private_key);
-      test_->test_delegate_->VerifySecureMessageDelegateCreatedByFactory(
-          static_cast<cryptauth::FakeSecureMessageDelegate*>(
-              secure_message_delegate.get()));
+      test_->fake_cryptauth_service_
+          ->VerifySecureMessageDelegateCreatedByFactory(
+              static_cast<cryptauth::FakeSecureMessageDelegate*>(
+                  secure_message_delegate.get()));
 
       std::unique_ptr<MockDeviceLoader> device_loader =
           base::WrapUnique(new NiceMock<MockDeviceLoader>());
@@ -141,9 +145,8 @@
     device_list_list_.clear();
     single_device_list_.clear();
 
-    std::unique_ptr<TestDelegate> test_delegate =
-        base::WrapUnique(new TestDelegate());
-    test_delegate_ = test_delegate.get();
+    fake_cryptauth_service_ =
+        base::WrapUnique(new FakeCryptAuthServiceWithTracking());
 
     mock_device_manager_ = base::WrapUnique(new NiceMock<MockDeviceManager>());
     ON_CALL(*mock_device_manager_, GetTetherHosts())
@@ -156,7 +159,7 @@
 
     tether_host_fetcher_ = base::MakeUnique<TetherHostFetcher>(
         std::string(kTestUserId), std::string(kTestUserPrivateKey),
-        std::move(test_delegate), mock_device_manager_.get());
+        fake_cryptauth_service_.get(), mock_device_manager_.get());
   }
 
   void OnTetherHostListFetched(const cryptauth::RemoteDeviceList& device_list) {
@@ -174,7 +177,7 @@
   std::vector<cryptauth::RemoteDeviceList> device_list_list_;
   std::vector<std::shared_ptr<cryptauth::RemoteDevice>> single_device_list_;
 
-  TestDelegate* test_delegate_;
+  std::unique_ptr<FakeCryptAuthServiceWithTracking> fake_cryptauth_service_;
   std::unique_ptr<NiceMock<MockDeviceManager>> mock_device_manager_;
   std::unique_ptr<TestRemoteDeviceLoaderFactory> test_device_loader_factory_;
 
diff --git a/chromeos/dbus/services/cros_dbus_service.cc b/chromeos/dbus/services/cros_dbus_service.cc
index ee37705..e27f1ab 100644
--- a/chromeos/dbus/services/cros_dbus_service.cc
+++ b/chromeos/dbus/services/cros_dbus_service.cc
@@ -113,6 +113,14 @@
 }
 
 // static
+CrosDBusService::ServiceProviderList CrosDBusService::CreateServiceProviderList(
+    std::unique_ptr<ServiceProviderInterface> provider) {
+  ServiceProviderList list;
+  list.push_back(std::move(provider));
+  return list;
+}
+
+// static
 std::unique_ptr<CrosDBusService> CrosDBusService::CreateRealImpl(
     dbus::Bus* bus,
     const std::string& service_name,
diff --git a/chromeos/dbus/services/cros_dbus_service.h b/chromeos/dbus/services/cros_dbus_service.h
index 700f0998..4652d88d 100644
--- a/chromeos/dbus/services/cros_dbus_service.h
+++ b/chromeos/dbus/services/cros_dbus_service.h
@@ -49,6 +49,10 @@
       const dbus::ObjectPath& object_path,
       ServiceProviderList service_providers);
 
+  // Creates a ServiceProviderList containing a single provider.
+  static ServiceProviderList CreateServiceProviderList(
+      std::unique_ptr<ServiceProviderInterface> provider);
+
   virtual ~CrosDBusService();
 
  protected:
diff --git a/chromeos/dbus/services/org.chromium.KioskAppService.conf b/chromeos/dbus/services/org.chromium.KioskAppService.conf
new file mode 100644
index 0000000..fc976c07
--- /dev/null
+++ b/chromeos/dbus/services/org.chromium.KioskAppService.conf
@@ -0,0 +1,22 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<!--
+  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.
+
+  This file will be installed at /opt/google/chrome/dbus on Chrome OS.
+-->
+<busconfig>
+  <policy user="chronos">
+    <allow own="org.chromium.KioskAppService"/>
+  </policy>
+
+  <!--
+    update_engine uses this service to query required platform version for
+    the auto launched kiosk app.
+  -->
+  <policy user="root">
+    <allow send_destination="org.chromium.KioskAppService"/>
+  </policy>
+</busconfig>
diff --git a/components/cryptauth/BUILD.gn b/components/cryptauth/BUILD.gn
index b6a7a42..b9cc6a7c 100644
--- a/components/cryptauth/BUILD.gn
+++ b/components/cryptauth/BUILD.gn
@@ -102,6 +102,8 @@
     "fake_connection.h",
     "fake_cryptauth_gcm_manager.cc",
     "fake_cryptauth_gcm_manager.h",
+    "fake_cryptauth_service.cc",
+    "fake_cryptauth_service.h",
     "fake_secure_channel.cc",
     "fake_secure_channel.h",
     "fake_secure_context.cc",
diff --git a/components/cryptauth/cryptauth_service.h b/components/cryptauth/cryptauth_service.h
index 54506bc6..044d166a 100644
--- a/components/cryptauth/cryptauth_service.h
+++ b/components/cryptauth/cryptauth_service.h
@@ -5,6 +5,8 @@
 #ifndef COMPONENTS_CRYPTAUTH_CRYPTAUTH_SERVICE_H_
 #define COMPONENTS_CRYPTAUTH_CRYPTAUTH_SERVICE_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "components/cryptauth/proto/cryptauth_api.pb.h"
 
diff --git a/components/cryptauth/fake_cryptauth_service.cc b/components/cryptauth/fake_cryptauth_service.cc
new file mode 100644
index 0000000..93b9113c
--- /dev/null
+++ b/components/cryptauth/fake_cryptauth_service.cc
@@ -0,0 +1,46 @@
+// 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 "components/cryptauth/fake_cryptauth_service.h"
+
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "components/cryptauth/fake_secure_message_delegate.h"
+#include "components/cryptauth/mock_cryptauth_client.h"
+
+namespace cryptauth {
+
+FakeCryptAuthService::FakeCryptAuthService() {}
+
+FakeCryptAuthService::~FakeCryptAuthService() {}
+
+CryptAuthDeviceManager* FakeCryptAuthService::GetCryptAuthDeviceManager() {
+  return cryptauth_device_manager_;
+}
+
+CryptAuthEnrollmentManager*
+FakeCryptAuthService::GetCryptAuthEnrollmentManager() {
+  return cryptauth_enrollment_manager_;
+}
+
+DeviceClassifier FakeCryptAuthService::GetDeviceClassifier() {
+  return device_classifier_;
+}
+
+std::string FakeCryptAuthService::GetAccountId() {
+  return account_id_;
+}
+
+std::unique_ptr<SecureMessageDelegate>
+FakeCryptAuthService::CreateSecureMessageDelegate() {
+  return base::MakeUnique<FakeSecureMessageDelegate>();
+}
+
+std::unique_ptr<CryptAuthClientFactory>
+FakeCryptAuthService::CreateCryptAuthClientFactory() {
+  return base::MakeUnique<MockCryptAuthClientFactory>(
+      MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS);
+}
+
+}  // namespace cryptauth
diff --git a/components/cryptauth/fake_cryptauth_service.h b/components/cryptauth/fake_cryptauth_service.h
new file mode 100644
index 0000000..ba5ac17
--- /dev/null
+++ b/components/cryptauth/fake_cryptauth_service.h
@@ -0,0 +1,65 @@
+// 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 COMPONENTS_CRYPTAUTH_FAKE_CRYPTAUTH_SERVICE_H_
+#define COMPONENTS_CRYPTAUTH_FAKE_CRYPTAUTH_SERVICE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/cryptauth/cryptauth_service.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+
+namespace cryptauth {
+
+class CryptAuthClientFactory;
+class CryptAuthDeviceManager;
+class CryptAuthEnrollmentManager;
+class SecureMessageDelegate;
+
+// Service which provides access to various CryptAuth singletons.
+class FakeCryptAuthService : public CryptAuthService {
+ public:
+  FakeCryptAuthService();
+  ~FakeCryptAuthService() override;
+
+  void set_cryptauth_device_manager(
+      CryptAuthDeviceManager* cryptauth_device_manager) {
+    cryptauth_device_manager_ = cryptauth_device_manager;
+  }
+
+  void set_cryptauth_enrollment_manager(
+      CryptAuthEnrollmentManager* cryptauth_enrollment_manager) {
+    cryptauth_enrollment_manager_ = cryptauth_enrollment_manager;
+  }
+
+  void set_device_classifier(const DeviceClassifier& device_classifier) {
+    device_classifier_ = device_classifier;
+  }
+
+  void set_account_id(const std::string& account_id) {
+    account_id_ = account_id;
+  }
+
+  // CryptAuthService:
+  CryptAuthDeviceManager* GetCryptAuthDeviceManager() override;
+  CryptAuthEnrollmentManager* GetCryptAuthEnrollmentManager() override;
+  DeviceClassifier GetDeviceClassifier() override;
+  std::string GetAccountId() override;
+  std::unique_ptr<SecureMessageDelegate> CreateSecureMessageDelegate() override;
+  std::unique_ptr<CryptAuthClientFactory> CreateCryptAuthClientFactory()
+      override;
+
+ private:
+  CryptAuthDeviceManager* cryptauth_device_manager_;
+  CryptAuthEnrollmentManager* cryptauth_enrollment_manager_;
+  DeviceClassifier device_classifier_;
+  std::string account_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeCryptAuthService);
+};
+
+}  // namespace cryptauth
+
+#endif  // COMPONENTS_CRYPTAUTH_FAKE_CRYPTAUTH_SERVICE_H_
diff --git a/components/cryptauth/fake_secure_channel.cc b/components/cryptauth/fake_secure_channel.cc
index e06a0d4d..03956aa 100644
--- a/components/cryptauth/fake_secure_channel.cc
+++ b/components/cryptauth/fake_secure_channel.cc
@@ -13,8 +13,8 @@
     : feature(feature), payload(payload) {}
 
 FakeSecureChannel::FakeSecureChannel(std::unique_ptr<Connection> connection,
-                                     std::unique_ptr<Delegate> delegate)
-    : SecureChannel(std::move(connection), std::move(delegate)) {}
+                                     CryptAuthService* cryptauth_service)
+    : SecureChannel(std::move(connection), cryptauth_service) {}
 
 FakeSecureChannel::~FakeSecureChannel() {}
 
diff --git a/components/cryptauth/fake_secure_channel.h b/components/cryptauth/fake_secure_channel.h
index e086801b..4a202d9a 100644
--- a/components/cryptauth/fake_secure_channel.h
+++ b/components/cryptauth/fake_secure_channel.h
@@ -10,11 +10,13 @@
 
 namespace cryptauth {
 
+class CryptAuthService;
+
 // A fake implementation of SecureChannel to use in tests.
 class FakeSecureChannel : public SecureChannel {
  public:
   FakeSecureChannel(std::unique_ptr<Connection> connection,
-                    std::unique_ptr<Delegate> delegate);
+                    CryptAuthService* cryptauth_service);
   ~FakeSecureChannel() override;
 
   struct SentMessage {
diff --git a/components/cryptauth/secure_channel.cc b/components/cryptauth/secure_channel.cc
index a51b5c8..9048f4d 100644
--- a/components/cryptauth/secure_channel.cc
+++ b/components/cryptauth/secure_channel.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
+#include "components/cryptauth/cryptauth_service.h"
 #include "components/cryptauth/wire_message.h"
 #include "components/proximity_auth/logging/logging.h"
 
@@ -17,12 +18,12 @@
 // static
 std::unique_ptr<SecureChannel> SecureChannel::Factory::NewInstance(
     std::unique_ptr<Connection> connection,
-    std::unique_ptr<Delegate> delegate) {
+    CryptAuthService* cryptauth_service) {
   if (!factory_instance_) {
     factory_instance_ = new Factory();
   }
   return factory_instance_->BuildInstance(std::move(connection),
-                                          std::move(delegate));
+                                          cryptauth_service);
 }
 
 // static
@@ -32,9 +33,9 @@
 
 std::unique_ptr<SecureChannel> SecureChannel::Factory::BuildInstance(
     std::unique_ptr<Connection> connection,
-    std::unique_ptr<Delegate> delegate) {
+    CryptAuthService* cryptauth_service) {
   return base::WrapUnique(
-      new SecureChannel(std::move(connection), std::move(delegate)));
+      new SecureChannel(std::move(connection), cryptauth_service));
 }
 
 // static
@@ -55,8 +56,6 @@
   }
 }
 
-SecureChannel::Delegate::~Delegate() {}
-
 SecureChannel::PendingMessage::PendingMessage() {}
 
 SecureChannel::PendingMessage::PendingMessage(
@@ -66,15 +65,15 @@
 SecureChannel::PendingMessage::~PendingMessage() {}
 
 SecureChannel::SecureChannel(std::unique_ptr<Connection> connection,
-                             std::unique_ptr<Delegate> delegate)
+                             CryptAuthService* cryptauth_service)
     : status_(Status::DISCONNECTED),
       connection_(std::move(connection)),
-      delegate_(std::move(delegate)),
+      cryptauth_service_(cryptauth_service),
       weak_ptr_factory_(this) {
   DCHECK(connection_);
   DCHECK(!connection_->IsConnected());
   DCHECK(!connection_->remote_device().user_id.empty());
-  DCHECK(delegate_);
+  DCHECK(cryptauth_service);
 
   connection_->AddObserver(this);
 }
@@ -201,9 +200,8 @@
   DCHECK(!authenticator_);
 
   authenticator_ = DeviceToDeviceAuthenticator::Factory::NewInstance(
-      connection_.get(),
-      connection_->remote_device().user_id,
-      delegate_->CreateSecureMessageDelegate());
+      connection_.get(), connection_->remote_device().user_id,
+      cryptauth_service_->CreateSecureMessageDelegate());
   authenticator_->Authenticate(
       base::Bind(&SecureChannel::OnAuthenticationResult,
                  weak_ptr_factory_.GetWeakPtr()));
diff --git a/components/cryptauth/secure_channel.h b/components/cryptauth/secure_channel.h
index 3732f24..e0d83b2 100644
--- a/components/cryptauth/secure_channel.h
+++ b/components/cryptauth/secure_channel.h
@@ -19,6 +19,8 @@
 
 namespace cryptauth {
 
+class CryptAuthService;
+
 // An authenticated bi-directional channel for exchanging messages with remote
 // devices. |SecureChannel| manages a |Connection| by initializing it and
 // authenticating it via a security handshake once the connection has occurred.
@@ -59,26 +61,18 @@
         const std::string& payload) = 0;
   };
 
-  class Delegate {
-   public:
-    virtual ~Delegate();
-
-    virtual std::unique_ptr<SecureMessageDelegate>
-    CreateSecureMessageDelegate() = 0;
-  };
-
   class Factory {
    public:
     static std::unique_ptr<SecureChannel> NewInstance(
         std::unique_ptr<Connection> connection,
-        std::unique_ptr<Delegate> delegate);
+        CryptAuthService* cryptauth_service);
 
     static void SetInstanceForTesting(Factory* factory);
 
    protected:
     virtual std::unique_ptr<SecureChannel> BuildInstance(
         std::unique_ptr<Connection> connection,
-        std::unique_ptr<Delegate> delegate);
+        CryptAuthService* cryptauth_service);
 
    private:
     static Factory* factory_instance_;
@@ -112,7 +106,7 @@
 
  protected:
   SecureChannel(std::unique_ptr<Connection> connection,
-                std::unique_ptr<Delegate> delegate);
+                CryptAuthService* cryptauth_service);
 
   Status status_;
 
@@ -141,7 +135,7 @@
       std::unique_ptr<SecureContext> secure_context);
 
   std::unique_ptr<Connection> connection_;
-  std::unique_ptr<Delegate> delegate_;
+  CryptAuthService* cryptauth_service_;  // Outlives this instance.
   std::unique_ptr<Authenticator> authenticator_;
   std::unique_ptr<SecureContext> secure_context_;
   std::deque<PendingMessage> queued_messages_;
diff --git a/components/cryptauth/secure_channel_unittest.cc b/components/cryptauth/secure_channel_unittest.cc
index 3e7968c..f894110 100644
--- a/components/cryptauth/secure_channel_unittest.cc
+++ b/components/cryptauth/secure_channel_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "components/cryptauth/fake_authenticator.h"
 #include "components/cryptauth/fake_connection.h"
+#include "components/cryptauth/fake_cryptauth_service.h"
 #include "components/cryptauth/fake_secure_context.h"
 #include "components/cryptauth/fake_secure_message_delegate.h"
 #include "components/cryptauth/remote_device_test_util.h"
@@ -23,21 +24,6 @@
 
 const std::string test_user_id = "testUserId";
 
-class TestDelegate : public SecureChannel::Delegate {
- public:
-  TestDelegate(std::unique_ptr<SecureMessageDelegate> secure_message_delegate)
-      : secure_message_delegate_(std::move(secure_message_delegate)) {}
-  ~TestDelegate() override {}
-
-  std::unique_ptr<SecureMessageDelegate> CreateSecureMessageDelegate()
-      override {
-    return std::move(secure_message_delegate_);
-  }
-
- private:
-  std::unique_ptr<SecureMessageDelegate> secure_message_delegate_;
-};
-
 struct SecureChannelStatusChange {
   SecureChannelStatusChange(
       const SecureChannel::Status& old_status,
@@ -122,8 +108,8 @@
 class TestSecureChannel : public SecureChannel {
  public:
   TestSecureChannel(std::unique_ptr<Connection> connection,
-                    std::unique_ptr<Delegate> delegate)
-      : SecureChannel(std::move(connection), std::move(delegate)) {}
+                    CryptAuthService* cryptauth_service)
+      : SecureChannel(std::move(connection), cryptauth_service) {}
 };
 
 }  // namespace
@@ -141,17 +127,14 @@
 
     fake_secure_context_ = nullptr;
 
-    fake_secure_message_delegate_ = new FakeSecureMessageDelegate();
-
-    test_delegate_ =
-        new TestDelegate(base::WrapUnique(fake_secure_message_delegate_));
+    fake_cryptauth_service_ = base::MakeUnique<FakeCryptAuthService>();
 
     fake_connection_ =
         new FakeConnection(test_device_, /* should_auto_connect */ false);
 
     EXPECT_FALSE(fake_connection_->observers().size());
     secure_channel_ = base::MakeUnique<TestSecureChannel>(
-        base::WrapUnique(fake_connection_), base::WrapUnique(test_delegate_));
+        base::WrapUnique(fake_connection_), fake_cryptauth_service_.get());
     EXPECT_EQ(static_cast<size_t>(1), fake_connection_->observers().size());
     EXPECT_EQ(secure_channel_.get(), fake_connection_->observers()[0]);
 
@@ -300,11 +283,7 @@
   // Owned by secure_channel_.
   FakeConnection* fake_connection_;
 
-  // Owned by secure_chanel_.
-  TestDelegate* test_delegate_;
-
-  // Owned by test_delegate_.
-  FakeSecureMessageDelegate* fake_secure_message_delegate_;
+  std::unique_ptr<FakeCryptAuthService> fake_cryptauth_service_;
 
   // Owned by secure_channel_ once authentication has completed successfully.
   FakeSecureContext* fake_secure_context_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index 207c98f..651d177 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -20,6 +21,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
 #include "components/data_reduction_proxy/core/browser/data_usage_store.h"
 #include "components/data_reduction_proxy/core/browser/data_use_group.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
 #include "components/data_reduction_proxy/proto/data_store.pb.h"
@@ -367,6 +369,14 @@
       base::Bind(
           &DataReductionProxyCompressionStats::OnDataUsageReportingPrefChanged,
           weak_factory_.GetWeakPtr()));
+
+  if (!base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown)) {
+    // If the user is moved out of the experiment make sure that data usage
+    // reporting is not enabled and the map is cleared.
+    SetDataUsageReportingEnabled(false);
+    DeleteHistoricalDataUsage();
+  }
+
   if (data_usage_reporting_enabled_.GetValue()) {
     current_data_usage_load_status_ = LOADING;
     service_->LoadCurrentDataUsageBucket(base::Bind(
@@ -681,6 +691,15 @@
   current_data_usage_load_status_ = LOADED;
 }
 
+void DataReductionProxyCompressionStats::SetDataUsageReportingEnabled(
+    bool enabled) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  if (data_usage_reporting_enabled_.GetValue() != enabled) {
+    data_usage_reporting_enabled_.SetValue(enabled);
+    OnDataUsageReportingPrefChanged();
+  }
+}
+
 void DataReductionProxyCompressionStats::ClearDataSavingStatistics() {
   DeleteHistoricalDataUsage();
 
@@ -1195,6 +1214,7 @@
 void DataReductionProxyCompressionStats::GetHistoricalDataUsageImpl(
     const HistoricalDataUsageCallback& get_data_usage_callback,
     const base::Time& now) {
+#if !defined(OS_ANDROID)
   if (current_data_usage_load_status_ != LOADED) {
     // If current data usage has not yet loaded, we return an empty array. The
     // extension can retry after a slight delay.
@@ -1204,10 +1224,13 @@
         base::MakeUnique<std::vector<DataUsageBucket>>());
     return;
   }
+#endif
 
-  PersistDataUsage();
+  if (current_data_usage_load_status_ == LOADED)
+    PersistDataUsage();
 
-  if (!DataUsageStore::AreInSameInterval(data_usage_map_last_updated_, now)) {
+  if (!data_usage_map_last_updated_.is_null() &&
+      !DataUsageStore::AreInSameInterval(data_usage_map_last_updated_, now)) {
     data_usage_map_.clear();
     data_usage_map_last_updated_ = base::Time();
 
@@ -1229,7 +1252,19 @@
           weak_factory_.GetWeakPtr()));
     }
   } else {
+// Don't delete the historical data on Android, but clear the map.
+#if defined(OS_ANDROID)
+    DCHECK(current_data_usage_load_status_ != LOADING);
+
+    if (current_data_usage_load_status_ == LOADED)
+      PersistDataUsage();
+
+    data_usage_map_.clear();
+    data_usage_map_last_updated_ = base::Time();
+    data_usage_map_is_dirty_ = false;
+#else
     DeleteHistoricalDataUsage();
+#endif
     current_data_usage_load_status_ = NOT_LOADED;
   }
 }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
index 780e9d2..b3cf152c 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
@@ -125,6 +125,11 @@
   // for the last stored interval.
   void OnCurrentDataUsageLoaded(std::unique_ptr<DataUsageBucket> data_usage);
 
+  // Sets the value of |prefs::kDataUsageReportingEnabled| to |enabled|.
+  // Initializes data usage statistics in memory when pref is enabled and
+  // persists data usage to memory when pref is disabled.
+  void SetDataUsageReportingEnabled(bool enabled);
+
  private:
   // Enum to track the state of loading data usage from storage.
   enum CurrentDataUsageLoadStatus { NOT_LOADED = 0, LOADING = 1, LOADED = 2 };
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
index 15ab6fc..3629386e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
@@ -1120,6 +1120,7 @@
   DisableDataUsageReporting();
   base::RunLoop().RunUntilIdle();
 
+#if !defined(OS_ANDROID)
   // Data usage on disk must be deleted.
   auto expected_data_usage1 =
       base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
@@ -1135,6 +1136,26 @@
   GetHistoricalDataUsage(base::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
                                     base::Unretained(&verifier2)),
                          now);
+#else
+  // For Android don't delete data usage.
+  auto expected_data_usage =
+      base::MakeUnique<std::vector<data_reduction_proxy::DataUsageBucket>>(
+          kNumExpectedBuckets);
+  data_reduction_proxy::PerConnectionDataUsage* connection_usage =
+      expected_data_usage->at(kNumExpectedBuckets - 1).add_connection_usage();
+  data_reduction_proxy::PerSiteDataUsage* site_usage =
+      connection_usage->add_site_usage();
+  site_usage->set_hostname("www.foo.com");
+  site_usage->set_data_used(1000);
+  site_usage->set_original_size(1250);
+
+  DataUsageLoadVerifier verifier(std::move(expected_data_usage));
+
+  GetHistoricalDataUsage(base::Bind(&DataUsageLoadVerifier::OnLoadDataUsage,
+                                    base::Unretained(&verifier)),
+                         now);
+#endif
+
   base::RunLoop().RunUntilIdle();
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index 80631551..b07e7dd8 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/clock.h"
 #include "base/time/default_clock.h"
@@ -15,6 +16,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
@@ -103,6 +105,12 @@
   UpdateConfigValues();
   RecordDataReductionInit();
   data_reduction_proxy_service_->InitializeLoFiPrefs();
+
+  if (base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown) &&
+      spdy_proxy_auth_enabled_.GetValue()) {
+    data_reduction_proxy_service_->compression_stats()
+        ->SetDataUsageReportingEnabled(true);
+  }
 }
 
 void DataReductionProxySettings::OnServiceInitialized() {
@@ -139,9 +147,14 @@
 
 void DataReductionProxySettings::SetDataReductionProxyEnabled(bool enabled) {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(data_reduction_proxy_service_->compression_stats());
   if (spdy_proxy_auth_enabled_.GetValue() != enabled) {
     spdy_proxy_auth_enabled_.SetValue(enabled);
     OnProxyEnabledPrefChange();
+    if (base::FeatureList::IsEnabled(features::kDataReductionSiteBreakdown)) {
+      data_reduction_proxy_service_->compression_stats()
+          ->SetDataUsageReportingEnabled(enabled);
+    }
   }
 }
 
@@ -152,6 +165,13 @@
       data_reduction_proxy_service_->compression_stats()->GetLastUpdateTime();
 }
 
+void DataReductionProxySettings::ClearDataSavingStatistics() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(data_reduction_proxy_service_->compression_stats());
+  data_reduction_proxy_service_->compression_stats()
+      ->ClearDataSavingStatistics();
+}
+
 int64_t DataReductionProxySettings::GetTotalHttpContentLengthSaved() {
   DCHECK(thread_checker_.CalledOnValidThread());
   return data_reduction_proxy_service_->compression_stats()
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index 75af6f3..b329f5f 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -90,8 +90,6 @@
       DataReductionProxyIOData* io_data,
       std::unique_ptr<DataReductionProxyService> data_reduction_proxy_service);
 
-  base::WeakPtr<DataReductionProxyCompressionStats> compression_stats();
-
   // Sets the |register_synthetic_field_trial_| callback and runs to register
   // the DataReductionProxyEnabled and the DataReductionProxyLoFiEnabled
   // synthetic field trial.
@@ -139,6 +137,9 @@
   // daily original and received content lengths.
   int64_t GetDataReductionLastUpdateTime();
 
+  // Clears all data saving statistics.
+  void ClearDataSavingStatistics();
+
   // Returns the difference between the total original size of all HTTP content
   // received from the network and the actual size of the HTTP content received.
   int64_t GetTotalHttpContentLengthSaved();
diff --git a/components/data_reduction_proxy/core/browser/data_usage_store.cc b/components/data_reduction_proxy/core/browser/data_usage_store.cc
index 98bcbbd0..fb89dd0 100644
--- a/components/data_reduction_proxy/core/browser/data_usage_store.cc
+++ b/components/data_reduction_proxy/core/browser/data_usage_store.cc
@@ -22,23 +22,23 @@
 #include "base/time/time.h"
 #include "components/data_reduction_proxy/proto/data_store.pb.h"
 
+namespace data_reduction_proxy {
+
 namespace {
+
 const char kCurrentBucketIndexKey[] = "current_bucket_index";
 const char kBucketKeyPrefix[] = "data_usage_bucket:";
 
 const int kMinutesInHour = 60;
 const int kMinutesInDay = 24 * kMinutesInHour;
 
-// Time interval for each DataUsageBucket.
-const int kDataUsageBucketLengthInMinutes = 15;
-static_assert(kDataUsageBucketLengthInMinutes > 0,
+static_assert(data_reduction_proxy::kDataUsageBucketLengthInMinutes > 0,
               "Length of time should be positive");
-static_assert(kMinutesInHour % kDataUsageBucketLengthInMinutes == 0,
+static_assert(kMinutesInHour %
+                      data_reduction_proxy::kDataUsageBucketLengthInMinutes ==
+                  0,
               "kDataUsageBucketLengthMins must be a factor of kMinsInHour");
 
-// Number of days for which to maintain data usage history.
-const int kDataUsageHistoryNumDays = 60;
-
 // Total number of buckets persisted to DB.
 const int kNumDataUsageBuckets =
     kDataUsageHistoryNumDays * kMinutesInDay / kDataUsageBucketLengthInMinutes;
@@ -65,8 +65,6 @@
 
 }  // namespace
 
-namespace data_reduction_proxy {
-
 DataUsageStore::DataUsageStore(DataStore* db)
     : db_(db), current_bucket_index_(-1) {
   sequence_checker_.DetachFromSequence();
diff --git a/components/data_reduction_proxy/core/browser/data_usage_store.h b/components/data_reduction_proxy/core/browser/data_usage_store.h
index c346408..9ef594a 100644
--- a/components/data_reduction_proxy/core/browser/data_usage_store.h
+++ b/components/data_reduction_proxy/core/browser/data_usage_store.h
@@ -21,6 +21,12 @@
 class DataStore;
 class DataUsageBucket;
 
+// Time interval for each DataUsageBucket.
+constexpr int kDataUsageBucketLengthInMinutes = 15;
+
+// Number of days for which to maintain data usage history.
+constexpr int kDataUsageHistoryNumDays = 60;
+
 // Store for detailed data usage stats. Data usage from every
 // |kDataUsageBucketLengthMins| interval is stored in a DataUsageBucket.
 class DataUsageStore {
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
index 8e7e96e..6e09db8 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -12,5 +12,9 @@
 const base::Feature kDataReductionMainMenu{"DataReductionProxyMainMenu",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables the site breakdown on the Data Reduction Proxy settings page.
+const base::Feature kDataReductionSiteBreakdown{
+    "DataReductionProxySiteBreakdown", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
index bb5fbe7..9913b05 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -11,6 +11,7 @@
 namespace features {
 
 extern const base::Feature kDataReductionMainMenu;
+extern const base::Feature kDataReductionSiteBreakdown;
 
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/exo/compositor_frame_sink_holder.cc b/components/exo/compositor_frame_sink_holder.cc
index c21346f..695aeec1 100644
--- a/components/exo/compositor_frame_sink_holder.cc
+++ b/components/exo/compositor_frame_sink_holder.cc
@@ -41,7 +41,8 @@
 // cc::mojom::MojoCompositorFrameSinkClient overrides:
 
 void CompositorFrameSinkHolder::DidReceiveCompositorFrameAck() {
-  // TODO(staraz): Implement this
+  if (surface_)
+    surface_->DidReceiveCompositorFrameAck();
 }
 
 void CompositorFrameSinkHolder::OnBeginFrame(const cc::BeginFrameArgs& args) {
@@ -62,10 +63,7 @@
 
 void CompositorFrameSinkHolder::WillDrawSurface(
     const cc::LocalSurfaceId& local_surface_id,
-    const gfx::Rect& damage_rect) {
-  if (surface_)
-    surface_->WillDraw();
-}
+    const gfx::Rect& damage_rect) {}
 
 ////////////////////////////////////////////////////////////////////////////////
 // cc::ExternalBeginFrameSourceClient overrides:
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 57a45f616..ab863b1 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -464,6 +464,13 @@
     local_surface_id_ = id_allocator_.GenerateId();
   }
 
+  // Move pending frame callbacks to the end of frame_callbacks_.
+  frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
+
+  // Move pending presentation callbacks to the end of presentation_callbacks_.
+  presentation_callbacks_.splice(presentation_callbacks_.end(),
+                                 pending_presentation_callbacks_);
+
   UpdateSurface(false);
 
   if (old_local_surface_id != local_surface_id_) {
@@ -492,13 +499,6 @@
          compositor_frame_sink_holder_->HasReleaseCallbackForResource(
              current_resource_.id));
 
-  // Move pending frame callbacks to the end of frame_callbacks_.
-  frame_callbacks_.splice(frame_callbacks_.end(), pending_frame_callbacks_);
-
-  // Move pending presentation callbacks to the end of presentation_callbacks_.
-  presentation_callbacks_.splice(presentation_callbacks_.end(),
-                                 pending_presentation_callbacks_);
-
   // Synchronize window hierarchy. This will position and update the stacking
   // order of all sub-surfaces after committing all pending state of sub-surface
   // descendants.
@@ -605,7 +605,7 @@
   return value;
 }
 
-void Surface::WillDraw() {
+void Surface::DidReceiveCompositorFrameAck() {
   active_frame_callbacks_.splice(active_frame_callbacks_.end(),
                                  frame_callbacks_);
   swapping_presentation_callbacks_.splice(
diff --git a/components/exo/surface.h b/components/exo/surface.h
index 8e4a6ad..9c633b63 100644
--- a/components/exo/surface.h
+++ b/components/exo/surface.h
@@ -191,8 +191,9 @@
   // Returns a trace value representing the state of the surface.
   std::unique_ptr<base::trace_event::TracedValue> AsTracedValue() const;
 
-  // Call this to indicate that surface is being scheduled for a draw.
-  void WillDraw();
+  // Call this to indicate that the previous CompositorFrame is processed and
+  // the surface is being scheduled for a draw.
+  void DidReceiveCompositorFrameAck();
 
   // Called when the begin frame source has changed.
   void SetBeginFrameSource(cc::BeginFrameSource* begin_frame_source);
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index cd5ddb3..1eb28038 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -329,8 +329,9 @@
   surface->Commit();  // Move callback from pending callbacks to current ones.
   RunAllPendingInMessageLoop();
 
-  // Surface should add itself as observer during WillDraw().
-  surface->WillDraw();
+  // Surface should add itself as observer during
+  // DidReceiveCompositorFrameAck().
+  surface->DidReceiveCompositorFrameAck();
   EXPECT_EQ(1u, source.num_observers());
 
   cc::BeginFrameArgs args(source.CreateBeginFrameArgs(BEGINFRAME_FROM_HERE));
diff --git a/components/exo/wm_helper_ash.cc b/components/exo/wm_helper_ash.cc
index 738a040..72850ee8 100644
--- a/components/exo/wm_helper_ash.cc
+++ b/components/exo/wm_helper_ash.cc
@@ -8,6 +8,7 @@
 #include "ash/common/system/tray/system_tray_notifier.h"
 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm_shell.h"
+#include "ash/public/cpp/config.h"
 #include "ash/shell.h"
 #include "base/memory/singleton.h"
 #include "ui/aura/client/focus_client.h"
@@ -23,12 +24,16 @@
 WMHelperAsh::WMHelperAsh() {
   ash::Shell::Get()->AddShellObserver(this);
   ash::Shell::Get()->activation_client()->AddObserver(this);
-  ash::Shell::Get()->cursor_manager()->AddObserver(this);
+  // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
+  if (ash::WmShell::Get()->GetAshConfig() != ash::Config::MUS)
+    ash::Shell::Get()->cursor_manager()->AddObserver(this);
   ash::WmShell::Get()->AddDisplayObserver(this);
   aura::client::FocusClient* focus_client =
       aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
   focus_client->AddObserver(this);
-  ui::DeviceDataManager::GetInstance()->AddObserver(this);
+  // TODO(crbug.com/709225): Mushrome doesn't have a DeviceDataManager.
+  if (ash::WmShell::Get()->GetAshConfig() != ash::Config::MUS)
+    ui::DeviceDataManager::GetInstance()->AddObserver(this);
   ash::Shell::Get()->system_tray_notifier()->AddAccessibilityObserver(this);
 }
 
@@ -39,10 +44,14 @@
       aura::client::GetFocusClient(ash::Shell::GetPrimaryRootWindow());
   focus_client->RemoveObserver(this);
   ash::WmShell::Get()->RemoveDisplayObserver(this);
-  ash::Shell::Get()->cursor_manager()->RemoveObserver(this);
+  // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
+  if (ash::WmShell::Get()->GetAshConfig() != ash::Config::MUS)
+    ash::Shell::Get()->cursor_manager()->RemoveObserver(this);
   ash::Shell::Get()->activation_client()->RemoveObserver(this);
   ash::Shell::Get()->RemoveShellObserver(this);
-  ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
+  // TODO(crbug.com/709225): Mushrome doesn't have a DeviceDataManager.
+  if (ash::WmShell::Get()->GetAshConfig() != ash::Config::MUS)
+    ui::DeviceDataManager::GetInstance()->RemoveObserver(this);
   ash::Shell::Get()->system_tray_notifier()->RemoveAccessibilityObserver(this);
 }
 
@@ -70,6 +79,9 @@
 }
 
 ui::CursorSetType WMHelperAsh::GetCursorSet() const {
+  // TODO(crbug.com/631103): Mushrome doesn't have a cursor manager yet.
+  if (ash::WmShell::Get()->GetAshConfig() == ash::Config::MUS)
+    return ui::CURSOR_SET_NORMAL;
   return ash::Shell::Get()->cursor_manager()->GetCursorSet();
 }
 
diff --git a/components/exo/wm_helper_mus.h b/components/exo/wm_helper_mus.h
index b9f27d70..c1d9558 100644
--- a/components/exo/wm_helper_mus.h
+++ b/components/exo/wm_helper_mus.h
@@ -20,6 +20,7 @@
 namespace exo {
 
 // A helper class for accessing WindowManager related features.
+// This is only used for mash. Mushrome uses WMHelperAsh.
 class WMHelperMus : public WMHelper,
                     public ui::InputDeviceEventObserver,
                     public aura::FocusSynchronizerObserver,
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index efee30c..027ea48 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -24,7 +24,6 @@
 #include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "content/browser/gpu/gpu_process_host.h"
-#include "content/common/gpu_host_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
 #include "content/public/common/content_client.h"
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 990d5b5..4160c89 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -38,7 +38,6 @@
 #include "content/browser/renderer_host/render_widget_host_view_frame_subscriber.h"
 #include "content/browser/service_manager/service_manager_context.h"
 #include "content/common/child_process_host_impl.h"
-#include "content/common/gpu_host_messages.h"
 #include "content/common/in_process_child_thread_params.h"
 #include "content/common/service_manager/child_connection.h"
 #include "content/common/view_messages.h"
@@ -66,7 +65,6 @@
 #include "media/base/media_switches.h"
 #include "media/media_features.h"
 #include "mojo/edk/embedder/embedder.h"
-#include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
@@ -326,16 +324,7 @@
 class GpuProcessHost::ConnectionFilterImpl : public ConnectionFilter {
  public:
   ConnectionFilterImpl() {
-    registry_.AddInterface(
-        base::Bind(
-            &memory_instrumentation::CoordinatorImpl::BindCoordinatorRequest,
-            base::Unretained(
-                memory_instrumentation::CoordinatorImpl::GetInstance())),
-        content::BrowserThread::GetTaskRunnerForThread(
-            content::BrowserThread::UI));
-#if defined(OS_ANDROID)
     GpuProcessHostUIShim::RegisterUIThreadMojoInterfaces(&registry_);
-#endif
   }
 
  private:
@@ -680,11 +669,7 @@
 
 bool GpuProcessHost::OnMessageReceived(const IPC::Message& message) {
   DCHECK(CalledOnValidThread());
-  IPC_BEGIN_MESSAGE_MAP(GpuProcessHost, message)
-    IPC_MESSAGE_HANDLER(GpuHostMsg_FieldTrialActivated, OnFieldTrialActivated);
-    IPC_MESSAGE_UNHANDLED(RouteOnUIThread(message))
-  IPC_END_MESSAGE_MAP()
-
+  RouteOnUIThread(message);
   return true;
 }
 
@@ -809,13 +794,6 @@
 }
 #endif
 
-void GpuProcessHost::OnFieldTrialActivated(const std::string& trial_name) {
-  // Activate the trial in the browser process to match its state in the
-  // GPU process. This is done by calling FindFullName which finalizes the group
-  // and activates the trial.
-  base::FieldTrialList::FindFullName(trial_name);
-}
-
 void GpuProcessHost::OnProcessLaunched() {
   UMA_HISTOGRAM_TIMES("GPU.GPUProcessLaunchTime",
                       base::TimeTicks::Now() - init_start_time_);
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.cc b/content/browser/gpu/gpu_process_host_ui_shim.cc
index 1eed9f9..8c3afc9 100644
--- a/content/browser/gpu/gpu_process_host_ui_shim.cc
+++ b/content/browser/gpu/gpu_process_host_ui_shim.cc
@@ -14,6 +14,7 @@
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "content/browser/compositor/gpu_process_transport_factory.h"
+#include "content/browser/field_trial_recorder.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
@@ -21,9 +22,9 @@
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_helper.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
-#include "content/common/gpu_host_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "gpu/ipc/common/memory_stats.h"
+#include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
 #include "ui/gfx/swap_result.h"
 
 #if defined(OS_ANDROID)
@@ -56,14 +57,6 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   content::GetGlobalJavaInterfaces()->GetInterface(std::move(request));
 }
-
-// Binder which posts each request to the UI thread.
-template <typename Interface>
-void BindJavaInterfaceOnUIThread(mojo::InterfaceRequest<Interface> request) {
-  BrowserThread::GetTaskRunnerForThread(BrowserThread::UI)
-      ->PostTask(FROM_HERE, base::Bind(&BindJavaInterface<Interface>,
-                                       base::Passed(&request)));
-}
 #endif
 
 }  // namespace
@@ -144,13 +137,23 @@
   g_hosts_by_id.Pointer()->Remove(host_id_);
 }
 
-#if defined(OS_ANDROID)
 // static
 void GpuProcessHostUIShim::RegisterUIThreadMojoInterfaces(
     service_manager::BinderRegistry* registry) {
-  registry->AddInterface(base::Bind(
-      &BindJavaInterfaceOnUIThread<media::mojom::AndroidOverlayProvider>));
-}
+  auto task_runner = BrowserThread::GetTaskRunnerForThread(BrowserThread::UI);
+
+  registry->AddInterface(base::Bind(&FieldTrialRecorder::Create), task_runner);
+  registry->AddInterface(
+      base::Bind(
+          &memory_instrumentation::CoordinatorImpl::BindCoordinatorRequest,
+          base::Unretained(
+              memory_instrumentation::CoordinatorImpl::GetInstance())),
+      task_runner);
+#if defined(OS_ANDROID)
+  registry->AddInterface(
+      base::Bind(&BindJavaInterface<media::mojom::AndroidOverlayProvider>),
+      task_runner);
 #endif
+}
 
 }  // namespace content
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.h b/content/browser/gpu/gpu_process_host_ui_shim.h
index e7ad784..55754be7 100644
--- a/content/browser/gpu/gpu_process_host_ui_shim.h
+++ b/content/browser/gpu/gpu_process_host_ui_shim.h
@@ -61,11 +61,9 @@
   // actually received on the IO thread.
   bool OnMessageReceived(const IPC::Message& message) override;
 
-#if defined(OS_ANDROID)
   // Register Mojo interfaces that must be bound on the UI thread.
   static void RegisterUIThreadMojoInterfaces(
       service_manager::BinderRegistry* registry);
-#endif
 
  private:
   explicit GpuProcessHostUIShim(int host_id);
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
index 625e8d3..5c4f789 100644
--- a/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
+++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker.cc
@@ -339,7 +339,7 @@
       latency_component_id_(0),
       device_scale_factor_(1),
       has_seen_first_gesture_scroll_update_(false),
-      multi_finger_gesture_(false),
+      active_multi_finger_gesture_(false),
       touch_start_default_prevented_(false),
       render_widget_host_delegate_(nullptr) {}
 
@@ -375,6 +375,9 @@
   }
   DCHECK_EQ(rwh_component.event_count, 1u);
 
+  bool multi_finger_touch_gesture =
+      WebInputEvent::isTouchEventType(type) && active_multi_finger_gesture_;
+
   LatencyInfo::LatencyComponent ui_component;
   if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_UI_COMPONENT, 0,
                           &ui_component)) {
@@ -407,7 +410,7 @@
   if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT, 0,
                           &main_component)) {
     DCHECK_EQ(main_component.event_count, 1u);
-    if (!multi_finger_gesture_) {
+    if (!multi_finger_touch_gesture) {
       UMA_HISTOGRAM_INPUT_LATENCY_MILLISECONDS(
           "Event.Latency.QueueingTime." + event_name + default_action_status,
           rwh_component, main_component);
@@ -418,7 +421,7 @@
   if (latency.FindLatency(ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0,
                           &acked_component)) {
     DCHECK_EQ(acked_component.event_count, 1u);
-    if (!multi_finger_gesture_ &&
+    if (!multi_finger_touch_gesture &&
         main_component.event_time != base::TimeTicks()) {
       UMA_HISTOGRAM_INPUT_LATENCY_MILLISECONDS(
           "Event.Latency.BlockingTime." + event_name + default_action_status,
@@ -438,6 +441,14 @@
     const blink::WebInputEvent& event,
     LatencyInfo* latency) {
   DCHECK(latency);
+
+  if (event.type() == WebInputEvent::TouchStart) {
+    const WebTouchEvent& touch_event =
+        *static_cast<const WebTouchEvent*>(&event);
+    DCHECK(touch_event.touchesLength >= 1);
+    active_multi_finger_gesture_ = touch_event.touchesLength != 1;
+  }
+
   if (latency->FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
                            latency_component_id_, NULL)) {
     return;
@@ -508,10 +519,11 @@
     const WebTouchEvent& touch_event =
         *static_cast<const WebTouchEvent*>(&event);
     if (event.type() == WebInputEvent::TouchStart) {
-      DCHECK(touch_event.touchesLength >= 1);
-      multi_finger_gesture_ = touch_event.touchesLength != 1;
       touch_start_default_prevented_ =
           ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
+    } else if (event.type() == WebInputEvent::TouchEnd ||
+               event.type() == WebInputEvent::TouchCancel) {
+      active_multi_finger_gesture_ = touch_event.touchesLength > 2;
     }
   }
 
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker.h b/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
index 7166ff2..520e7ee 100644
--- a/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
+++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker.h
@@ -78,9 +78,9 @@
   int64_t latency_component_id_;
   float device_scale_factor_;
   bool has_seen_first_gesture_scroll_update_;
-  // Whether the current stream of touch events has ever included more than one
-  // touch point.
-  bool multi_finger_gesture_;
+  // Whether the current stream of touch events includes more than one active
+  // touch point. This is set in OnInputEvent, and cleared in OnInputEventAck.
+  bool active_multi_finger_gesture_;
   // Whether the touch start for the current stream of touch events had its
   // default action prevented. Only valid for single finger gestures.
   bool touch_start_default_prevented_;
diff --git a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
index 701e4026..ae4cd8296 100644
--- a/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
+++ b/content/browser/renderer_host/input/render_widget_host_latency_tracker_unittest.cc
@@ -964,4 +964,124 @@
                   touchend_timestamps_ms[2] - touchend_timestamps_ms[1], 1)));
 }
 
+// Event.Latency.(Queueing|Blocking)Time.* histograms shouldn't be reported for
+// multi-finger touch.
+TEST_F(RenderWidgetHostLatencyTrackerTest,
+       MultiFingerTouchIgnoredForQueueingAndBlockingTimeMetrics) {
+  SyntheticWebTouchEvent event;
+  InputEventAckState ack_state = INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
+
+  {
+    // First touch start.
+    ui::LatencyInfo latency;
+    event.PressPoint(1, 1);
+    tracker()->OnInputEvent(event, &latency);
+    tracker()->OnInputEventAck(event, &latency, ack_state);
+  }
+
+  {
+    // Additional touch start will be ignored for queueing and blocking time
+    // metrics.
+    int touchstart_timestamps_ms[] = {11, 25, 35};
+    ui::LatencyInfo latency;
+    event.PressPoint(1, 1);
+    tracker()->OnInputEvent(event, &latency);
+
+    ui::LatencyInfo fake_latency;
+    fake_latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+        tracker()->latency_component_id(), 0,
+        base::TimeTicks() +
+            base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[0]),
+        1);
+
+    fake_latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT, 0, 0,
+        base::TimeTicks() +
+            base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[1]),
+        1);
+
+    fake_latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0,
+        base::TimeTicks() +
+            base::TimeDelta::FromMilliseconds(touchstart_timestamps_ms[2]),
+        1);
+
+    // Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck
+    // overwriting components.
+    tracker()->ComputeInputLatencyHistograms(event.type(),
+                                             tracker()->latency_component_id(),
+                                             fake_latency, ack_state);
+
+    tracker()->OnInputEventAck(event, &latency, ack_state);
+  }
+
+  EXPECT_THAT(histogram_tester().GetAllSamples(
+                  "Event.Latency.QueueingTime.TouchStartDefaultAllowed"),
+              ElementsAre());
+}
+
+// Some touch input histograms aren't reported for multi-finger touch. Other
+// input modalities shouldn't be impacted by there being an active multi-finger
+// touch gesture.
+TEST_F(RenderWidgetHostLatencyTrackerTest, WheelDuringMultiFingerTouch) {
+  SyntheticWebTouchEvent touch_event;
+  InputEventAckState ack_state = INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
+
+  {
+    // First touch start.
+    ui::LatencyInfo latency;
+    touch_event.PressPoint(1, 1);
+    tracker()->OnInputEvent(touch_event, &latency);
+    tracker()->OnInputEventAck(touch_event, &latency, ack_state);
+  }
+
+  {
+    // Second touch start.
+    ui::LatencyInfo latency;
+    touch_event.PressPoint(1, 1);
+    tracker()->OnInputEvent(touch_event, &latency);
+    tracker()->OnInputEventAck(touch_event, &latency, ack_state);
+  }
+
+  {
+    // Wheel event.
+    ui::LatencyInfo latency;
+    // These numbers are sensitive to where the histogram buckets are.
+    int timestamps_ms[] = {11, 25, 35};
+    auto wheel_event = SyntheticWebMouseWheelEventBuilder::Build(
+        blink::WebMouseWheelEvent::PhaseChanged);
+    tracker()->OnInputEvent(touch_event, &latency);
+
+    ui::LatencyInfo fake_latency;
+    fake_latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
+        tracker()->latency_component_id(), 0,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(timestamps_ms[0]),
+        1);
+
+    fake_latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_RENDERER_MAIN_COMPONENT, 0, 0,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(timestamps_ms[1]),
+        1);
+
+    fake_latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT, 0, 0,
+        base::TimeTicks() + base::TimeDelta::FromMilliseconds(timestamps_ms[2]),
+        1);
+
+    // Call ComputeInputLatencyHistograms directly to avoid OnInputEventAck
+    // overwriting components.
+    tracker()->ComputeInputLatencyHistograms(wheel_event.type(),
+                                             tracker()->latency_component_id(),
+                                             fake_latency, ack_state);
+
+    tracker()->OnInputEventAck(wheel_event, &latency, ack_state);
+  }
+
+  EXPECT_THAT(histogram_tester().GetAllSamples(
+                  "Event.Latency.QueueingTime.MouseWheelDefaultAllowed"),
+              ElementsAre(Bucket(14, 1)));
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 7ac964e..b9f0d3a 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -135,7 +135,6 @@
 #include "content/common/child_process_messages.h"
 #include "content/common/content_switches_internal.h"
 #include "content/common/frame_messages.h"
-#include "content/common/gpu_host_messages.h"
 #include "content/common/in_process_child_thread_params.h"
 #include "content/common/render_process_messages.h"
 #include "content/common/resource_messages.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 179378e..007cbf6 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -62,7 +62,6 @@
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
-#include "content/common/gpu_host_messages.h"
 #include "content/common/input_messages.h"
 #include "content/common/site_isolation_policy.h"
 #include "content/common/view_messages.h"
diff --git a/content/browser/speech/chunked_byte_buffer.cc b/content/browser/speech/chunked_byte_buffer.cc
index 3edd0ea..6a5a517 100644
--- a/content/browser/speech/chunked_byte_buffer.cc
+++ b/content/browser/speech/chunked_byte_buffer.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/big_endian.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 
@@ -17,13 +18,6 @@
 static_assert(sizeof(size_t) >= kHeaderLength,
               "chunked byte buffer not supported on this architecture");
 
-uint32_t ReadBigEndian32(const uint8_t* buffer) {
-  return (static_cast<uint32_t>(buffer[3])) |
-         (static_cast<uint32_t>(buffer[2]) << 8) |
-         (static_cast<uint32_t>(buffer[1]) << 16) |
-         (static_cast<uint32_t>(buffer[0]) << 24);
-}
-
 }  // namespace
 
 namespace content {
@@ -128,7 +122,10 @@
 
 size_t ChunkedByteBuffer::Chunk::ExpectedContentLength() const {
   DCHECK_EQ(header.size(), kHeaderLength);
-  return static_cast<size_t>(ReadBigEndian32(&header[0]));
+  uint32_t content_length = 0;
+  base::ReadBigEndian(reinterpret_cast<const char*>(&header[0]),
+                      &content_length);
+  return static_cast<size_t>(content_length);
 }
 
 }  // namespace content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 01910e0..4295af4 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -150,7 +150,6 @@
     "generic_shared_memory_id_generator.cc",
     "generic_shared_memory_id_generator.h",
     "gin_java_bridge_messages.h",
-    "gpu_host_messages.h",
     "host_shared_bitmap_manager.cc",
     "host_shared_bitmap_manager.h",
     "in_process_child_thread_params.cc",
diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h
index c8794ab6..420b4243 100644
--- a/content/common/content_message_generator.h
+++ b/content/common/content_message_generator.h
@@ -21,7 +21,6 @@
 #include "content/common/fileapi/file_system_messages.h"
 #include "content/common/fileapi/webblob_messages.h"
 #include "content/common/frame_messages.h"
-#include "content/common/gpu_host_messages.h"
 #include "content/common/input_messages.h"
 #include "content/common/manifest_manager_messages.h"
 #include "content/common/media/aec_dump_messages.h"
diff --git a/content/common/gpu_host_messages.h b/content/common/gpu_host_messages.h
deleted file mode 100644
index 37a98a2..0000000
--- a/content/common/gpu_host_messages.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Multiply-included message file, hence no include guard here, but see below
-// for a much smaller-than-usual include guard section.
-
-#include "build/build_config.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_message_start.h"
-
-#undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
-
-#define IPC_MESSAGE_START GpuMsgStart
-
-//------------------------------------------------------------------------------
-// GPU Host Messages
-// These are messages to the browser.
-
-// Sent by the GPU process to indicate that a fields trial has been activated.
-IPC_MESSAGE_CONTROL1(GpuHostMsg_FieldTrialActivated, std::string /* name */)
diff --git a/content/gpu/BUILD.gn b/content/gpu/BUILD.gn
index 7ba339a..b1490e8 100644
--- a/content/gpu/BUILD.gn
+++ b/content/gpu/BUILD.gn
@@ -53,6 +53,7 @@
     "//content:export",
     "//content/child",
     "//content/common",
+    "//content/common:mojo_bindings",
     "//content/public/child:child_sources",
     "//content/public/common:common_sources",
     "//gpu:gpu",
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index f55da61a..af964692 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -11,16 +11,18 @@
 #include "base/callback_helpers.h"
 #include "build/build_config.h"
 #include "content/child/child_process.h"
-#include "content/common/gpu_host_messages.h"
+#include "content/common/field_trial_recorder.mojom.h"
 #include "content/gpu/gpu_service_factory.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/service_manager_connection.h"
+#include "content/public/common/service_names.mojom.h"
 #include "content/public/gpu/content_gpu_client.h"
 #include "gpu/command_buffer/common/activity_flags.h"
 #include "gpu/ipc/service/gpu_watchdog_thread.h"
 #include "ipc/ipc_sync_message_filter.h"
 #include "media/gpu/ipc/service/media_gpu_channel_manager.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/ui/gpu/interfaces/gpu_service.mojom.h"
 
@@ -130,7 +132,10 @@
 
 void GpuChildThread::OnFieldTrialGroupFinalized(const std::string& trial_name,
                                                 const std::string& group_name) {
-  Send(new GpuHostMsg_FieldTrialActivated(trial_name));
+  mojom::FieldTrialRecorderPtr field_trial_recorder;
+  GetConnector()->BindInterface(mojom::kBrowserServiceName,
+                                &field_trial_recorder);
+  field_trial_recorder->FieldTrialActivated(trial_name);
 }
 
 void GpuChildThread::CreateGpuMainService(
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index 5d9ae2e..2fd9d0b 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -22,7 +22,6 @@
 #include "build/build_config.h"
 #include "content/child/child_process.h"
 #include "content/common/content_constants_internal.h"
-#include "content/common/gpu_host_messages.h"
 #include "content/gpu/gpu_child_thread.h"
 #include "content/gpu/gpu_process.h"
 #include "content/public/common/content_client.h"
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 6daa30cdc..278c8a6 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -55,7 +55,6 @@
     "//services/service_manager/public/interfaces:interfaces_java",
     "//services/service_manager/public/java:service_manager_java",
     "//services/shape_detection/public/interfaces:interfaces_java",
-    "//skia/public/interfaces:interfaces_java",
     "//third_party/WebKit/public:android_mojo_bindings_java",
     "//third_party/WebKit/public:blink_headers_java",
     "//third_party/WebKit/public:mojo_bindings_java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java
index 50bc619..17ff5506 100644
--- a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java
@@ -12,10 +12,11 @@
 import org.chromium.base.Log;
 import org.chromium.gfx.mojom.RectF;
 import org.chromium.mojo.system.MojoException;
+import org.chromium.mojo.system.SharedBufferHandle;
+import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
 import org.chromium.shape_detection.mojom.FaceDetection;
 import org.chromium.shape_detection.mojom.FaceDetectionResult;
 import org.chromium.shape_detection.mojom.FaceDetectorOptions;
-import org.chromium.skia.mojom.ColorType;
 
 import java.nio.ByteBuffer;
 
@@ -35,42 +36,29 @@
     }
 
     @Override
-    public void detect(org.chromium.skia.mojom.Bitmap bitmapData, DetectResponse callback) {
-        int width = bitmapData.width;
-        int height = bitmapData.height;
+    public void detect(
+            SharedBufferHandle frameData, int width, int height, DetectResponse callback) {
         final long numPixels = (long) width * height;
         // TODO(xianglu): https://crbug.com/670028 homogeneize overflow checking.
-        if (bitmapData.pixelData == null || width <= 0 || height <= 0
-                || numPixels > (Long.MAX_VALUE / 4)) {
+        if (!frameData.isValid() || width <= 0 || height <= 0 || numPixels > (Long.MAX_VALUE / 4)) {
             Log.d(TAG, "Invalid argument(s).");
             callback.call(new FaceDetectionResult());
             return;
         }
 
-        // TODO(junwei.fu): Consider supporting other bitmap pixel formats,
-        // https://crbug.com/684921.
-        if (bitmapData.colorType != ColorType.RGBA_8888
-                && bitmapData.colorType != ColorType.BGRA_8888) {
-            Log.e(TAG, "Unsupported bitmap pixel format");
-            callback.call(new FaceDetectionResult());
-            return;
-        }
-
-        ByteBuffer imageBuffer = ByteBuffer.wrap(bitmapData.pixelData);
+        ByteBuffer imageBuffer = frameData.map(0, numPixels * 4, MapFlags.none());
         if (imageBuffer.capacity() <= 0) {
-            Log.d(TAG, "Failed to wrap from Bitmap.");
+            Log.d(TAG, "Failed to map from SharedBufferHandle.");
             callback.call(new FaceDetectionResult());
             return;
         }
 
-        // TODO(junwei.fu): Use |bitmapData| directly for |unPremultipliedBitmap| to spare a copy
-        // if the bitmap pixel format is RGB_565, the ARGB_8888 Bitmap doesn't need to be created
-        // in this case, https://crbug.com/684930.
         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
 
         // An int array is needed to construct a Bitmap. However the Bytebuffer
-        // we get from |bitmapData| is directly allocated and does not have a supporting array.
-        // Therefore we need to copy from |imageBuffer| to create this intermediate Bitmap.
+        // we get from |sharedBufferHandle| is directly allocated and does not
+        // have a supporting array. Therefore we need to copy from |imageBuffer|
+        // to create this intermediate Bitmap.
         // TODO(xianglu): Consider worker pool as appropriate threads.
         // http://crbug.com/655814
         bitmap.copyPixelsFromBuffer(imageBuffer);
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 4d90edc1..38fbcc5 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -5,6 +5,7 @@
     "service_manager:connector": {
       "provides": {
         "gpu": [
+          "content::mojom::FieldTrialRecorder",
           "media::mojom::AndroidOverlayProvider",
           "memory_instrumentation::mojom::Coordinator"
         ],
diff --git a/content/renderer/media/media_stream_audio_unittest.cc b/content/renderer/media/media_stream_audio_unittest.cc
index 225e87b..defbb51 100644
--- a/content/renderer/media/media_stream_audio_unittest.cc
+++ b/content/renderer/media/media_stream_audio_unittest.cc
@@ -460,8 +460,15 @@
   track()->RemoveSink(&sink);
 }
 
+// https://crbug.com/709231 tracks test failures on Mac10.9 Tests (dbg).
+#if defined(OS_MACOSX)
+#define MAYBE_CallbackOnTrackInitialization \
+  DISABLED_CallbackOnTrackInitialization
+#else
+#define MAYBE_CallbackOnTrackInitialization CallbackOnTrackInitialization
+#endif
 // Tests that a callback is fired when initialization completes on a track.
-TEST_F(MediaStreamAudioTest, CallbackOnTrackInitialization) {
+TEST_F(MediaStreamAudioTest, MAYBE_CallbackOnTrackInitialization) {
   // Create a source, connect it to track, and connect the track to a
   // sink.
   blink_audio_source_.setExtraData(new FakeMediaStreamAudioSource());
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 013db3b..03c74fa 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1651,6 +1651,7 @@
       "//third_party/opus",
       "//third_party/webrtc/api:libjingle_peerconnection",
       "//third_party/webrtc/api:rtc_stats_api",
+      "//third_party/webrtc/api/video_codecs:video_codecs_api",
       "//third_party/webrtc/base:rtc_base",
       "//third_party/webrtc/media:rtc_media",
       "//third_party/webrtc/modules/desktop_capture:primitives",
diff --git a/content/test/data/accessibility/aria/aria-cell-expected-win.txt b/content/test/data/accessibility/aria/aria-cell-expected-win.txt
index 42b593d..79ffc24 100644
--- a/content/test/data/accessibility/aria/aria-cell-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-cell-expected-win.txt
@@ -1,12 +1,12 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE xml-roles:table
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+++++++ROLE_SYSTEM_COLUMNHEADER name='Browser' xml-roles:columnheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser'
-++++++ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+++++++ROLE_SYSTEM_COLUMNHEADER name='Rendering Engine' xml-roles:columnheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_CELL xml-roles:cell
+++++++ROLE_SYSTEM_CELL name='Chrome' xml-roles:cell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Chrome'
-++++++ROLE_SYSTEM_CELL xml-roles:cell
-++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
\ No newline at end of file
+++++++ROLE_SYSTEM_CELL name='Blink' xml-roles:cell
+++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
diff --git a/content/test/data/accessibility/aria/aria-col-attr-expected-blink.txt b/content/test/data/accessibility/aria/aria-col-attr-expected-blink.txt
index 57c2c66..3accb55 100644
--- a/content/test/data/accessibility/aria/aria-col-attr-expected-blink.txt
+++ b/content/test/data/accessibility/aria/aria-col-attr-expected-blink.txt
@@ -1,26 +1,26 @@
 rootWebArea
 ++table ariaColCount=5
 ++++row
-++++++columnHeader ariaColIndex=2
+++++++columnHeader name='cell 2' ariaColIndex=2
 ++++++++staticText name='cell 2'
 ++++++++++inlineTextBox name='cell 2'
-++++++columnHeader ariaColIndex=4
+++++++columnHeader name='cell 4' ariaColIndex=4
 ++++++++staticText name='cell 4'
 ++++++++++inlineTextBox name='cell 4'
-++++++columnHeader ariaColIndex=5
+++++++columnHeader name='cell 5' ariaColIndex=5
 ++++++++staticText name='cell 5'
 ++++++++++inlineTextBox name='cell 5'
 ++++row
-++++++cell ariaColIndex=2
+++++++cell name='cell 2' ariaColIndex=2
 ++++++++staticText name='cell 2'
 ++++++++++inlineTextBox name='cell 2'
-++++++cell ariaColIndex=3
+++++++cell name='cell 3' ariaColIndex=3
 ++++++++staticText name='cell 3'
 ++++++++++inlineTextBox name='cell 3'
-++++++cell ariaColIndex=4
+++++++cell name='cell 4' ariaColIndex=4
 ++++++++staticText name='cell 4'
 ++++++++++inlineTextBox name='cell 4'
-++++++cell ariaColIndex=5
+++++++cell name='cell 5' ariaColIndex=5
 ++++++++staticText name='cell 5'
 ++++++++++inlineTextBox name='cell 5'
 ++++column
@@ -28,4 +28,3 @@
 ++++column
 ++++column
 ++++tableHeaderContainer
-<-- End-of-file -->
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-col-attr-expected-mac.txt b/content/test/data/accessibility/aria/aria-col-attr-expected-mac.txt
index 96c51ad2..e2f6b921 100644
--- a/content/test/data/accessibility/aria/aria-col-attr-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-col-attr-expected-mac.txt
@@ -1,23 +1,23 @@
 AXWebArea
 ++AXTable AXARIAColumnCount='5'
 ++++AXRow
-++++++AXCell AXARIAColumnIndex='2'
+++++++AXCell AXTitle='cell 2' AXARIAColumnIndex='2'
 ++++++++AXStaticText AXValue='cell 2'
-++++++AXCell AXARIAColumnIndex='4'
+++++++AXCell AXTitle='cell 4' AXARIAColumnIndex='4'
 ++++++++AXStaticText AXValue='cell 4'
-++++++AXCell AXARIAColumnIndex='5'
+++++++AXCell AXTitle='cell 5' AXARIAColumnIndex='5'
 ++++++++AXStaticText AXValue='cell 5'
 ++++AXRow
-++++++AXCell AXARIAColumnIndex='2'
+++++++AXCell AXTitle='cell 2' AXARIAColumnIndex='2'
 ++++++++AXStaticText AXValue='cell 2'
-++++++AXCell AXARIAColumnIndex='3'
+++++++AXCell AXTitle='cell 3' AXARIAColumnIndex='3'
 ++++++++AXStaticText AXValue='cell 3'
-++++++AXCell AXARIAColumnIndex='4'
+++++++AXCell AXTitle='cell 4' AXARIAColumnIndex='4'
 ++++++++AXStaticText AXValue='cell 4'
-++++++AXCell AXARIAColumnIndex='5'
+++++++AXCell AXTitle='cell 5' AXARIAColumnIndex='5'
 ++++++++AXStaticText AXValue='cell 5'
 ++++AXColumn
 ++++AXColumn
 ++++AXColumn
 ++++AXColumn
-++++AXGroup
\ No newline at end of file
+++++AXGroup
diff --git a/content/test/data/accessibility/aria/aria-col-attr-expected-win.txt b/content/test/data/accessibility/aria/aria-col-attr-expected-win.txt
index bd10684..51de0a1 100644
--- a/content/test/data/accessibility/aria/aria-col-attr-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-col-attr-expected-win.txt
@@ -1,23 +1,23 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE colcount:5
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER colindex:2 colspan:2
+++++++ROLE_SYSTEM_COLUMNHEADER name='cell 2' colindex:2 colspan:2
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 2'
-++++++ROLE_SYSTEM_COLUMNHEADER colindex:4
+++++++ROLE_SYSTEM_COLUMNHEADER name='cell 4' colindex:4
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 4'
-++++++ROLE_SYSTEM_COLUMNHEADER colindex:5
+++++++ROLE_SYSTEM_COLUMNHEADER name='cell 5' colindex:5
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 5'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL colindex:2
+++++++ROLE_SYSTEM_CELL name='cell 2' colindex:2
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 2'
-++++++ROLE_SYSTEM_CELL colindex:3
+++++++ROLE_SYSTEM_CELL name='cell 3' colindex:3
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 3'
-++++++ROLE_SYSTEM_CELL colindex:4
+++++++ROLE_SYSTEM_CELL name='cell 4' colindex:4
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 4'
-++++++ROLE_SYSTEM_CELL colindex:5
+++++++ROLE_SYSTEM_CELL name='cell 5' colindex:5
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 5'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
-++++IA2_ROLE_SECTION
\ No newline at end of file
+++++IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/aria/aria-columnheader-expected-mac.txt b/content/test/data/accessibility/aria/aria-columnheader-expected-mac.txt
index 9eece0b7..7c778711 100644
--- a/content/test/data/accessibility/aria/aria-columnheader-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-columnheader-expected-mac.txt
@@ -1,19 +1,19 @@
 AXWebArea
 ++AXTable
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Browser'
 ++++++++AXStaticText AXValue='Browser'
-++++++AXCell
+++++++AXCell AXTitle='Rendering Engine'
 ++++++++AXStaticText AXValue='Rendering Engine'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Chrome'
 ++++++++AXStaticText AXValue='Chrome'
-++++++AXCell
+++++++AXCell AXTitle='Blink'
 ++++++++AXStaticText AXValue='Blink'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Safari'
 ++++++++AXStaticText AXValue='Safari'
-++++++AXCell
+++++++AXCell AXTitle='WebKit'
 ++++++++AXStaticText AXValue='WebKit'
 ++++AXColumn
 ++++AXColumn
diff --git a/content/test/data/accessibility/aria/aria-columnheader-expected-win.txt b/content/test/data/accessibility/aria/aria-columnheader-expected-win.txt
index c525009..73aa51a 100644
--- a/content/test/data/accessibility/aria/aria-columnheader-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-columnheader-expected-win.txt
@@ -1,19 +1,19 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Browser'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser'
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Rendering Engine'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Chrome'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Chrome'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Blink'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Safari'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Safari'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='WebKit'
 ++++++++ROLE_SYSTEM_STATICTEXT name='WebKit'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
diff --git a/content/test/data/accessibility/aria/aria-describedby-expected-mac.txt b/content/test/data/accessibility/aria/aria-describedby-expected-mac.txt
index f3679c4..9a2ba2b 100644
--- a/content/test/data/accessibility/aria/aria-describedby-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-describedby-expected-mac.txt
@@ -1,4 +1,4 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXTextField AXRoleDescription='text field' AXHelp='Your username should be your email id'
-++AXGroup AXSubrole=AXUserInterfaceTooltip AXRoleDescription='tooltip'
+++AXGroup AXSubrole=AXUserInterfaceTooltip AXRoleDescription='tooltip' AXTitle='Your username should be your email id'
 ++++AXStaticText AXRoleDescription='text' AXValue='Your username should be your email id'
diff --git a/content/test/data/accessibility/aria/aria-grid-expected-mac.txt b/content/test/data/accessibility/aria/aria-grid-expected-mac.txt
index 154ff32..68f4871 100644
--- a/content/test/data/accessibility/aria/aria-grid-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-grid-expected-mac.txt
@@ -1,14 +1,14 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXTable AXRoleDescription='table'
 ++++AXRow AXRoleDescription='row'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Browser'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Browser'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Rendering Engine'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Rendering Engine'
 ++++AXRow AXRoleDescription='row'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Chrome'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Chrome'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Blink'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Blink'
 ++++AXColumn AXRoleDescription='column'
 ++++AXColumn AXRoleDescription='column'
diff --git a/content/test/data/accessibility/aria/aria-grid-expected-win.txt b/content/test/data/accessibility/aria/aria-grid-expected-win.txt
index 1f2879d4..bdc2eaec 100644
--- a/content/test/data/accessibility/aria/aria-grid-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-grid-expected-win.txt
@@ -1,14 +1,14 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE MULTISELECTABLE EXTSELECTABLE xml-roles:grid
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+++++++ROLE_SYSTEM_COLUMNHEADER name='Browser' xml-roles:columnheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser'
-++++++ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+++++++ROLE_SYSTEM_COLUMNHEADER name='Rendering Engine' xml-roles:columnheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Chrome' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Chrome'
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Blink' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
diff --git a/content/test/data/accessibility/aria/aria-gridcell-expected-mac.txt b/content/test/data/accessibility/aria/aria-gridcell-expected-mac.txt
index 154ff32..68f4871 100644
--- a/content/test/data/accessibility/aria/aria-gridcell-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-gridcell-expected-mac.txt
@@ -1,14 +1,14 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXTable AXRoleDescription='table'
 ++++AXRow AXRoleDescription='row'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Browser'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Browser'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Rendering Engine'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Rendering Engine'
 ++++AXRow AXRoleDescription='row'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Chrome'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Chrome'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Blink'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Blink'
 ++++AXColumn AXRoleDescription='column'
 ++++AXColumn AXRoleDescription='column'
diff --git a/content/test/data/accessibility/aria/aria-gridcell-expected-win.txt b/content/test/data/accessibility/aria/aria-gridcell-expected-win.txt
index 1f2879d4..bdc2eaec 100644
--- a/content/test/data/accessibility/aria/aria-gridcell-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-gridcell-expected-win.txt
@@ -1,14 +1,14 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE MULTISELECTABLE EXTSELECTABLE xml-roles:grid
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+++++++ROLE_SYSTEM_COLUMNHEADER name='Browser' xml-roles:columnheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser'
-++++++ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+++++++ROLE_SYSTEM_COLUMNHEADER name='Rendering Engine' xml-roles:columnheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Chrome' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Chrome'
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Blink' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
diff --git a/content/test/data/accessibility/aria/aria-level-expected-mac.txt b/content/test/data/accessibility/aria/aria-level-expected-mac.txt
index 6f6864e..f7bcd46 100644
--- a/content/test/data/accessibility/aria/aria-level-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-level-expected-mac.txt
@@ -22,10 +22,10 @@
 ++++++AXStaticText AXValue='Tree item at level 3'
 ++AXTable
 ++++AXRow AXDisclosureLevel='0'
-++++++AXCell
+++++++AXCell AXTitle='Cell at level 1'
 ++++++++AXStaticText AXValue='Cell at level 1'
 ++++AXRow AXDisclosureLevel='1'
-++++++AXCell
+++++++AXCell AXTitle='Cell at level 2'
 ++++++++AXStaticText AXValue='Cell at level 2'
 ++++AXColumn
 ++++AXGroup
diff --git a/content/test/data/accessibility/aria/aria-level-expected-win.txt b/content/test/data/accessibility/aria/aria-level-expected-win.txt
index 36eb8126..b10d0bb 100644
--- a/content/test/data/accessibility/aria/aria-level-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-level-expected-win.txt
@@ -22,10 +22,10 @@
 ++++++ROLE_SYSTEM_STATICTEXT name='Tree item at level 3'
 ++ROLE_SYSTEM_OUTLINE
 ++++ROLE_SYSTEM_ROW level:1
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Cell at level 1'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Cell at level 1'
 ++++ROLE_SYSTEM_ROW level:2
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Cell at level 2'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Cell at level 2'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/aria/aria-row-attr-expected-blink.txt b/content/test/data/accessibility/aria/aria-row-attr-expected-blink.txt
index 10f2ad99..f95baaf 100644
--- a/content/test/data/accessibility/aria/aria-row-attr-expected-blink.txt
+++ b/content/test/data/accessibility/aria/aria-row-attr-expected-blink.txt
@@ -1,24 +1,23 @@
 rootWebArea
 ++table ariaRowCount=5
 ++++row
-++++++columnHeader ariaRowIndex=3
+++++++columnHeader name='cell 2' ariaRowIndex=3
 ++++++++staticText name='cell 2'
 ++++++++++inlineTextBox name='cell 2'
-++++++columnHeader ariaRowIndex=3
+++++++columnHeader name='cell 3' ariaRowIndex=3
 ++++++++staticText name='cell 3'
 ++++++++++inlineTextBox name='cell 3'
-++++++columnHeader ariaRowIndex=3
+++++++columnHeader name='cell 4' ariaRowIndex=3
 ++++++++staticText name='cell 4'
 ++++++++++inlineTextBox name='cell 4'
 ++++row ariaRowIndex=4
-++++++cell ariaRowIndex=4
+++++++cell name='cell 2' ariaRowIndex=4
 ++++++++staticText name='cell 2'
 ++++++++++inlineTextBox name='cell 2'
-++++++cell ariaRowIndex=4
+++++++cell name='cell 3' ariaRowIndex=4
 ++++++++staticText name='cell 3'
 ++++++++++inlineTextBox name='cell 3'
 ++++column
 ++++column
 ++++column
 ++++tableHeaderContainer
-<-- End-of-file -->
\ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-row-attr-expected-mac.txt b/content/test/data/accessibility/aria/aria-row-attr-expected-mac.txt
index ae87e0d..a4fc45e 100644
--- a/content/test/data/accessibility/aria/aria-row-attr-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-row-attr-expected-mac.txt
@@ -1,18 +1,18 @@
 AXWebArea
 ++AXTable AXARIARowCount='5'
 ++++AXRow
-++++++AXCell AXARIARowIndex='3'
+++++++AXCell AXTitle='cell 2' AXARIARowIndex='3'
 ++++++++AXStaticText AXValue='cell 2'
-++++++AXCell AXARIARowIndex='3'
+++++++AXCell AXTitle='cell 3' AXARIARowIndex='3'
 ++++++++AXStaticText AXValue='cell 3'
-++++++AXCell AXARIARowIndex='3'
+++++++AXCell AXTitle='cell 4' AXARIARowIndex='3'
 ++++++++AXStaticText AXValue='cell 4'
 ++++AXRow
-++++++AXCell AXARIARowIndex='4'
+++++++AXCell AXTitle='cell 2' AXARIARowIndex='4'
 ++++++++AXStaticText AXValue='cell 2'
-++++++AXCell AXARIARowIndex='4'
+++++++AXCell AXTitle='cell 3' AXARIARowIndex='4'
 ++++++++AXStaticText AXValue='cell 3'
 ++++AXColumn
 ++++AXColumn
 ++++AXColumn
-++++AXGroup
\ No newline at end of file
+++++AXGroup
diff --git a/content/test/data/accessibility/aria/aria-row-attr-expected-win.txt b/content/test/data/accessibility/aria/aria-row-attr-expected-win.txt
index a606e21..ce05adc 100644
--- a/content/test/data/accessibility/aria/aria-row-attr-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-row-attr-expected-win.txt
@@ -1,18 +1,18 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE rowcount:5
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER rowindex:3
+++++++ROLE_SYSTEM_COLUMNHEADER name='cell 2' rowindex:3
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 2'
-++++++ROLE_SYSTEM_COLUMNHEADER rowindex:3
+++++++ROLE_SYSTEM_COLUMNHEADER name='cell 3' rowindex:3
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 3'
-++++++ROLE_SYSTEM_COLUMNHEADER rowindex:3 rowspan:2
+++++++ROLE_SYSTEM_COLUMNHEADER name='cell 4' rowindex:3 rowspan:2
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 4'
 ++++ROLE_SYSTEM_ROW rowindex:4
-++++++ROLE_SYSTEM_CELL rowindex:4
+++++++ROLE_SYSTEM_CELL name='cell 2' rowindex:4
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 2'
-++++++ROLE_SYSTEM_CELL rowindex:4
+++++++ROLE_SYSTEM_CELL name='cell 3' rowindex:4
 ++++++++ROLE_SYSTEM_STATICTEXT name='cell 3'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
-++++IA2_ROLE_SECTION
\ No newline at end of file
+++++IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/aria/aria-row-expected-mac.txt b/content/test/data/accessibility/aria/aria-row-expected-mac.txt
index 9eece0b7..7c778711 100644
--- a/content/test/data/accessibility/aria/aria-row-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-row-expected-mac.txt
@@ -1,19 +1,19 @@
 AXWebArea
 ++AXTable
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Browser'
 ++++++++AXStaticText AXValue='Browser'
-++++++AXCell
+++++++AXCell AXTitle='Rendering Engine'
 ++++++++AXStaticText AXValue='Rendering Engine'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Chrome'
 ++++++++AXStaticText AXValue='Chrome'
-++++++AXCell
+++++++AXCell AXTitle='Blink'
 ++++++++AXStaticText AXValue='Blink'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Safari'
 ++++++++AXStaticText AXValue='Safari'
-++++++AXCell
+++++++AXCell AXTitle='WebKit'
 ++++++++AXStaticText AXValue='WebKit'
 ++++AXColumn
 ++++AXColumn
diff --git a/content/test/data/accessibility/aria/aria-row-expected-win.txt b/content/test/data/accessibility/aria/aria-row-expected-win.txt
index c525009..73aa51a 100644
--- a/content/test/data/accessibility/aria/aria-row-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-row-expected-win.txt
@@ -1,19 +1,19 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Browser'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser'
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Rendering Engine'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Chrome'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Chrome'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Blink'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Safari'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Safari'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='WebKit'
 ++++++++ROLE_SYSTEM_STATICTEXT name='WebKit'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
diff --git a/content/test/data/accessibility/aria/aria-rowheader-expected-mac.txt b/content/test/data/accessibility/aria/aria-rowheader-expected-mac.txt
index 684c184..5b6be0fa 100644
--- a/content/test/data/accessibility/aria/aria-rowheader-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-rowheader-expected-mac.txt
@@ -1,18 +1,18 @@
 AXWebArea
 ++AXTable
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Browser'
 ++++++++AXStaticText AXValue='Browser'
-++++++AXCell
+++++++AXCell AXTitle='Chrome'
 ++++++++AXStaticText AXValue='Chrome'
-++++++AXCell
+++++++AXCell AXTitle='Safari'
 ++++++++AXStaticText AXValue='Safari'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Rendering Engine'
 ++++++++AXStaticText AXValue='Rendering Engine'
-++++++AXCell
+++++++AXCell AXTitle='Blink'
 ++++++++AXStaticText AXValue='Blink'
-++++++AXCell
+++++++AXCell AXTitle='WebKit'
 ++++++++AXStaticText AXValue='WebKit'
 ++++AXColumn
 ++++AXColumn
diff --git a/content/test/data/accessibility/aria/aria-rowheader-expected-win.txt b/content/test/data/accessibility/aria/aria-rowheader-expected-win.txt
index 428128dd..07aeb41 100644
--- a/content/test/data/accessibility/aria/aria-rowheader-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-rowheader-expected-win.txt
@@ -1,18 +1,18 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE MULTISELECTABLE EXTSELECTABLE xml-roles:grid
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_ROWHEADER xml-roles:rowheader
+++++++ROLE_SYSTEM_ROWHEADER name='Browser' xml-roles:rowheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser'
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Chrome' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Chrome'
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Safari' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Safari'
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_ROWHEADER xml-roles:rowheader
+++++++ROLE_SYSTEM_ROWHEADER name='Rendering Engine' xml-roles:rowheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Blink' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='WebKit' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='WebKit'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
diff --git a/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-mac.txt b/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-mac.txt
index f8ed8f56..b4b49bd 100644
--- a/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-mac.txt
@@ -1,71 +1,71 @@
 AXWebArea
 ++AXTable
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell AXSortDirection='AXAscendingSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXAscendingSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell AXSortDirection='AXDescendingSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXDescendingSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXColumn
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell AXSortDirection='AXUnknownSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXUnknownSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXColumn
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXColumn
@@ -73,11 +73,11 @@
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXColumn
@@ -85,11 +85,11 @@
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell AXSortDirection='AXAscendingSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXAscendingSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXColumn
@@ -97,11 +97,11 @@
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell AXSortDirection='AXDescendingSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXDescendingSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXColumn
 ++++AXColumn
@@ -109,11 +109,11 @@
 ++++AXGroup
 ++AXTable
 ++++AXRow
-++++++AXCell AXSortDirection='AXUnknownSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXUnknownSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXColumn
 ++++AXColumn
diff --git a/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-win.txt b/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-win.txt
index 0ccd7be..fccb5168 100644
--- a/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-sort-aria-grid-expected-win.txt
@@ -1,71 +1,71 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER sort:none
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet' sort:none
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER sort:ascending
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet' sort:ascending
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER sort:descending
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet' sort:descending
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER sort:other
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet' sort:other
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -73,11 +73,11 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER sort:none
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet' sort:none
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -85,11 +85,11 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER sort:ascending
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet' sort:ascending
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -97,11 +97,11 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER sort:descending
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet' sort:descending
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -109,11 +109,11 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER sort:other
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet' sort:other
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
diff --git a/content/test/data/accessibility/aria/aria-sort-html-table-expected-mac.txt b/content/test/data/accessibility/aria/aria-sort-html-table-expected-mac.txt
index f715133..f784e68 100644
--- a/content/test/data/accessibility/aria/aria-sort-html-table-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-sort-html-table-expected-mac.txt
@@ -1,71 +1,71 @@
 AXWebArea
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell AXSortDirection='AXAscendingSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXAscendingSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell AXSortDirection='AXDescendingSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXDescendingSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXColumn
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell AXSortDirection='AXUnknownSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXUnknownSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXColumn
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXColumn
@@ -73,11 +73,11 @@
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXColumn
@@ -85,11 +85,11 @@
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell AXSortDirection='AXAscendingSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXAscendingSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXColumn
@@ -97,11 +97,11 @@
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell AXSortDirection='AXDescendingSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXDescendingSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXColumn
 ++++AXColumn
@@ -109,11 +109,11 @@
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell AXSortDirection='AXUnknownSortDirection'
+++++++AXCell AXTitle='Alphabet' AXSortDirection='AXUnknownSortDirection'
 ++++++++AXStaticText AXValue='Alphabet'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXColumn
 ++++AXColumn
@@ -121,13 +121,13 @@
 ++++AXGroup
 ++AXTable AXDescription='Data table'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Alphabet'
 ++++++++AXStaticText AXValue='Alphabet'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='A'
 ++++++++AXStaticText AXValue='A'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='B'
 ++++++++AXStaticText AXValue='B'
 ++++AXColumn
 ++++AXGroup
diff --git a/content/test/data/accessibility/aria/aria-sort-html-table-expected-win.txt b/content/test/data/accessibility/aria/aria-sort-html-table-expected-win.txt
index 06acd42..3111d24 100644
--- a/content/test/data/accessibility/aria/aria-sort-html-table-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-sort-html-table-expected-win.txt
@@ -1,71 +1,71 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER sort:none
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet' sort:none
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER sort:ascending
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet' sort:ascending
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER sort:descending
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet' sort:descending
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER sort:other
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet' sort:other
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -73,11 +73,11 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER sort:none
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet' sort:none
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -85,11 +85,11 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER sort:ascending
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet' sort:ascending
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -97,11 +97,11 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER sort:descending
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet' sort:descending
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -109,11 +109,11 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_ROWHEADER sort:other
+++++++ROLE_SYSTEM_ROWHEADER name='Alphabet' sort:other
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
@@ -121,13 +121,13 @@
 ++++IA2_ROLE_SECTION
 ++ROLE_SYSTEM_TABLE name='Data table'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Alphabet'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Alphabet'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='A'
 ++++++++ROLE_SYSTEM_STATICTEXT name='A'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='B'
 ++++++++ROLE_SYSTEM_STATICTEXT name='B'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/aria/aria-table-expected-mac.txt b/content/test/data/accessibility/aria/aria-table-expected-mac.txt
index bf295d1..f49c8b6d 100644
--- a/content/test/data/accessibility/aria/aria-table-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-table-expected-mac.txt
@@ -1,12 +1,12 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXTable AXRoleDescription='table'
 ++++AXRow AXRoleDescription='row'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Browser'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Browser'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Rendering Engine'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Rendering Engine'
 ++++AXRow AXRoleDescription='row'
-++++++AXCell AXRoleDescription='cell'
+++++++AXCell AXRoleDescription='cell' AXTitle='Chrome'
 ++++++++AXStaticText AXRoleDescription='text' AXValue='Chrome'
-++++++AXCell AXRoleDescription='cell'
-++++++++AXStaticText AXRoleDescription='text' AXValue='Blink'
\ No newline at end of file
+++++++AXCell AXRoleDescription='cell' AXTitle='Blink'
+++++++++AXStaticText AXRoleDescription='text' AXValue='Blink'
diff --git a/content/test/data/accessibility/aria/aria-table-expected-win.txt b/content/test/data/accessibility/aria/aria-table-expected-win.txt
index 42b593d..79ffc24 100644
--- a/content/test/data/accessibility/aria/aria-table-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-table-expected-win.txt
@@ -1,12 +1,12 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_TABLE xml-roles:table
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+++++++ROLE_SYSTEM_COLUMNHEADER name='Browser' xml-roles:columnheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser'
-++++++ROLE_SYSTEM_COLUMNHEADER xml-roles:columnheader
+++++++ROLE_SYSTEM_COLUMNHEADER name='Rendering Engine' xml-roles:columnheader
 ++++++++ROLE_SYSTEM_STATICTEXT name='Rendering Engine'
 ++++ROLE_SYSTEM_ROW xml-roles:row
-++++++ROLE_SYSTEM_CELL xml-roles:cell
+++++++ROLE_SYSTEM_CELL name='Chrome' xml-roles:cell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Chrome'
-++++++ROLE_SYSTEM_CELL xml-roles:cell
-++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
\ No newline at end of file
+++++++ROLE_SYSTEM_CELL name='Blink' xml-roles:cell
+++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
diff --git a/content/test/data/accessibility/aria/aria-tooltip-expected-mac.txt b/content/test/data/accessibility/aria/aria-tooltip-expected-mac.txt
index f3679c4..9a2ba2b 100644
--- a/content/test/data/accessibility/aria/aria-tooltip-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-tooltip-expected-mac.txt
@@ -1,4 +1,4 @@
 AXWebArea AXRoleDescription='HTML content'
 ++AXTextField AXRoleDescription='text field' AXHelp='Your username should be your email id'
-++AXGroup AXSubrole=AXUserInterfaceTooltip AXRoleDescription='tooltip'
+++AXGroup AXSubrole=AXUserInterfaceTooltip AXRoleDescription='tooltip' AXTitle='Your username should be your email id'
 ++++AXStaticText AXRoleDescription='text' AXValue='Your username should be your email id'
diff --git a/content/test/data/accessibility/aria/aria-treegrid-expected-mac.txt b/content/test/data/accessibility/aria/aria-treegrid-expected-mac.txt
index ab14a45..feee33b 100644
--- a/content/test/data/accessibility/aria/aria-treegrid-expected-mac.txt
+++ b/content/test/data/accessibility/aria/aria-treegrid-expected-mac.txt
@@ -1,10 +1,10 @@
 AXWebArea
 ++AXTable
 ++++AXRow AXDisclosureLevel='0'
-++++++AXCell
+++++++AXCell AXTitle='Cell at level 1'
 ++++++++AXStaticText AXValue='Cell at level 1'
 ++++AXRow AXDisclosureLevel='1'
-++++++AXCell
+++++++AXCell AXTitle='Cell at level 2'
 ++++++++AXStaticText AXValue='Cell at level 2'
 ++++AXColumn
 ++++AXGroup
diff --git a/content/test/data/accessibility/aria/aria-treegrid-expected-win.txt b/content/test/data/accessibility/aria/aria-treegrid-expected-win.txt
index cf9f17d..d9d10f540 100644
--- a/content/test/data/accessibility/aria/aria-treegrid-expected-win.txt
+++ b/content/test/data/accessibility/aria/aria-treegrid-expected-win.txt
@@ -1,10 +1,10 @@
 ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE
 ++ROLE_SYSTEM_OUTLINE xml-roles:treegrid
 ++++ROLE_SYSTEM_ROW xml-roles:row level:1
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Cell at level 1' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Cell at level 1'
 ++++ROLE_SYSTEM_ROW xml-roles:row level:2
-++++++ROLE_SYSTEM_CELL xml-roles:gridcell
+++++++ROLE_SYSTEM_CELL name='Cell at level 2' xml-roles:gridcell
 ++++++++ROLE_SYSTEM_STATICTEXT name='Cell at level 2'
 ++++ROLE_SYSTEM_COLUMN
 ++++IA2_ROLE_SECTION
diff --git a/content/test/data/accessibility/html/caption-expected-mac.txt b/content/test/data/accessibility/html/caption-expected-mac.txt
index 6ee2ad08..b2f5230 100644
--- a/content/test/data/accessibility/html/caption-expected-mac.txt
+++ b/content/test/data/accessibility/html/caption-expected-mac.txt
@@ -3,19 +3,19 @@
 ++++AXGroup
 ++++++AXStaticText AXValue='Browser and Engine'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Browser'
 ++++++++AXStaticText AXValue='Browser'
-++++++AXCell
+++++++AXCell AXTitle='Engine'
 ++++++++AXStaticText AXValue='Engine'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Chrome'
 ++++++++AXStaticText AXValue='Chrome'
-++++++AXCell
+++++++AXCell AXTitle='Blink'
 ++++++++AXStaticText AXValue='Blink'
 ++++AXRow
-++++++AXCell
+++++++AXCell AXTitle='Safari'
 ++++++++AXStaticText AXValue='Safari'
-++++++AXCell
+++++++AXCell AXTitle='WebKit'
 ++++++++AXStaticText AXValue='WebKit'
 ++++AXColumn
 ++++AXColumn
diff --git a/content/test/data/accessibility/html/caption-expected-win.txt b/content/test/data/accessibility/html/caption-expected-win.txt
index e8c876e..140d5f1 100644
--- a/content/test/data/accessibility/html/caption-expected-win.txt
+++ b/content/test/data/accessibility/html/caption-expected-win.txt
@@ -3,19 +3,19 @@
 ++++IA2_ROLE_CAPTION
 ++++++ROLE_SYSTEM_STATICTEXT name='Browser and Engine'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Browser'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Browser'
-++++++ROLE_SYSTEM_COLUMNHEADER
+++++++ROLE_SYSTEM_COLUMNHEADER name='Engine'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Engine'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Chrome'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Chrome'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Blink'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Blink'
 ++++ROLE_SYSTEM_ROW
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='Safari'
 ++++++++ROLE_SYSTEM_STATICTEXT name='Safari'
-++++++ROLE_SYSTEM_CELL
+++++++ROLE_SYSTEM_CELL name='WebKit'
 ++++++++ROLE_SYSTEM_STATICTEXT name='WebKit'
 ++++ROLE_SYSTEM_COLUMN
 ++++ROLE_SYSTEM_COLUMN
diff --git a/content/test/data/accessibility/html/contenteditable-descendants-expected-win.txt b/content/test/data/accessibility/html/contenteditable-descendants-expected-win.txt
index 9156a30..3d942d8 100644
--- a/content/test/data/accessibility/html/contenteditable-descendants-expected-win.txt
+++ b/content/test/data/accessibility/html/contenteditable-descendants-expected-win.txt
@@ -11,7 +11,7 @@
 ++++++ROLE_SYSTEM_STATICTEXT name='.' IA2_STATE_EDITABLE ia2_hypertext='.' n_selections=0
 ++++ROLE_SYSTEM_TABLE IA2_STATE_EDITABLE ia2_hypertext='<obj0><obj1><obj2>' n_selections=0
 ++++++ROLE_SYSTEM_ROW IA2_STATE_EDITABLE ia2_hypertext='<obj0>' n_selections=0
-++++++++ROLE_SYSTEM_CELL IA2_STATE_EDITABLE ia2_hypertext='Always expose editable tables as tables.' n_selections=0
+++++++++ROLE_SYSTEM_CELL name='Always expose editable tables as tables.' IA2_STATE_EDITABLE ia2_hypertext='Always expose editable tables as tables.' n_selections=0
 ++++++++++ROLE_SYSTEM_STATICTEXT name='Always expose editable tables as tables.' IA2_STATE_EDITABLE ia2_hypertext='Always expose editable tables as tables.' n_selections=0
 ++++++ROLE_SYSTEM_COLUMN n_selections=0
 ++++++IA2_ROLE_SECTION n_selections=0
diff --git a/content/test/data/accessibility/html/contenteditable-descendants-with-selection-expected-win.txt b/content/test/data/accessibility/html/contenteditable-descendants-with-selection-expected-win.txt
index eea73dd..97adec5 100644
--- a/content/test/data/accessibility/html/contenteditable-descendants-with-selection-expected-win.txt
+++ b/content/test/data/accessibility/html/contenteditable-descendants-with-selection-expected-win.txt
@@ -11,7 +11,7 @@
 ++++++ROLE_SYSTEM_STATICTEXT name='.' IA2_STATE_EDITABLE ia2_hypertext='.' n_selections=1 selection_start=0 selection_end=1
 ++++ROLE_SYSTEM_TABLE IA2_STATE_EDITABLE ia2_hypertext='<obj0><obj1><obj2>' n_selections=1 selection_start=0 selection_end=3
 ++++++ROLE_SYSTEM_ROW IA2_STATE_EDITABLE ia2_hypertext='<obj0>' n_selections=1 selection_start=0 selection_end=1
-++++++++ROLE_SYSTEM_CELL IA2_STATE_EDITABLE ia2_hypertext='Always expose editable tables as tables.' n_selections=1 selection_start=0 selection_end=40
+++++++++ROLE_SYSTEM_CELL name='Always expose editable tables as tables.' IA2_STATE_EDITABLE ia2_hypertext='Always expose editable tables as tables.' n_selections=1 selection_start=0 selection_end=40
 ++++++++++ROLE_SYSTEM_STATICTEXT name='Always expose editable tables as tables.' IA2_STATE_EDITABLE ia2_hypertext='Always expose editable tables as tables.' n_selections=1 selection_start=0 selection_end=40
 ++++++ROLE_SYSTEM_COLUMN n_selections=0
 ++++++IA2_ROLE_SECTION n_selections=0
diff --git a/content/test/data/accessibility/html/table-simple-expected-mac.txt b/content/test/data/accessibility/html/table-simple-expected-mac.txt
index 8c220d5..753a23d 100644
--- a/content/test/data/accessibility/html/table-simple-expected-mac.txt
+++ b/content/test/data/accessibility/html/table-simple-expected-mac.txt
@@ -1,19 +1,19 @@
 AXWebArea AXTitle='Table example'
 ++AXTable
 ++++AXRow AXIndex='0'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":0}
+++++++AXCell AXTitle='Pair' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":0}
 ++++++++AXStaticText AXValue='Pair'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
+++++++AXCell AXTitle='Single' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
 ++++++++AXStaticText AXValue='Single'
 ++++AXRow AXIndex='1'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='AB' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='AB'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='B' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='B'
 ++++AXRow AXIndex='2'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":2}
+++++++AXCell AXTitle='CD' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":2}
 ++++++++AXStaticText AXValue='CD'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":2}
+++++++AXCell AXTitle='D' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":2}
 ++++++++AXStaticText AXValue='D'
 ++++AXColumn AXIndex='0'
 ++++AXColumn AXIndex='1'
diff --git a/content/test/data/accessibility/html/table-spans-expected-mac.txt b/content/test/data/accessibility/html/table-spans-expected-mac.txt
index ddec6f6..2b0832cd 100644
--- a/content/test/data/accessibility/html/table-spans-expected-mac.txt
+++ b/content/test/data/accessibility/html/table-spans-expected-mac.txt
@@ -1,26 +1,26 @@
 AXWebArea AXTitle='Table example with rowspan and colspan'
 ++AXTable
 ++++AXRow AXIndex='0'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":2,"loc":0}
+++++++AXCell AXTitle='AD' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":2,"loc":0}
 ++++++++AXStaticText AXValue='AD'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
+++++++AXCell AXTitle='BC' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
 ++++++++AXStaticText AXValue='BC'
 ++++AXRow AXIndex='1'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='EF' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='EF'
 ++++AXColumn AXIndex='0'
 ++++AXColumn AXIndex='1'
 ++++AXGroup
 ++AXTable
 ++++AXRow AXIndex='0'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":2,"loc":0}
+++++++AXCell AXTitle='AD' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":2,"loc":0}
 ++++++++AXStaticText AXValue='AD'
-++++++AXCell AXColumnIndexRange={"len":2,"loc":1} AXRowIndexRange={"len":1,"loc":0}
+++++++AXCell AXTitle='BC' AXColumnIndexRange={"len":2,"loc":1} AXRowIndexRange={"len":1,"loc":0}
 ++++++++AXStaticText AXValue='BC'
 ++++AXRow AXIndex='1'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='EF' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='EF'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":2} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='GH' AXColumnIndexRange={"len":1,"loc":2} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='GH'
 ++++AXColumn AXIndex='0'
 ++++AXColumn AXIndex='1'
diff --git a/content/test/data/accessibility/html/table-th-rowheader-expected-mac.txt b/content/test/data/accessibility/html/table-th-rowheader-expected-mac.txt
index a9d70884..8c5481a 100644
--- a/content/test/data/accessibility/html/table-th-rowheader-expected-mac.txt
+++ b/content/test/data/accessibility/html/table-th-rowheader-expected-mac.txt
@@ -1,14 +1,14 @@
 AXWebArea AXTitle='Table example - th rowheader'
 ++AXTable
 ++++AXRow AXIndex='0'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":0}
+++++++AXCell AXTitle='Firstname' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":0}
 ++++++++AXStaticText AXValue='Firstname'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
+++++++AXCell AXTitle='Jill' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
 ++++++++AXStaticText AXValue='Jill'
 ++++AXRow AXIndex='1'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='Lastname' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='Lastname'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='Smith' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='Smith'
 ++++AXColumn AXIndex='0'
 ++++AXColumn AXIndex='1'
diff --git a/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-mac.txt b/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-mac.txt
index 4cb9990..3b6faa3 100644
--- a/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-mac.txt
+++ b/content/test/data/accessibility/html/table-thead-tbody-tfoot-expected-mac.txt
@@ -1,24 +1,24 @@
 AXWebArea AXTitle='Table example - thead, tbody, tfoot'
 ++AXTable
 ++++AXRow AXIndex='0'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":0}
+++++++AXCell AXTitle='Sum' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":0}
 ++++++++AXStaticText AXValue='Sum'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
+++++++AXCell AXTitle='Subtraction' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":0}
 ++++++++AXStaticText AXValue='Subtraction'
 ++++AXRow AXIndex='1'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='10' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='10'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
+++++++AXCell AXTitle='7' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":1}
 ++++++++AXStaticText AXValue='7'
 ++++AXRow AXIndex='2'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":2}
+++++++AXCell AXTitle='2' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":2}
 ++++++++AXStaticText AXValue='2'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":2}
+++++++AXCell AXTitle='4' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":2}
 ++++++++AXStaticText AXValue='4'
 ++++AXRow AXIndex='3'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":3}
+++++++AXCell AXTitle='12' AXColumnIndexRange={"len":1,"loc":0} AXRowIndexRange={"len":1,"loc":3}
 ++++++++AXStaticText AXValue='12'
-++++++AXCell AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":3}
+++++++AXCell AXTitle='3' AXColumnIndexRange={"len":1,"loc":1} AXRowIndexRange={"len":1,"loc":3}
 ++++++++AXStaticText AXValue='3'
 ++++AXColumn AXIndex='0'
 ++++AXColumn AXIndex='1'
diff --git a/content/test/data/gpu/pixel_video_mp4.html b/content/test/data/gpu/pixel_video_mp4.html
index 2a2bf90..0346bfe2f 100644
--- a/content/test/data/gpu/pixel_video_mp4.html
+++ b/content/test/data/gpu/pixel_video_mp4.html
@@ -21,7 +21,11 @@
 function main()
 {
   video = document.getElementById("video");
-  video.addEventListener('canplaythrough', waitForFinish, true);
+  if (video.readyState >= 4) {
+    waitForFinish();
+  } else {
+    video.addEventListener('canplaythrough', waitForFinish, true);
+  }
 }
 
 function waitForFinish()
diff --git a/content/test/data/gpu/pixel_video_vp9.html b/content/test/data/gpu/pixel_video_vp9.html
index ee300f6..c183570 100644
--- a/content/test/data/gpu/pixel_video_vp9.html
+++ b/content/test/data/gpu/pixel_video_vp9.html
@@ -21,11 +21,16 @@
 function main()
 {
   video = document.getElementById("video");
-  video.addEventListener('canplaythrough', waitForFinish, true);
+  if (video.readyState >= 4) {
+    waitForFinish();
+  } else {
+    video.addEventListener('canplaythrough', waitForFinish, true);
+  }
 }
 
 function waitForFinish()
 {
+  console.log("readyState" + video.readyState);
   if (g_swapsBeforeAck == 0) {
     domAutomationController.setAutomationId(1);
     domAutomationController.send("SUCCESS");
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc
index 6d52ad2..83f0748 100644
--- a/extensions/browser/app_window/app_window.cc
+++ b/extensions/browser/app_window/app_window.cc
@@ -561,6 +561,10 @@
   return title;
 }
 
+bool AppWindow::HasCustomIcon() const {
+  return window_icon_url_.is_valid() || app_icon_url_.is_valid();
+}
+
 void AppWindow::SetAppIconUrl(const GURL& url) {
   // Avoid using any previous icons that were being downloaded.
   image_loader_ptr_factory_.InvalidateWeakPtrs();
@@ -595,7 +599,8 @@
   // Set the showInShelf=true window icon and add the app_icon_image_
   // as a badge. If the image is empty, set the default app icon placeholder
   // as the base image.
-  if (window_icon_url_.is_valid() && !app_icon_image_->image().IsEmpty()) {
+  if (window_icon_url_.is_valid() && app_icon_image_ &&
+      !app_icon_image_->image().IsEmpty()) {
     gfx::Image base_image =
         !image.IsEmpty()
             ? image
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h
index 6afc6aab..73072ef 100644
--- a/extensions/browser/app_window/app_window.h
+++ b/extensions/browser/app_window/app_window.h
@@ -360,6 +360,10 @@
   // unblock resource requests.
   void NotifyRenderViewReady();
 
+  // Returns true if window has custom icon in case either |window_icon_url_| or
+  // |app_icon_url_| is set. Custom icon may be not loaded yet.
+  bool HasCustomIcon() const;
+
   // Whether the app window wants to be alpha enabled.
   bool requested_alpha_enabled() const { return requested_alpha_enabled_; }
 
diff --git a/extensions/browser/renderer_startup_helper.cc b/extensions/browser/renderer_startup_helper.cc
index 4a309fa..30bd75ee 100644
--- a/extensions/browser/renderer_startup_helper.cc
+++ b/extensions/browser/renderer_startup_helper.cc
@@ -9,11 +9,13 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "extensions/browser/extension_function_dispatcher.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_util.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
 #include "extensions/common/extension_messages.h"
@@ -27,6 +29,27 @@
 
 namespace extensions {
 
+namespace {
+
+// Returns whether the |extension| should be loaded in the given
+// |browser_context|.
+bool IsExtensionVisibleToContext(const Extension& extension,
+                                 content::BrowserContext* browser_context) {
+  // Renderers don't need to know about themes.
+  if (extension.is_theme())
+    return false;
+
+  // Only extensions enabled in incognito mode should be loaded in an incognito
+  // renderer. However extensions which can't be enabled in the incognito mode
+  // (e.g. platform apps) should also be loaded in an incognito renderer to
+  // ensure connections from incognito tabs to such extensions work.
+  return !browser_context->IsOffTheRecord() ||
+         !util::CanBeIncognitoEnabled(&extension) ||
+         util::IsIncognitoEnabled(extension.id(), browser_context);
+}
+
+}  // namespace
+
 RendererStartupHelper::RendererStartupHelper(BrowserContext* browser_context)
     : browser_context_(browser_context) {
   DCHECK(browser_context);
@@ -102,6 +125,7 @@
 
   // Loaded extensions.
   std::vector<ExtensionMsg_Loaded_Params> loaded_extensions;
+  BrowserContext* renderer_context = process->GetBrowserContext();
   const ExtensionSet& extensions =
       ExtensionRegistry::Get(browser_context_)->enabled_extensions();
   for (const auto& ext : extensions) {
@@ -109,18 +133,20 @@
     DCHECK(base::ContainsKey(extension_process_map_, ext->id()));
     DCHECK(!base::ContainsKey(extension_process_map_[ext->id()], process));
 
-    // Renderers don't need to know about themes.
-    if (!ext->is_theme()) {
-      // TODO(kalman): Only include tab specific permissions for extension
-      // processes, no other process needs it, so it's mildly wasteful.
-      // I am not sure this is possible to know this here, at such a low
-      // level of the stack. Perhaps site isolation can help.
-      bool include_tab_permissions = true;
-      loaded_extensions.push_back(
-          ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions));
-      extension_process_map_[ext->id()].insert(process);
-    }
+    if (!IsExtensionVisibleToContext(*ext, renderer_context))
+      continue;
+
+    // TODO(kalman): Only include tab specific permissions for extension
+    // processes, no other process needs it, so it's mildly wasteful.
+    // I am not sure this is possible to know this here, at such a low
+    // level of the stack. Perhaps site isolation can help.
+    bool include_tab_permissions = true;
+    loaded_extensions.push_back(
+        ExtensionMsg_Loaded_Params(ext.get(), include_tab_permissions));
+    extension_process_map_[ext->id()].insert(process);
   }
+
+  // Activate pending extensions.
   process->Send(new ExtensionMsg_Loaded(loaded_extensions));
   auto iter = pending_active_extensions_.find(process);
   if (iter != pending_active_extensions_.end()) {
@@ -165,10 +191,7 @@
 #endif
   }
 
-  // Renderers don't need to know about themes. We also don't normally
-  // "activate" themes, but this could happen if someone tries to open a tab
-  // to the e.g. theme's manifest.
-  if (extension.is_theme())
+  if (!IsExtensionVisibleToContext(extension, process->GetBrowserContext()))
     return;
 
   if (base::ContainsKey(initialized_processes_, process)) {
@@ -190,7 +213,8 @@
   std::set<content::RenderProcessHost*>& loaded_process_set =
       extension_process_map_[extension.id()];
 
-  // Renderers don't need to know about themes.
+  // IsExtensionVisibleToContext() would filter out themes, but we choose to
+  // return early for performance reasons.
   if (extension.is_theme())
     return;
 
@@ -202,6 +226,8 @@
       1,
       ExtensionMsg_Loaded_Params(&extension, false /* no tab permissions */));
   for (content::RenderProcessHost* process : initialized_processes_) {
+    if (!IsExtensionVisibleToContext(extension, process->GetBrowserContext()))
+      continue;
     process->Send(new ExtensionMsg_Loaded(params));
     loaded_process_set.insert(process);
   }
diff --git a/extensions/browser/renderer_startup_helper_unittest.cc b/extensions/browser/renderer_startup_helper_unittest.cc
index 613ed84..2e92234 100644
--- a/extensions/browser/renderer_startup_helper_unittest.cc
+++ b/extensions/browser/renderer_startup_helper_unittest.cc
@@ -6,12 +6,16 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
+#include "components/crx_file/id_util.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/test/mock_render_process_host.h"
+#include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_registry_factory.h"
+#include "extensions/browser/extension_util.h"
 #include "extensions/browser/extensions_test.h"
+#include "extensions/browser/test_extensions_browser_client.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/extension_messages.h"
 
@@ -29,11 +33,14 @@
         ExtensionRegistryFactory::GetForBrowserContext(browser_context());
     render_process_host_ =
         base::MakeUnique<content::MockRenderProcessHost>(browser_context());
+    incognito_render_process_host_ =
+        base::MakeUnique<content::MockRenderProcessHost>(incognito_context());
     extension_ = CreateExtension("ext_1");
   }
 
   void TearDown() override {
     render_process_host_.reset();
+    incognito_render_process_host_.reset();
     helper_.reset();
     ExtensionsTest::TearDown();
   }
@@ -53,7 +60,7 @@
         content::NotificationService::NoDetails());
   }
 
-  scoped_refptr<Extension> CreateExtension(const std::string& extension_id) {
+  scoped_refptr<Extension> CreateExtension(const std::string& id_input) {
     std::unique_ptr<base::DictionaryValue> manifest =
         DictionaryBuilder()
             .Set("name", "extension")
@@ -61,13 +68,10 @@
             .Set("manifest_version", 2)
             .Set("version", "0.1")
             .Build();
-    return ExtensionBuilder()
-        .SetManifest(std::move(manifest))
-        .SetID(extension_id)
-        .Build();
+    return CreateExtension(id_input, std::move(manifest));
   }
 
-  scoped_refptr<Extension> CreateTheme(const std::string& extension_id) {
+  scoped_refptr<Extension> CreateTheme(const std::string& id_input) {
     std::unique_ptr<base::DictionaryValue> manifest =
         DictionaryBuilder()
             .Set("name", "theme")
@@ -76,10 +80,25 @@
             .Set("manifest_version", 2)
             .Set("version", "0.1")
             .Build();
-    return ExtensionBuilder()
-        .SetManifest(std::move(manifest))
-        .SetID(extension_id)
-        .Build();
+    return CreateExtension(id_input, std::move(manifest));
+  }
+
+  scoped_refptr<Extension> CreatePlatformApp(const std::string& id_input) {
+    std::unique_ptr<base::Value> background =
+        DictionaryBuilder()
+            .Set("scripts", ListBuilder().Append("background.js").Build())
+            .Build();
+    std::unique_ptr<base::DictionaryValue> manifest =
+        DictionaryBuilder()
+            .Set("name", "platform_app")
+            .Set("description", "a platform app")
+            .Set("app", DictionaryBuilder()
+                            .Set("background", std::move(background))
+                            .Build())
+            .Set("manifest_version", 2)
+            .Set("version", "0.1")
+            .Build();
+    return CreateExtension(id_input, std::move(manifest));
   }
 
   void AddExtensionToRegistry(scoped_refptr<Extension> extension) {
@@ -115,9 +134,20 @@
   std::unique_ptr<RendererStartupHelper> helper_;
   ExtensionRegistry* registry_;  // Weak.
   std::unique_ptr<content::MockRenderProcessHost> render_process_host_;
+  std::unique_ptr<content::MockRenderProcessHost>
+      incognito_render_process_host_;
   scoped_refptr<Extension> extension_;
 
  private:
+  scoped_refptr<Extension> CreateExtension(
+      const std::string& id_input,
+      std::unique_ptr<base::DictionaryValue> manifest) {
+    return ExtensionBuilder()
+        .SetManifest(std::move(manifest))
+        .SetID(crx_file::id_util::GenerateId(id_input))
+        .Build();
+  }
+
   DISALLOW_COPY_AND_ASSIGN(RendererStartupHelperTest);
 };
 
@@ -243,4 +273,94 @@
   EXPECT_FALSE(IsExtensionLoaded(*extension));
 }
 
+// Tests that only incognito-enabled extensions are loaded in an incognito
+// context.
+TEST_F(RendererStartupHelperTest, ExtensionInIncognitoRenderer) {
+  // Initialize the incognito renderer.
+  EXPECT_FALSE(IsProcessInitialized(incognito_render_process_host_.get()));
+  SimulateRenderProcessCreated(incognito_render_process_host_.get());
+  EXPECT_TRUE(IsProcessInitialized(incognito_render_process_host_.get()));
+
+  IPC::TestSink& sink = render_process_host_->sink();
+  IPC::TestSink& incognito_sink = incognito_render_process_host_->sink();
+
+  // Enable the extension. It should not be loaded in the initialized incognito
+  // renderer.
+  sink.ClearMessages();
+  incognito_sink.ClearMessages();
+  EXPECT_FALSE(util::IsIncognitoEnabled(extension_->id(), browser_context()));
+  EXPECT_FALSE(IsExtensionLoaded(*extension_));
+  AddExtensionToRegistry(extension_);
+  helper_->OnExtensionLoaded(*extension_);
+  EXPECT_EQ(0u, sink.message_count());
+  EXPECT_EQ(0u, incognito_sink.message_count());
+  EXPECT_TRUE(IsExtensionLoaded(*extension_));
+  EXPECT_FALSE(IsExtensionLoadedInProcess(
+      *extension_, incognito_render_process_host_.get()));
+  EXPECT_FALSE(
+      IsExtensionLoadedInProcess(*extension_, render_process_host_.get()));
+
+  // Initialize the normal renderer. The extension should get loaded in it.
+  sink.ClearMessages();
+  incognito_sink.ClearMessages();
+  EXPECT_FALSE(IsProcessInitialized(render_process_host_.get()));
+  SimulateRenderProcessCreated(render_process_host_.get());
+  EXPECT_TRUE(IsProcessInitialized(render_process_host_.get()));
+  EXPECT_TRUE(
+      IsExtensionLoadedInProcess(*extension_, render_process_host_.get()));
+  EXPECT_FALSE(IsExtensionLoadedInProcess(
+      *extension_, incognito_render_process_host_.get()));
+  // Multiple initialization messages including the extension load message
+  // should be dispatched to the non-incognito renderer.
+  EXPECT_LE(1u, sink.message_count());
+  EXPECT_EQ(0u, incognito_sink.message_count());
+
+  // Enable the extension in incognito mode. This will reload the extension.
+  sink.ClearMessages();
+  incognito_sink.ClearMessages();
+  ExtensionPrefs::Get(browser_context())
+      ->SetIsIncognitoEnabled(extension_->id(), true);
+  helper_->OnExtensionUnloaded(*extension_);
+  helper_->OnExtensionLoaded(*extension_);
+  EXPECT_TRUE(IsExtensionLoadedInProcess(*extension_,
+                                         incognito_render_process_host_.get()));
+  EXPECT_TRUE(
+      IsExtensionLoadedInProcess(*extension_, render_process_host_.get()));
+  // The extension would not have been unloaded from the incognito renderer
+  // since it wasn't loaded.
+  ASSERT_EQ(1u, incognito_sink.message_count());
+  EXPECT_EQ(ExtensionMsg_Loaded::ID, incognito_sink.GetMessageAt(0)->type());
+  // The extension would be first unloaded and then loaded from the normal
+  // renderer.
+  ASSERT_EQ(2u, sink.message_count());
+  EXPECT_EQ(ExtensionMsg_Unloaded::ID, sink.GetMessageAt(0)->type());
+  EXPECT_EQ(ExtensionMsg_Loaded::ID, sink.GetMessageAt(1)->type());
+}
+
+// Tests that platform apps are always loaded in an incognito renderer.
+TEST_F(RendererStartupHelperTest, PlatformAppInIncognitoRenderer) {
+  // Initialize the incognito renderer.
+  EXPECT_FALSE(IsProcessInitialized(incognito_render_process_host_.get()));
+  SimulateRenderProcessCreated(incognito_render_process_host_.get());
+  EXPECT_TRUE(IsProcessInitialized(incognito_render_process_host_.get()));
+
+  IPC::TestSink& incognito_sink = incognito_render_process_host_->sink();
+
+  scoped_refptr<Extension> platform_app(CreatePlatformApp("platform_app"));
+  ASSERT_TRUE(platform_app->is_platform_app());
+  EXPECT_FALSE(util::IsIncognitoEnabled(platform_app->id(), browser_context()));
+  EXPECT_FALSE(util::CanBeIncognitoEnabled(platform_app.get()));
+
+  // Enable the app. It should get loaded in the incognito renderer even though
+  // IsIncognitoEnabled returns false for it, since it can't be enabled for
+  // incognito.
+  incognito_sink.ClearMessages();
+  AddExtensionToRegistry(platform_app);
+  helper_->OnExtensionLoaded(*platform_app);
+  EXPECT_TRUE(IsExtensionLoadedInProcess(*platform_app,
+                                         incognito_render_process_host_.get()));
+  ASSERT_EQ(1u, incognito_sink.message_count());
+  EXPECT_EQ(ExtensionMsg_Loaded::ID, incognito_sink.GetMessageAt(0)->type());
+}
+
 }  // namespace extensions
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
index 5eefa17..b6412b6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
@@ -420,8 +420,6 @@
                           GLenum type,
                           GLsizei bufsize,
                           GLsizei* length,
-                          GLsizei* columns,
-                          GLsizei* rows,
                           void* pixels,
                           int32_t* success);
 error::Error DoReleaseShaderCompiler();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index d602360..f6e723d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -1687,13 +1687,11 @@
                                                        GLenum type,
                                                        GLsizei bufsize,
                                                        GLsizei* length,
-                                                       GLsizei* columns,
-                                                       GLsizei* rows,
                                                        void* pixels,
                                                        int32_t* success) {
   FlushErrors();
   glReadPixelsRobustANGLE(x, y, width, height, format, type, bufsize, length,
-                          columns, rows, pixels);
+                          pixels);
   *success = FlushErrors() ? 0 : 1;
   return error::kNoError;
 }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers.cc
index a1398ed..2989ccd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers.cc
@@ -859,11 +859,9 @@
 
   GLsizei bufsize = buffer_size;
   GLsizei length = 0;
-  GLsizei columns = 0;
-  GLsizei rows = 0;
   int32_t success = 0;
   error::Error error = DoReadPixels(x, y, width, height, format, type, bufsize,
-                                    &length, &columns, &rows, pixels, &success);
+                                    &length, pixels, &success);
   if (error != error::kNoError) {
     return error;
   }
@@ -886,8 +884,8 @@
 
   if (result) {
     result->success = success;
-    result->row_length = static_cast<uint32_t>(columns);
-    result->num_rows = static_cast<uint32_t>(rows);
+    result->row_length = static_cast<uint32_t>(width);
+    result->num_rows = static_cast<uint32_t>(height);
   }
 
   return error::kNoError;
diff --git a/ios/BUILD.gn b/ios/BUILD.gn
index 29356b2..7ba2d563 100644
--- a/ios/BUILD.gn
+++ b/ios/BUILD.gn
@@ -13,7 +13,6 @@
   # the overrides are never used.
   v8_extra_library_files = []
   v8_experimental_extra_library_files = []
-  v8_enable_inspector = true
   v8_enable_gdbjit = false
   v8_imminent_deprecation_warnings = false
 }
@@ -21,7 +20,6 @@
 # Prevent warnings for unused build args above.
 assert(v8_extra_library_files != 0)
 assert(v8_experimental_extra_library_files != 0)
-assert(v8_enable_inspector)
 assert(!v8_enable_gdbjit)
 assert(!v8_imminent_deprecation_warnings)
 
diff --git a/ios/clean/chrome/browser/ui/context_menu/BUILD.gn b/ios/clean/chrome/browser/ui/context_menu/BUILD.gn
index 90210f7..24307b6d 100644
--- a/ios/clean/chrome/browser/ui/context_menu/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/context_menu/BUILD.gn
@@ -14,7 +14,6 @@
 
   deps = [
     ":context_menu_ui",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/ui/browser_list",
     "//ios/shared/chrome/browser/ui/commands",
     "//ios/shared/chrome/browser/ui/coordinators",
diff --git a/ios/clean/chrome/browser/ui/ntp/BUILD.gn b/ios/clean/chrome/browser/ui/ntp/BUILD.gn
index 363e965..2def52c 100644
--- a/ios/clean/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/ntp/BUILD.gn
@@ -12,7 +12,6 @@
 
   deps = [
     ":ntp_ui",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/ui/coordinators",
   ]
 }
diff --git a/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
index 3be9962..5dfd67c 100644
--- a/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -5,7 +5,6 @@
 #import "ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.h"
 
 #import "ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -20,9 +19,6 @@
 
 - (void)start {
   self.viewController = [[NTPViewController alloc] init];
-  [self.context.baseViewController presentViewController:self.viewController
-                                                animated:self.context.animated
-                                              completion:nil];
   [super start];
 }
 
diff --git a/ios/clean/chrome/browser/ui/settings/BUILD.gn b/ios/clean/chrome/browser/ui/settings/BUILD.gn
index c2130b1..e5b4bf6 100644
--- a/ios/clean/chrome/browser/ui/settings/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/settings/BUILD.gn
@@ -14,7 +14,6 @@
     "//ios/chrome/browser/ui/settings",
     "//ios/clean/chrome/browser/ui/actions",
     "//ios/clean/chrome/browser/ui/commands",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/ui/browser_list",
     "//ios/shared/chrome/browser/ui/commands",
     "//ios/shared/chrome/browser/ui/coordinators",
diff --git a/ios/clean/chrome/browser/ui/settings/settings_coordinator.mm b/ios/clean/chrome/browser/ui/settings/settings_coordinator.mm
index 4b6e6ed..b01ca7f8 100644
--- a/ios/clean/chrome/browser/ui/settings/settings_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/settings/settings_coordinator.mm
@@ -6,7 +6,6 @@
 
 #import "ios/chrome/browser/ui/settings/settings_navigation_controller.h"
 #import "ios/clean/chrome/browser/ui/commands/settings_commands.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #import "ios/shared/chrome/browser/ui/browser_list/browser.h"
 #import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
@@ -31,19 +30,9 @@
                                 currentBrowserState:self.browser
                                                         ->browser_state()
                                            delegate:self];
-  [self.context.baseViewController presentViewController:self.viewController
-                                                animated:self.context.animated
-                                              completion:nil];
   [super start];
 }
 
-- (void)stop {
-  [super stop];
-  [self.viewController.presentingViewController
-      dismissViewControllerAnimated:self.context.animated
-                         completion:nil];
-}
-
 #pragma mark - SettingsNavigationControllerDelegate
 
 - (void)closeSettingsAndOpenUrl:(OpenUrlCommand*)command {
diff --git a/ios/clean/chrome/browser/ui/tab/BUILD.gn b/ios/clean/chrome/browser/ui/tab/BUILD.gn
index 14b5202..d97375c 100644
--- a/ios/clean/chrome/browser/ui/tab/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/tab/BUILD.gn
@@ -19,7 +19,6 @@
     "//ios/clean/chrome/browser/ui/tab_strip",
     "//ios/clean/chrome/browser/ui/toolbar",
     "//ios/clean/chrome/browser/ui/web_contents",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/ui/coordinators",
     "//ios/web",
   ]
diff --git a/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm b/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
index 59497cb2..faf15db3 100644
--- a/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
@@ -14,7 +14,6 @@
 #import "ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.h"
 #import "ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.h"
 #import "ios/clean/chrome/browser/ui/web_contents/web_coordinator.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
@@ -54,28 +53,17 @@
   WebCoordinator* webCoordinator = [[WebCoordinator alloc] init];
   webCoordinator.webState = self.webState;
   [self addChildCoordinator:webCoordinator];
-  // Unset the base view controller, so |webCoordinator| doesn't present its
-  // view controller.
-  webCoordinator.context.baseViewController = nil;
   [webCoordinator start];
 
   ToolbarCoordinator* toolbarCoordinator = [[ToolbarCoordinator alloc] init];
   toolbarCoordinator.webState = self.webState;
   [self addChildCoordinator:toolbarCoordinator];
-  // Unset the base view controller, so |toolbarCoordinator| doesn't present
-  // its view controller.
-  toolbarCoordinator.context.baseViewController = nil;
   [toolbarCoordinator start];
 
   TabStripCoordinator* tabStripCoordinator = [[TabStripCoordinator alloc] init];
   [self addChildCoordinator:tabStripCoordinator];
-  // Unset the base view controller since this is a contained view controller.
-  tabStripCoordinator.context.baseViewController = nil;
   [tabStripCoordinator start];
 
-  [self.context.baseViewController presentViewController:self.viewController
-                                                animated:self.context.animated
-                                              completion:nil];
   [super start];
 }
 
@@ -86,19 +74,18 @@
   for (BrowserCoordinator* child in self.children) {
     [child stop];
   }
-  [self.viewController.presentingViewController
-      dismissViewControllerAnimated:self.context.animated
-                         completion:nil];
   _webStateObserver.reset();
 }
 
-- (void)childCoordinatorDidStart:(BrowserCoordinator*)coordinator {
-  if ([coordinator isKindOfClass:[ToolbarCoordinator class]]) {
-    self.viewController.toolbarViewController = coordinator.viewController;
-  } else if ([coordinator isKindOfClass:[WebCoordinator class]]) {
-    self.viewController.contentViewController = coordinator.viewController;
-  } else if ([coordinator isKindOfClass:[TabStripCoordinator class]]) {
-    self.viewController.tabStripViewController = coordinator.viewController;
+- (void)childCoordinatorDidStart:(BrowserCoordinator*)childCoordinator {
+  if ([childCoordinator isKindOfClass:[ToolbarCoordinator class]]) {
+    self.viewController.toolbarViewController = childCoordinator.viewController;
+  } else if ([childCoordinator isKindOfClass:[WebCoordinator class]] ||
+             [childCoordinator isKindOfClass:[NTPCoordinator class]]) {
+    self.viewController.contentViewController = childCoordinator.viewController;
+  } else if ([childCoordinator isKindOfClass:[TabStripCoordinator class]]) {
+    self.viewController.tabStripViewController =
+        childCoordinator.viewController;
   }
 }
 
@@ -128,9 +115,7 @@
   if (webState->GetLastCommittedURL() == GURL("chrome://newtab/")) {
     NTPCoordinator* ntpCoordinator = [[NTPCoordinator alloc] init];
     [self addChildCoordinator:ntpCoordinator];
-    ntpCoordinator.context.baseViewController = nil;
     [ntpCoordinator start];
-    self.viewController.contentViewController = ntpCoordinator.viewController;
   }
 }
 
diff --git a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
index 70c8b1d..ec4ad7d 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/tab_grid/BUILD.gn
@@ -22,7 +22,6 @@
     "//ios/clean/chrome/browser/ui/tab",
     "//ios/clean/chrome/browser/ui/tab_collection",
     "//ios/clean/chrome/browser/ui/tab_collection:tab_collection_ui",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/tabs",
     "//ios/shared/chrome/browser/ui/browser_list",
     "//ios/shared/chrome/browser/ui/commands",
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
index 1598edf5..9748760 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -14,7 +14,6 @@
 #import "ios/clean/chrome/browser/ui/tab/tab_coordinator.h"
 #import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_mediator.h"
 #import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #import "ios/shared/chrome/browser/tabs/web_state_list.h"
 #import "ios/shared/chrome/browser/ui/browser_list/browser.h"
 #import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
@@ -68,8 +67,6 @@
   // SettingsCommands
   [dispatcher startDispatchingToTarget:self
                            forSelector:@selector(showSettings)];
-  [dispatcher startDispatchingToTarget:self
-                           forSelector:@selector(closeSettings)];
   // TabGridCommands
   [dispatcher startDispatchingToTarget:self
                            forSelector:@selector(showTabGridTabAtIndex:)];
@@ -85,12 +82,6 @@
 
   self.mediator.consumer = self.viewController;
 
-  // |baseViewController| is nullable, so this is by design a no-op if it hasn't
-  // been set. This may be true in a unit test, or if this coordinator is being
-  // used as a root coordinator.
-  [self.context.baseViewController presentViewController:self.viewController
-                                                animated:self.context.animated
-                                              completion:nil];
   [super start];
 }
 
@@ -99,6 +90,22 @@
   [self.browser->dispatcher() stopDispatchingToTarget:self];
 }
 
+- (void)childCoordinatorDidStart:(BrowserCoordinator*)childCoordinator {
+  DCHECK([childCoordinator isKindOfClass:[SettingsCoordinator class]] ||
+         [childCoordinator isKindOfClass:[TabCoordinator class]]);
+  [self.viewController presentViewController:childCoordinator.viewController
+                                    animated:YES
+                                  completion:nil];
+}
+
+- (void)childCoordinatorWillStop:(BrowserCoordinator*)childCoordinator {
+  DCHECK([childCoordinator isKindOfClass:[SettingsCoordinator class]] ||
+         [childCoordinator isKindOfClass:[TabCoordinator class]]);
+  [childCoordinator.viewController.presentingViewController
+      dismissViewControllerAnimated:YES
+                         completion:nil];
+}
+
 #pragma mark - TabGridCommands
 
 - (void)showTabGridTabAtIndex:(int)index {
diff --git a/ios/clean/chrome/browser/ui/tab_strip/BUILD.gn b/ios/clean/chrome/browser/ui/tab_strip/BUILD.gn
index 8d6da29..c977e91 100644
--- a/ios/clean/chrome/browser/ui/tab_strip/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/tab_strip/BUILD.gn
@@ -12,7 +12,6 @@
     "//ios/chrome/browser/browser_state",
     "//ios/clean/chrome/browser/ui/commands",
     "//ios/clean/chrome/browser/ui/tab_collection",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/tabs",
     "//ios/shared/chrome/browser/ui/browser_list",
     "//ios/shared/chrome/browser/ui/commands",
diff --git a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.mm b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.mm
index de1cebf..1eeb414d 100644
--- a/ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/tab_strip/tab_strip_coordinator.mm
@@ -7,7 +7,6 @@
 #import "ios/clean/chrome/browser/ui/commands/tab_strip_commands.h"
 #import "ios/clean/chrome/browser/ui/tab_collection/tab_collection_mediator.h"
 #import "ios/clean/chrome/browser/ui/tab_strip/tab_strip_view_controller.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #import "ios/shared/chrome/browser/tabs/web_state_list.h"
 #import "ios/shared/chrome/browser/ui/browser_list/browser.h"
 #import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
@@ -49,9 +48,6 @@
   self.viewController.dataSource = self.mediator;
   self.viewController.dispatcher = static_cast<id>(self.browser->dispatcher());
 
-  [self.context.baseViewController presentViewController:self.viewController
-                                                animated:self.context.animated
-                                              completion:nil];
   [super start];
 }
 
diff --git a/ios/clean/chrome/browser/ui/toolbar/BUILD.gn b/ios/clean/chrome/browser/ui/toolbar/BUILD.gn
index 2ead6dd0..30ee4d1 100644
--- a/ios/clean/chrome/browser/ui/toolbar/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/toolbar/BUILD.gn
@@ -18,7 +18,6 @@
     "//ios/clean/chrome/browser/ui/commands",
     "//ios/clean/chrome/browser/ui/omnibox",
     "//ios/clean/chrome/browser/ui/tools",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/ui/browser_list",
     "//ios/shared/chrome/browser/ui/commands",
     "//ios/shared/chrome/browser/ui/coordinators",
diff --git a/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.mm b/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.mm
index a9955a0..75be7f5 100644
--- a/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.mm
@@ -9,7 +9,6 @@
 #import "ios/clean/chrome/browser/ui/toolbar/toolbar_mediator.h"
 #import "ios/clean/chrome/browser/ui/toolbar/toolbar_view_controller.h"
 #import "ios/clean/chrome/browser/ui/tools/tools_coordinator.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #import "ios/shared/chrome/browser/ui/browser_list/browser.h"
 #import "ios/shared/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
@@ -69,9 +68,6 @@
   [self addChildCoordinator:locationBarCoordinator];
   [locationBarCoordinator start];
 
-  [self.context.baseViewController presentViewController:self.viewController
-                                                animated:self.context.animated
-                                              completion:nil];
   [super start];
 }
 
@@ -80,10 +76,22 @@
   [self.browser->dispatcher() stopDispatchingToTarget:self];
 }
 
-- (void)childCoordinatorDidStart:(BrowserCoordinator*)coordinator {
-  if ([coordinator isKindOfClass:[LocationBarCoordinator class]]) {
+- (void)childCoordinatorDidStart:(BrowserCoordinator*)childCoordinator {
+  if ([childCoordinator isKindOfClass:[LocationBarCoordinator class]]) {
     self.viewController.locationBarViewController =
         self.locationBarCoordinator.viewController;
+  } else if ([childCoordinator isKindOfClass:[ToolsCoordinator class]]) {
+    [self.viewController presentViewController:childCoordinator.viewController
+                                      animated:YES
+                                    completion:nil];
+  }
+}
+
+- (void)childCoordinatorWillStop:(BrowserCoordinator*)childCoordinator {
+  if ([childCoordinator isKindOfClass:[ToolsCoordinator class]]) {
+    [childCoordinator.viewController.presentingViewController
+        dismissViewControllerAnimated:YES
+                           completion:nil];
   }
 }
 
diff --git a/ios/clean/chrome/browser/ui/tools/BUILD.gn b/ios/clean/chrome/browser/ui/tools/BUILD.gn
index 61d3519..5968c31 100644
--- a/ios/clean/chrome/browser/ui/tools/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/tools/BUILD.gn
@@ -18,7 +18,6 @@
     "//ios/clean/chrome/browser/ui/actions",
     "//ios/clean/chrome/browser/ui/animators",
     "//ios/clean/chrome/browser/ui/presenters",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/ui/browser_list",
     "//ios/shared/chrome/browser/ui/coordinators",
   ]
diff --git a/ios/clean/chrome/browser/ui/tools/tools_coordinator.mm b/ios/clean/chrome/browser/ui/tools/tools_coordinator.mm
index b76dd594..f6688159 100644
--- a/ios/clean/chrome/browser/ui/tools/tools_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/tools/tools_coordinator.mm
@@ -8,7 +8,6 @@
 #import "ios/clean/chrome/browser/ui/presenters/menu_presentation_controller.h"
 #import "ios/clean/chrome/browser/ui/tools/menu_view_controller.h"
 #import "ios/clean/chrome/browser/ui/tools/tools_mediator.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #import "ios/shared/chrome/browser/ui/browser_list/browser.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -16,37 +15,26 @@
 #endif
 
 @interface ToolsCoordinator ()<UIViewControllerTransitioningDelegate>
-@property(nonatomic, strong) MenuViewController* menuViewController;
+@property(nonatomic, strong) MenuViewController* viewController;
 @property(nonatomic, strong) ToolsMediator* mediator;
 @end
 
 @implementation ToolsCoordinator
-@synthesize menuViewController = _menuViewController;
+@synthesize viewController = _viewController;
 @synthesize mediator = _mediator;
 
 #pragma mark - BrowserCoordinator
 
 - (void)start {
-  self.menuViewController = [[MenuViewController alloc] init];
-  self.menuViewController.modalPresentationStyle = UIModalPresentationCustom;
-  self.menuViewController.transitioningDelegate = self;
-  self.menuViewController.dispatcher =
-      static_cast<id>(self.browser->dispatcher());
-  _mediator = [[ToolsMediator alloc] initWithConsumer:self.menuViewController];
+  self.viewController = [[MenuViewController alloc] init];
+  self.viewController.modalPresentationStyle = UIModalPresentationCustom;
+  self.viewController.transitioningDelegate = self;
+  self.viewController.dispatcher = static_cast<id>(self.browser->dispatcher());
+  self.mediator = [[ToolsMediator alloc] initWithConsumer:self.viewController];
 
-  [self.context.baseViewController presentViewController:self.menuViewController
-                                                animated:self.context.animated
-                                              completion:nil];
   [super start];
 }
 
-- (void)stop {
-  [super stop];
-  [self.menuViewController.presentingViewController
-      dismissViewControllerAnimated:self.context.animated
-                         completion:nil];
-}
-
 #pragma mark - UIViewControllerTransitioningDelegate
 
 - (id<UIViewControllerAnimatedTransitioning>)
diff --git a/ios/clean/chrome/browser/ui/web_contents/BUILD.gn b/ios/clean/chrome/browser/ui/web_contents/BUILD.gn
index fa1af44f..207c2a0 100644
--- a/ios/clean/chrome/browser/ui/web_contents/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/web_contents/BUILD.gn
@@ -15,7 +15,6 @@
   deps = [
     ":web_contents_ui",
     "//ios/clean/chrome/browser/ui/context_menu",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/ui/coordinators",
     "//ios/web",
     "//ui/base",
diff --git a/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm b/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm
index 94602d4..ba0be5a 100644
--- a/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/web_contents/web_coordinator.mm
@@ -8,7 +8,6 @@
 #import "ios/clean/chrome/browser/ui/context_menu/web_context_menu_coordinator.h"
 #import "ios/clean/chrome/browser/ui/web_contents/web_contents_mediator.h"
 #import "ios/clean/chrome/browser/ui/web_contents/web_contents_view_controller.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
 #include "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_delegate_bridge.h"
@@ -46,13 +45,6 @@
 - (void)start {
   self.viewController = [[WebContentsViewController alloc] init];
   self.mediator.consumer = self.viewController;
-
-  // Reminder: this is a no-op if |baseViewController| is nil, for example
-  // when this coordinator's view controller will be contained instead of
-  // presented.
-  [self.context.baseViewController presentViewController:self.viewController
-                                                animated:self.context.animated
-                                              completion:nil];
   [super start];
 }
 
diff --git a/ios/shared/chrome/browser/coordinator_context/BUILD.gn b/ios/shared/chrome/browser/coordinator_context/BUILD.gn
deleted file mode 100644
index 4f3f5c2..0000000
--- a/ios/shared/chrome/browser/coordinator_context/BUILD.gn
+++ /dev/null
@@ -1,24 +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.
-
-source_set("coordinator_context") {
-  sources = [
-    "coordinator_context.h",
-    "coordinator_context.mm",
-  ]
-  configs += [ "//build/config/compiler:enable_arc" ]
-  libs = [ "UIKit.framework" ]
-}
-
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "coordinator_context_unittest.mm",
-  ]
-  deps = [
-    ":coordinator_context",
-    "//testing/gtest",
-  ]
-  configs += [ "//build/config/compiler:enable_arc" ]
-}
diff --git a/ios/shared/chrome/browser/coordinator_context/coordinator_context.h b/ios/shared/chrome/browser/coordinator_context/coordinator_context.h
deleted file mode 100644
index 3bb3419..0000000
--- a/ios/shared/chrome/browser/coordinator_context/coordinator_context.h
+++ /dev/null
@@ -1,24 +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_SHARED_CHROME_BROWSER_COORDINATOR_CONTEXT_COORDINATOR_CONTEXT_H_
-#define IOS_SHARED_CHROME_BROWSER_COORDINATOR_CONTEXT_COORDINATOR_CONTEXT_H_
-
-#import <UIKit/UIKit.h>
-
-// Holds data for the coordinator that uses it.
-@interface CoordinatorContext : NSObject
-
-// The view controller that the coordinator will use to present its content, if
-// it is presenting content. This is not the view controller created and managed
-// by the coordinator; it should be supplied by whatever object is creating
-// the coordinator.
-@property(nonatomic, weak) UIViewController* baseViewController;
-
-// Default is YES.
-@property(nonatomic, assign, getter=isAnimated) BOOL animated;
-
-@end
-
-#endif  // IOS_SHARED_CHROME_BROWSER_COORDINATOR_CONTEXT_COORDINATOR_CONTEXT_H_
diff --git a/ios/shared/chrome/browser/coordinator_context/coordinator_context.mm b/ios/shared/chrome/browser/coordinator_context/coordinator_context.mm
deleted file mode 100644
index 2815174..0000000
--- a/ios/shared/chrome/browser/coordinator_context/coordinator_context.mm
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation CoordinatorContext
-
-@synthesize baseViewController = _baseViewController;
-@synthesize animated = _animated;
-
-- (instancetype)init {
-  self = [super init];
-  if (self) {
-    _animated = YES;
-  }
-  return self;
-}
-
-@end
diff --git a/ios/shared/chrome/browser/coordinator_context/coordinator_context_unittest.mm b/ios/shared/chrome/browser/coordinator_context/coordinator_context_unittest.mm
deleted file mode 100644
index 30e377d..0000000
--- a/ios/shared/chrome/browser/coordinator_context/coordinator_context_unittest.mm
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-TEST(CoordinatorContextTest, Initialization) {
-  CoordinatorContext* context = [[CoordinatorContext alloc] init];
-  EXPECT_TRUE(context.animated);
-}
-
-}  // namespace
diff --git a/ios/shared/chrome/browser/ui/coordinators/BUILD.gn b/ios/shared/chrome/browser/ui/coordinators/BUILD.gn
index 39a3d8f..2f45aeb 100644
--- a/ios/shared/chrome/browser/ui/coordinators/BUILD.gn
+++ b/ios/shared/chrome/browser/ui/coordinators/BUILD.gn
@@ -17,7 +17,6 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/tabs:tabs_internal",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//ios/shared/chrome/browser/ui/browser_list",
   ]
 }
@@ -35,7 +34,6 @@
     "//base",
     "//base/test:test_support",
     "//ios/chrome/test/base",
-    "//ios/shared/chrome/browser/coordinator_context",
     "//testing/gtest",
   ]
 }
diff --git a/ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h b/ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h
index e3619643..b2e836f 100644
--- a/ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h
+++ b/ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h
@@ -56,8 +56,6 @@
 - (void)removeChildCoordinator:(BrowserCoordinator*)coordinator;
 
 // Called when this coordinator is added to a parent coordinator.
-// Subclasses can override this method to run code that requires a configured
-// CoordinatorContext.
 - (void)wasAddedToParentCoordinator:(BrowserCoordinator*)parentCoordinator;
 
 // Called when this coordinator is removed from its parent coordinator.
diff --git a/ios/shared/chrome/browser/ui/coordinators/browser_coordinator.h b/ios/shared/chrome/browser/ui/coordinators/browser_coordinator.h
index c5e725f..20987e0 100644
--- a/ios/shared/chrome/browser/ui/coordinators/browser_coordinator.h
+++ b/ios/shared/chrome/browser/ui/coordinators/browser_coordinator.h
@@ -8,7 +8,6 @@
 #import <UIKit/UIKit.h>
 
 class Browser;
-@class CoordinatorContext;
 
 // An object that manages a UI component via a view controller.
 // This is the public interface to this class; subclasses should also import
@@ -17,9 +16,6 @@
 // call, or reset.
 @interface BrowserCoordinator : NSObject
 
-// The context object for this coordinator.
-@property(nonatomic, strong, readonly) CoordinatorContext* context;
-
 // The browser object used by this coordinator and passed into any child
 // coordinators added to it. This is a weak pointer, and setting this property
 // doesn't transfer ownership of the browser.
diff --git a/ios/shared/chrome/browser/ui/coordinators/browser_coordinator.mm b/ios/shared/chrome/browser/ui/coordinators/browser_coordinator.mm
index 6660579..4e758fd 100644
--- a/ios/shared/chrome/browser/ui/coordinators/browser_coordinator.mm
+++ b/ios/shared/chrome/browser/ui/coordinators/browser_coordinator.mm
@@ -5,7 +5,6 @@
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator.h"
 
 #import "base/logging.h"
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -24,7 +23,6 @@
 
 @implementation BrowserCoordinator
 
-@synthesize context = _context;
 @synthesize browser = _browser;
 @synthesize childCoordinators = _childCoordinators;
 @synthesize parentCoordinator = _parentCoordinator;
@@ -33,7 +31,6 @@
 
 - (instancetype)init {
   if (self = [super init]) {
-    _context = [[CoordinatorContext alloc] init];
     _childCoordinators = [NSMutableSet set];
   }
   return self;
@@ -68,7 +65,6 @@
   [self.childCoordinators addObject:coordinator];
   coordinator.parentCoordinator = self;
   coordinator.browser = self.browser;
-  coordinator.context.baseViewController = self.viewController;
   [coordinator wasAddedToParentCoordinator:self];
 }
 
diff --git a/ios/shared/chrome/browser/ui/coordinators/browser_coordinator_unittest.mm b/ios/shared/chrome/browser/ui/coordinators/browser_coordinator_unittest.mm
index 2d13458..df005e6e 100644
--- a/ios/shared/chrome/browser/ui/coordinators/browser_coordinator_unittest.mm
+++ b/ios/shared/chrome/browser/ui/coordinators/browser_coordinator_unittest.mm
@@ -5,7 +5,6 @@
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator.h"
 #import "ios/shared/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
 
-#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 
@@ -95,13 +94,10 @@
   [parent addChildCoordinator:child];
   EXPECT_TRUE([parent.children containsObject:child]);
   EXPECT_EQ(parent, child.parentCoordinator);
-  EXPECT_EQ(parent.viewController, child.context.baseViewController);
 
   [parent removeChildCoordinator:child];
   EXPECT_FALSE([parent.children containsObject:child]);
   EXPECT_EQ(nil, child.parentCoordinator);
-  // Unparenting shouldn't change a child's baseViewController.
-  EXPECT_EQ(parent.viewController, child.context.baseViewController);
 
   TestCoordinator* otherParent = [[TestCoordinator alloc] init];
   TestCoordinator* otherChild = [[TestCoordinator alloc] init];
diff --git a/ios/testing/data/http_server_files/window_location.html b/ios/testing/data/http_server_files/window_location.html
index c8e9d70e..f4b6a8b3 100644
--- a/ios/testing/data/http_server_files/window_location.html
+++ b/ios/testing/data/http_server_files/window_location.html
@@ -16,6 +16,8 @@
 <br>
 <div id='url-to-load'></div>
 <br>
+<div id='no-op'></div>
+<br>
 </p>
 
 <input type="button" value="location-assign" id="location-assign"
diff --git a/ios/testing/data/http_server_files/window_location.js b/ios/testing/data/http_server_files/window_location.js
index 7e1bc19..d89e17f 100644
--- a/ios/testing/data/http_server_files/window_location.js
+++ b/ios/testing/data/http_server_files/window_location.js
@@ -11,10 +11,22 @@
   document.getElementById('on-load-div').innerHTML = text;
 }
 
+var updateNoOpText = function() {
+  document.getElementById('no-op').innerHTML = 'NoOpText';
+}
+
+var buttonWasTapped = function() {
+  setTimeout(updateNoOpText, 500);
+}
+
 var isOnLoadTextVisible = function() {
   return document.getElementById('on-load-div').innerHTML == 'OnLoadText';
 }
 
+var isNoOpTextVisible = function() {
+  return document.getElementById('no-op').innerHTML == 'NoOpText';
+}
+
 // Updates the url-to-load div with |text|.  This value is later used by the
 // window.location calls below.
 var updateUrlToLoadText = function(text) {
@@ -30,20 +42,24 @@
 var locationAssign = function() {
   updateOnLoadText('');
   window.location.assign(getUrl());
+  buttonWasTapped();
 }
 
 var locationReplace = function() {
   updateOnLoadText('');
   window.location.replace(getUrl());
+  buttonWasTapped();
 }
 
 var locationReload = function() {
   updateOnLoadText('');
   window.location.reload();
+  buttonWasTapped();
 }
 
 var setLocationToDOMString = function() {
   updateOnLoadText('');
   window.location = getUrl();
+  buttonWasTapped();
 }
 
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index d737225..d5a4bdc 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -697,6 +697,7 @@
     "web_state/js/resources/base.js",
     "web_state/js/resources/common.js",
     "web_state/js/resources/console.js",
+    "web_state/js/resources/context_menu.js",
     "web_state/js/resources/core.js",
     "web_state/js/resources/dialog_overrides.js",
     "web_state/js/resources/message.js",
diff --git a/ios/web/navigation/window_location_inttest.mm b/ios/web/navigation/window_location_inttest.mm
index fcfe4f71..984754e 100644
--- a/ios/web/navigation/window_location_inttest.mm
+++ b/ios/web/navigation/window_location_inttest.mm
@@ -45,6 +45,7 @@
 NSString* const kUpdateURLScriptFormat = @"updateUrlToLoadText('%s')";
 NSString* const kGetURLScript = @"getUrl()";
 NSString* const kOnLoadCheckScript = @"isOnLoadTextVisible()";
+NSString* const kNoOpCheckScript = @"isNoOpTextVisible()";
 
 // URL of a sample file-based page.
 const char kSampleFileBasedURL[] =
@@ -92,6 +93,15 @@
     return [text_visible boolValue];
   }
 
+  // Executes JavaScript on the window.location test page and returns whether
+  // the no-op text is visible.  It is displayed 0.5 seconds after a button is
+  // tapped, and can be used to verify that a navigation did not occur.
+  bool IsNoOpTextVisible() {
+    NSNumber* text_visible = base::mac::ObjCCastStrict<NSNumber>(
+        ExecuteJavaScript(kNoOpCheckScript));
+    return [text_visible boolValue];
+  }
+
  private:
   GURL window_location_url_;
 };
@@ -127,17 +137,15 @@
 // about:blank.
 TEST_F(WindowLocationTest, WindowLocationAssignUnresolvable) {
   // Attempt to call window.location.assign() using an unresolvable URL.
-  GURL about_blank("about:blank");
   GURL unresolvable_url("http:https:not a url");
   SetWindowLocationUrl(unresolvable_url);
-  ExecuteBlockAndWaitForLoad(about_blank, ^{
-    ASSERT_TRUE(web::test::TapWebViewElementWithId(web_state(),
-                                                   kWindowLocationAssignID));
-  });
+  ASSERT_TRUE(
+      web::test::TapWebViewElementWithId(web_state(), kWindowLocationAssignID));
 
-  // Verify that about:blank was actually loaded.
-  EXPECT_EQ(about_blank,
-            navigation_manager()->GetLastCommittedItem()->GetURL());
+  // Wait for the no-op text to appear.
+  base::test::ios::WaitUntilCondition(^bool {
+    return IsNoOpTextVisible();
+  });
 }
 
 // Tests that calling window.location.replace() doesn't create a new
@@ -172,21 +180,19 @@
             GetIndexOfNavigationItem(about_blank_item));
 }
 
-// Tests that calling window.location.replace() with an unresolvable URL loads
-// about:blank.
+// Tests that calling window.location.replace() with an unresolvable URL is a
+// no-op.
 TEST_F(WindowLocationTest, WindowLocationReplaceUnresolvable) {
   // Attempt to call window.location.assign() using an unresolvable URL.
-  GURL about_blank("about:blank");
   GURL unresolvable_url("http:https:not a url");
   SetWindowLocationUrl(unresolvable_url);
-  ExecuteBlockAndWaitForLoad(about_blank, ^{
-    ASSERT_TRUE(web::test::TapWebViewElementWithId(web_state(),
-                                                   kWindowLocationReplaceID));
-  });
+  ASSERT_TRUE(web::test::TapWebViewElementWithId(web_state(),
+                                                 kWindowLocationReplaceID));
 
-  // Verify that about:blank was actually loaded.
-  EXPECT_EQ(about_blank,
-            navigation_manager()->GetLastCommittedItem()->GetURL());
+  // Wait for the no-op text to appear.
+  base::test::ios::WaitUntilCondition(^bool {
+    return IsNoOpTextVisible();
+  });
 }
 
 // Tests that calling window.location.reload() causes an onload event to occur.
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h
index aa55ba6..0bd5ba1 100644
--- a/ios/web/public/web_state/web_state.h
+++ b/ios/web/public/web_state/web_state.h
@@ -62,7 +62,7 @@
     web::BrowserState* browser_state;
 
     // Whether the WebState is created as the result of a window.open or by
-    // clicking a link with a blank targer.  Used to determin whether the
+    // clicking a link with a blank target.  Used to determine whether the
     // WebState is allowed to be closed via window.close().
     bool created_with_opener;
   };
diff --git a/ios/web/web_state/js/resources/context_menu.js b/ios/web/web_state/js/resources/context_menu.js
new file mode 100644
index 0000000..ffd654b
--- /dev/null
+++ b/ios/web/web_state/js/resources/context_menu.js
@@ -0,0 +1,269 @@
+// 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.
+
+/**
+ * @fileoverview APIs used by CRWContextMenuController.
+ */
+
+goog.provide('__crWeb.contextMenu');
+
+/** Beginning of anonymous object */
+(function() {
+
+  /**
+   * Returns the url of the image or link under the selected point. Returns an
+   * empty string if no links or images are found.
+   * @param {number} x Horizontal center of the selected point.
+   * @param {number} y Vertical center of the selected point.
+   * @return {!Object} An object of the form {
+   *     href,  // URL of the link under the point
+   *     innerText,  // innerText of the link, if the selected element is a link
+   *     src,  // src of the image, if the selected element is an image
+   *     title,  // title of the image, if the selected
+   *     referrerPolicy
+   *   }
+   *   where:
+   *     <ul>
+   *     <li>href, innerText are set if the selected element is a link.
+   *     <li>src, title are set if the selected element is an image.
+   *     <li>href is also set if the selected element is an image with a link.
+   *     <li>referrerPolicy is the referrer policy to use for navigations away
+   *         from the current page.
+   *     </ul>
+   */
+  __gCrWeb['getElementFromPoint'] = function(x, y) {
+    var hitCoordinates = spiralCoordinates_(x, y);
+    for (var index = 0; index < hitCoordinates.length; index++) {
+      var coordinates = hitCoordinates[index];
+
+      var element = elementFromPoint_(coordinates.x, coordinates.y);
+      if (!element || !element.tagName) {
+        // Nothing under the hit point. Try the next hit point.
+        continue;
+      }
+
+      if (getComputedWebkitTouchCallout_(element) === 'none')
+        continue;
+      // Also check element's ancestors. A bound on the level is used here to
+      // avoid large overhead when no links or images are found.
+      var level = 0;
+      while (++level < 8 && element && element != document) {
+        var tagName = element.tagName;
+        if (!tagName)
+          continue;
+        tagName = tagName.toLowerCase();
+
+        if (tagName === 'input' || tagName === 'textarea' ||
+            tagName === 'select' || tagName === 'option') {
+          // If the element is a known input element, stop the spiral search and
+          // return empty results.
+          return {};
+        }
+
+        if (tagName === 'a' && element.href) {
+          // Found a link.
+          return {
+            href: element.href,
+            referrerPolicy: getReferrerPolicy_(element),
+            innerText: element.innerText
+          };
+        }
+
+        if (tagName === 'img' && element.src) {
+          // Found an image.
+          var result = {
+            src: element.src,
+            referrerPolicy: getReferrerPolicy_()
+          };
+          // Copy the title, if any.
+          if (element.title) {
+            result.title = element.title;
+          }
+          // Check if the image is also a link.
+          var parent = element.parentNode;
+          while (parent) {
+            if (parent.tagName &&
+                parent.tagName.toLowerCase() === 'a' &&
+                parent.href) {
+              // This regex identifies strings like void(0),
+              // void(0)  ;void(0);, ;;;;
+              // which result in a NOP when executed as JavaScript.
+              var regex = RegExp("^javascript:(?:(?:void\\(0\\)|;)\\s*)+$");
+              if (parent.href.match(regex)) {
+                parent = parent.parentNode;
+                continue;
+              }
+              result.href = parent.href;
+              result.referrerPolicy = getReferrerPolicy_(parent);
+              break;
+            }
+            parent = parent.parentNode;
+          }
+          return result;
+        }
+        element = element.parentNode;
+      }
+    }
+    return {};
+  };
+
+  /**
+   * Suppresses the next click such that they are not handled by JS click
+   * event handlers.
+   * @type {void}
+   */
+  __gCrWeb['suppressNextClick'] = function() {
+    var suppressNextClick = function(evt) {
+      evt.preventDefault();
+      document.removeEventListener('click', suppressNextClick, false);
+    };
+    document.addEventListener('click', suppressNextClick);
+  };
+
+  /**
+   * Returns the margin in points around touchable elements (e.g. links for
+   * custom context menu).
+   * @type {number}
+   */
+  __gCrWeb['getPageWidth'] = function() {
+    var documentElement = document.documentElement;
+    var documentBody = document.body;
+    return Math.max(documentElement.clientWidth,
+                    documentElement.scrollWidth,
+                    documentElement.offsetWidth,
+                    documentBody.scrollWidth,
+                    documentBody.offsetWidth);
+  };
+
+  /**
+   * Implementation of document.elementFromPoint that is working for iOS4 and
+   * iOS5 and that also goes into frames and iframes.
+   * @private
+   */
+  var elementFromPoint_ = function(x, y) {
+    var elementFromPointIsUsingViewPortCoordinates = function(win) {
+      if (win.pageYOffset > 0) {  // Page scrolled down.
+        return (win.document.elementFromPoint(
+            0, win.pageYOffset + win.innerHeight - 1) === null);
+      }
+      if (win.pageXOffset > 0) {  // Page scrolled to the right.
+        return (win.document.elementFromPoint(
+            win.pageXOffset + win.innerWidth - 1, 0) === null);
+      }
+      return false;  // No scrolling, don't care.
+    };
+
+    var newCoordinate = function(x, y) {
+      var coordinates = {
+          x: x, y: y,
+          viewPortX: x - window.pageXOffset, viewPortY: y - window.pageYOffset,
+          useViewPortCoordinates: false,
+          window: window
+      };
+      return coordinates;
+    };
+
+    // Returns the coordinates of the upper left corner of |obj| in the
+    // coordinates of the window that |obj| is in.
+    var getPositionInWindow = function(obj) {
+      var coord = { x: 0, y: 0 };
+      while (obj.offsetParent) {
+        coord.x += obj.offsetLeft;
+        coord.y += obj.offsetTop;
+        obj = obj.offsetParent;
+      }
+      return coord;
+    };
+
+    var elementsFromCoordinates = function(coordinates) {
+      coordinates.useViewPortCoordinates = coordinates.useViewPortCoordinates ||
+          elementFromPointIsUsingViewPortCoordinates(coordinates.window);
+
+      var currentElement = null;
+      if (coordinates.useViewPortCoordinates) {
+        currentElement = coordinates.window.document.elementFromPoint(
+            coordinates.viewPortX, coordinates.viewPortY);
+      } else {
+        currentElement = coordinates.window.document.elementFromPoint(
+            coordinates.x, coordinates.y);
+      }
+      // We have to check for tagName, because if a selection is made by the
+      // UIWebView, the element we will get won't have one.
+      if (!currentElement || !currentElement.tagName) {
+        return null;
+      }
+      if (currentElement.tagName.toLowerCase() === 'iframe' ||
+          currentElement.tagName.toLowerCase() === 'frame') {
+        // The following condition is true if the iframe is in a different
+        // domain; no further information is accessible.
+        if (typeof(currentElement.contentWindow.document) == 'undefined') {
+          return currentElement;
+        }
+        var framePosition = getPositionInWindow(currentElement);
+        coordinates.viewPortX -=
+            framePosition.x - coordinates.window.pageXOffset;
+        coordinates.viewPortY -=
+            framePosition.y - coordinates.window.pageYOffset;
+        coordinates.window = currentElement.contentWindow;
+        coordinates.x -= framePosition.x + coordinates.window.pageXOffset;
+        coordinates.y -= framePosition.y + coordinates.window.pageYOffset;
+        return elementsFromCoordinates(coordinates);
+      }
+      return currentElement;
+    };
+
+    return elementsFromCoordinates(newCoordinate(x, y));
+  };
+
+  /** @private */
+  var spiralCoordinates_ = function(x, y) {
+    var MAX_ANGLE = Math.PI * 2.0 * 3.0;
+    var POINT_COUNT = 30;
+    var ANGLE_STEP = MAX_ANGLE / POINT_COUNT;
+    var TOUCH_MARGIN = 25;
+    var SPEED = TOUCH_MARGIN / MAX_ANGLE;
+
+    var coordinates = [];
+    for (var index = 0; index < POINT_COUNT; index++) {
+      var angle = ANGLE_STEP * index;
+      var radius = angle * SPEED;
+
+      coordinates.push({x: x + Math.round(Math.cos(angle) * radius),
+                        y: y + Math.round(Math.sin(angle) * radius)});
+    }
+
+    return coordinates;
+  };
+
+  /** @private */
+  var getComputedWebkitTouchCallout_ = function(element) {
+    return window.getComputedStyle(element, null)['webkitTouchCallout'];
+  };
+
+  /**
+   * Gets the referrer policy to use for navigations away from the current page.
+   * If a link element is passed, and it includes a rel=noreferrer tag, that
+   * will override the page setting.
+   * @param {HTMLElement=} opt_linkElement The link triggering the navigation.
+   * @return {string} The policy string.
+   * @private
+   */
+  var getReferrerPolicy_ = function(opt_linkElement) {
+    if (opt_linkElement) {
+      var rel = opt_linkElement.getAttribute('rel');
+      if (rel && rel.toLowerCase() == 'noreferrer') {
+        return 'never';
+      }
+    }
+
+    var metaTags = document.getElementsByTagName('meta');
+    for (var i = 0; i < metaTags.length; ++i) {
+      if (metaTags[i].name.toLowerCase() == 'referrer') {
+        return metaTags[i].content.toLowerCase();
+      }
+    }
+    return 'default';
+  };
+
+}());  // End of anonymouse object
diff --git a/ios/web/web_state/js/resources/core.js b/ios/web/web_state/js/resources/core.js
index 65299716..0a477eb 100644
--- a/ios/web/web_state/js/resources/core.js
+++ b/ios/web/web_state/js/resources/core.js
@@ -40,206 +40,6 @@
                    'message': event.message.toString()});
   });
 
-  /**
-   * Margin in points around touchable elements (e.g. links for custom context
-   * menu).
-   * @type {number}
-   */
-  var touchMargin_ = 25;
-
-  __gCrWeb['getPageWidth'] = function() {
-    var documentElement = document.documentElement;
-    var documentBody = document.body;
-    return Math.max(documentElement.clientWidth,
-                    documentElement.scrollWidth,
-                    documentElement.offsetWidth,
-                    documentBody.scrollWidth,
-                    documentBody.offsetWidth);
-  };
-
-  // Implementation of document.elementFromPoint that is working for iOS4 and
-  // iOS5 and that also goes into frames and iframes.
-  var elementFromPoint_ = function(x, y) {
-    var elementFromPointIsUsingViewPortCoordinates = function(win) {
-      if (win.pageYOffset > 0) {  // Page scrolled down.
-        return (win.document.elementFromPoint(
-            0, win.pageYOffset + win.innerHeight - 1) === null);
-      }
-      if (win.pageXOffset > 0) {  // Page scrolled to the right.
-        return (win.document.elementFromPoint(
-            win.pageXOffset + win.innerWidth - 1, 0) === null);
-      }
-      return false;  // No scrolling, don't care.
-    };
-
-    var newCoordinate = function(x, y) {
-      var coordinates = {
-          x: x, y: y,
-          viewPortX: x - window.pageXOffset, viewPortY: y - window.pageYOffset,
-          useViewPortCoordinates: false,
-          window: window
-      };
-      return coordinates;
-    };
-
-    // Returns the coordinates of the upper left corner of |obj| in the
-    // coordinates of the window that |obj| is in.
-    var getPositionInWindow = function(obj) {
-      var coord = { x: 0, y: 0 };
-      while (obj.offsetParent) {
-        coord.x += obj.offsetLeft;
-        coord.y += obj.offsetTop;
-        obj = obj.offsetParent;
-      }
-      return coord;
-    };
-
-    var elementsFromCoordinates = function(coordinates) {
-      coordinates.useViewPortCoordinates = coordinates.useViewPortCoordinates ||
-          elementFromPointIsUsingViewPortCoordinates(coordinates.window);
-
-      var currentElement = null;
-      if (coordinates.useViewPortCoordinates) {
-        currentElement = coordinates.window.document.elementFromPoint(
-            coordinates.viewPortX, coordinates.viewPortY);
-      } else {
-        currentElement = coordinates.window.document.elementFromPoint(
-            coordinates.x, coordinates.y);
-      }
-      // We have to check for tagName, because if a selection is made by the
-      // UIWebView, the element we will get won't have one.
-      if (!currentElement || !currentElement.tagName) {
-        return null;
-      }
-      if (currentElement.tagName.toLowerCase() === 'iframe' ||
-          currentElement.tagName.toLowerCase() === 'frame') {
-        // The following condition is true if the iframe is in a different
-        // domain; no further information is accessible.
-        if (typeof(currentElement.contentWindow.document) == 'undefined') {
-          return currentElement;
-        }
-        var framePosition = getPositionInWindow(currentElement);
-        coordinates.viewPortX -=
-            framePosition.x - coordinates.window.pageXOffset;
-        coordinates.viewPortY -=
-            framePosition.y - coordinates.window.pageYOffset;
-        coordinates.window = currentElement.contentWindow;
-        coordinates.x -= framePosition.x + coordinates.window.pageXOffset;
-        coordinates.y -= framePosition.y + coordinates.window.pageYOffset;
-        return elementsFromCoordinates(coordinates);
-      }
-      return currentElement;
-    };
-
-    return elementsFromCoordinates(newCoordinate(x, y));
-  };
-
-  var spiralCoordinates = function(x, y) {
-    var coordinates = [];
-
-    var maxAngle = Math.PI * 2.0 * 3.0;
-    var pointCount = 30;
-    var angleStep = maxAngle / pointCount;
-    var speed = touchMargin_ / maxAngle;
-
-    for (var index = 0; index < pointCount; index++) {
-      var angle = angleStep * index;
-      var radius = angle * speed;
-
-      coordinates.push({x: x + Math.round(Math.cos(angle) * radius),
-                        y: y + Math.round(Math.sin(angle) * radius)});
-    }
-
-    return coordinates;
-  };
-
-  // Returns the url of the image or link under the selected point. Returns an
-  // empty string if no links or images are found.
-  __gCrWeb['getElementFromPoint'] = function(x, y) {
-    var hitCoordinates = spiralCoordinates(x, y);
-    for (var index = 0; index < hitCoordinates.length; index++) {
-      var coordinates = hitCoordinates[index];
-
-      var element = elementFromPoint_(coordinates.x, coordinates.y);
-      if (!element || !element.tagName) {
-        // Nothing under the hit point. Try the next hit point.
-        continue;
-      }
-
-      if (getComputedWebkitTouchCallout_(element) === 'none')
-        continue;
-      // Also check element's ancestors. A bound on the level is used here to
-      // avoid large overhead when no links or images are found.
-      var level = 0;
-      while (++level < 8 && element && element != document) {
-        var tagName = element.tagName;
-        if (!tagName)
-          continue;
-        tagName = tagName.toLowerCase();
-
-        if (tagName === 'input' || tagName === 'textarea' ||
-            tagName === 'select' || tagName === 'option') {
-          // If the element is a known input element, stop the spiral search and
-          // return empty results.
-          return {};
-        }
-
-        if (tagName === 'a' && element.href) {
-          // Found a link.
-          return {
-            href: element.href,
-            referrerPolicy: getReferrerPolicy_(element),
-            innerText: element.innerText
-          };
-        }
-
-        if (tagName === 'img' && element.src) {
-          // Found an image.
-          var result = {
-            src: element.src,
-            referrerPolicy: getReferrerPolicy_()
-          };
-          // Copy the title, if any.
-          if (element.title) {
-            result.title = element.title;
-          }
-          // Check if the image is also a link.
-          var parent = element.parentNode;
-          while (parent) {
-            if (parent.tagName &&
-                parent.tagName.toLowerCase() === 'a' &&
-                parent.href) {
-              // This regex identifies strings like void(0),
-              // void(0)  ;void(0);, ;;;;
-              // which result in a NOP when executed as JavaScript.
-              var regex = RegExp("^javascript:(?:(?:void\\(0\\)|;)\\s*)+$");
-              if (parent.href.match(regex)) {
-                parent = parent.parentNode;
-                continue;
-              }
-              result.href = parent.href;
-              result.referrerPolicy = getReferrerPolicy_(parent);
-              break;
-            }
-            parent = parent.parentNode;
-          }
-          return result;
-        }
-        element = element.parentNode;
-      }
-    }
-    return {};
-  };
-
-  // Suppresses the next click such that they are not handled by JS click
-  // event handlers.
-  __gCrWeb['suppressNextClick'] = function() {
-    var suppressNextClick = function(evt) {
-      evt.preventDefault();
-      document.removeEventListener('click', suppressNextClick, false);
-    };
-    document.addEventListener('click', suppressNextClick);
-  };
 
   // Returns true if the top window or any frames inside contain an input
   // field of type 'password'.
@@ -338,31 +138,6 @@
     __gCrWeb.message.invokeOnHost(command);
   };
 
-  /**
-   * Gets the referrer policy to use for navigations away from the current page.
-   * If a link element is passed, and it includes a rel=noreferrer tag, that
-   * will override the page setting.
-   * @param {HTMLElement=} opt_linkElement The link triggering the navigation.
-   * @return {string} The policy string.
-   * @private
-   */
-  var getReferrerPolicy_ = function(opt_linkElement) {
-    if (opt_linkElement) {
-      var rel = opt_linkElement.getAttribute('rel');
-      if (rel && rel.toLowerCase() == 'noreferrer') {
-        return 'never';
-      }
-    }
-
-    var metaTags = document.getElementsByTagName('meta');
-    for (var i = 0; i < metaTags.length; ++i) {
-      if (metaTags[i].name.toLowerCase() == 'referrer') {
-        return metaTags[i].content.toLowerCase();
-      }
-    }
-    return 'default';
-  };
-
   // Various aspects of global DOM behavior are overridden here.
 
   // A popstate event needs to be fired anytime the active history entry
@@ -481,10 +256,6 @@
     invokeOnHost_({'command': 'window.hashchange'});
   });
 
-  var getComputedWebkitTouchCallout_ = function(element) {
-    return window.getComputedStyle(element, null)['webkitTouchCallout'];
-  };
-
   // Flush the message queue.
   if (__gCrWeb.message) {
     __gCrWeb.message.invokeQueues();
diff --git a/ios/web/web_state/js/resources/web_bundle.js b/ios/web/web_state/js/resources/web_bundle.js
index 0252c45aa..74cae382 100644
--- a/ios/web/web_state/js/resources/web_bundle.js
+++ b/ios/web/web_state/js/resources/web_bundle.js
@@ -6,5 +6,6 @@
 goog.provide('__crWeb.webBundle');
 
 goog.require('__crWeb.console');
+goog.require('__crWeb.contextMenu');
 goog.require('__crWeb.core');
 goog.require('__crWeb.dialogOverrides');
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 9096e2a..a3726dfa 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4303,14 +4303,17 @@
   // retrieved state will be pending until |didCommitNavigation| callback.
   [self updatePendingNavigationInfoFromNavigationAction:action];
 
-  // Invalid URLs should not be loaded.  However, simply doing nothing upon
-  // tapping a link or button is a jarring user experience.  Instead, cancel
-  // the invalid navigation and load about:blank if navigation was requested for
-  // the main frame.
+  // Invalid URLs should not be loaded.
   GURL requestURL = net::GURLWithNSURL(action.request.URL);
   if (!requestURL.is_valid()) {
     decisionHandler(WKNavigationActionPolicyCancel);
-    if (action.targetFrame.mainFrame) {
+    // The HTML5 spec indicates that window.open with an invalid URL should open
+    // about:blank.
+    BOOL isFirstLoadInOpenedWindow =
+        self.webState->HasOpener() &&
+        !self.webState->GetNavigationManager()->GetLastCommittedItem();
+    BOOL isMainFrame = action.targetFrame.mainFrame;
+    if (isFirstLoadInOpenedWindow && isMainFrame) {
       GURL aboutBlankURL(url::kAboutBlankURL);
       web::NavigationManager::WebLoadParams loadParams(aboutBlankURL);
       loadParams.referrer = [self currentReferrer];
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index 1368635..e3d59a3a 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -21,7 +21,6 @@
   NaClMsgStart,
   UtilityMsgStart,
   GpuChannelMsgStart,
-  GpuMsgStart,
   MediaMsgStart,
   ServiceMsgStart,
   PpapiMsgStart,
diff --git a/media/base/android/android_util.cc b/media/base/android/android_util.cc
index 371f7e5..e2252c9 100644
--- a/media/base/android/android_util.cc
+++ b/media/base/android/android_util.cc
@@ -18,6 +18,13 @@
   return std::string(byte_vector.begin(), byte_vector.end());
 }
 
+base::android::ScopedJavaLocalRef<jbyteArray> StringToJavaBytes(
+    JNIEnv* env,
+    const std::string& str) {
+  return base::android::ToJavaByteArray(
+      env, reinterpret_cast<const uint8_t*>(str.data()), str.size());
+}
+
 JavaObjectPtr CreateJavaObjectPtr(jobject object) {
   JavaObjectPtr j_object_ptr(new base::android::ScopedJavaGlobalRef<jobject>());
   j_object_ptr->Reset(base::android::AttachCurrentThread(), object);
diff --git a/media/base/android/android_util.h b/media/base/android/android_util.h
index 2e7b968..527882e 100644
--- a/media/base/android/android_util.h
+++ b/media/base/android/android_util.h
@@ -15,6 +15,11 @@
 // Converts jbyteArray (byte[] in Java) into std::string.
 std::string JavaBytesToString(JNIEnv* env, jbyteArray j_byte_array);
 
+// Converts std::string to jbyteArray (byte[] in Java).
+base::android::ScopedJavaLocalRef<jbyteArray> StringToJavaBytes(
+    JNIEnv* env,
+    const std::string& str);
+
 // A helper method to create a JavaObjectPtr.
 JavaObjectPtr CreateJavaObjectPtr(jobject object);
 
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
index c84061c..df74868ac 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmBridge.java
@@ -97,6 +97,41 @@
     // Boolean to track if 'ORIGIN' is set in MediaDrm.
     private boolean mOriginSet = false;
 
+    // Delay the MediaDrm event handle if present.
+    private SessionEventDeferrer mSessionEventDeferrer = null;
+
+    // Block MediaDrm event for |mSessionId|. MediaDrm may fire event before the
+    // functions return. This may break Chromium CDM API's assumption. For
+    // example, when loading session, 'restoreKeys' will trigger key status
+    // change event. But the session isn't known to Chromium CDM because the
+    // promise isn't resolved. The class can block and collect these events and
+    // fire these events later.
+    private static class SessionEventDeferrer {
+        private final SessionId mSessionId;
+        private final ArrayList<Runnable> mEventHandlers;
+
+        SessionEventDeferrer(SessionId sessionId) {
+            mSessionId = sessionId;
+            mEventHandlers = new ArrayList<>();
+        }
+
+        boolean shouldDefer(SessionId sessionId) {
+            return mSessionId.isEqual(sessionId);
+        }
+
+        void defer(Runnable handler) {
+            mEventHandlers.add(handler);
+        }
+
+        void fire() {
+            for (Runnable r : mEventHandlers) {
+                r.run();
+            }
+
+            mEventHandlers.clear();
+        }
+    }
+
     /**
      *  An equivalent of MediaDrm.KeyStatus, which is only available on M+.
      */
@@ -573,8 +608,10 @@
         MediaDrm.KeyRequest request = null;
 
         try {
-            request = mMediaDrm.getKeyRequest(
-                    sessionId.drmId(), data, mime, keyType, optionalParameters);
+            byte[] scopeId =
+                    keyType == MediaDrm.KEY_TYPE_RELEASE ? sessionId.keySetId() : sessionId.drmId();
+            assert scopeId != null;
+            request = mMediaDrm.getKeyRequest(scopeId, data, mime, keyType, optionalParameters);
         } catch (IllegalStateException e) {
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && e
                     instanceof android.media.MediaDrm.MediaDrmStateException) {
@@ -825,19 +862,27 @@
 
         try {
             SessionInfo sessionInfo = mSessionManager.get(sessionId);
-            byte[] keySetId = mMediaDrm.provideKeyResponse(sessionId.drmId(), response);
+            boolean isKeyRelease = sessionInfo.keyType() == MediaDrm.KEY_TYPE_RELEASE;
 
-            if (keySetId != null && keySetId.length > 0) {
-                assert sessionInfo.keyType() == MediaDrm.KEY_TYPE_OFFLINE;
-                mSessionManager.setKeySetId(sessionId, keySetId, new Callback<Boolean>() {
-                    @Override
-                    public void onResult(Boolean success) {
-                        onKeyUpdated(sessionId, promiseId, success);
-                    }
-                });
+            byte[] keySetId = null;
+            if (isKeyRelease) {
+                Log.d(TAG, "updateSession() for key release");
+                assert sessionId.keySetId() != null;
+                mMediaDrm.provideKeyResponse(sessionId.keySetId(), response);
+            } else {
+                keySetId = mMediaDrm.provideKeyResponse(sessionId.drmId(), response);
+            }
+
+            KeyUpdatedCallback cb = new KeyUpdatedCallback(sessionId, promiseId, isKeyRelease);
+
+            if (isKeyRelease) {
+                mSessionManager.clearPersistentSessionInfo(sessionId, cb);
+            } else if (sessionInfo.keyType() == MediaDrm.KEY_TYPE_OFFLINE && keySetId != null
+                    && keySetId.length > 0) {
+                mSessionManager.setKeySetId(sessionId, keySetId, cb);
             } else {
                 // This can be either temporary license update or server certificate update.
-                onKeyUpdated(sessionId, promiseId, true);
+                cb.onResult(true);
             }
 
             return;
@@ -853,18 +898,139 @@
         release();
     }
 
-    private void onKeyUpdated(SessionId sessionId, long promiseId, boolean success) {
-        if (!success) {
-            onPromiseRejected(promiseId, "failed to update key after response accepted");
+    /**
+     * Load persistent license from storage.
+     */
+    @CalledByNative
+    private void loadSession(byte[] emeId, final long promiseId) {
+        Log.d(TAG, "loadSession()");
+        if (mProvisioningPending) {
+            onPersistentLicenseNoExist(promiseId);
             return;
         }
 
-        Log.d(TAG, "Key successfully added for session %s", sessionId.toHexString());
-        onPromiseResolved(promiseId);
+        mSessionManager.load(emeId, new Callback<SessionId>() {
+            @Override
+            public void onResult(SessionId sessionId) {
+                if (sessionId == null) {
+                    onPersistentLicenseNoExist(promiseId);
+                    return;
+                }
 
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
-            onSessionKeysChange(
-                    sessionId, getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE).toArray(), true);
+                loadSessionWithLoadedStorage(sessionId, promiseId);
+            }
+        });
+    }
+
+    /**
+     * Load session back to memory with MediaDrm. Load persistent storage
+     * before calling this. It will fail if persistent storage isn't loaded.
+     */
+    private void loadSessionWithLoadedStorage(SessionId sessionId, final long promiseId) {
+        byte[] drmId = null;
+        try {
+            drmId = openSession();
+            if (drmId == null) {
+                onPromiseRejected(promiseId, "Failed to open session to load license");
+                return;
+            }
+
+            mSessionManager.setDrmId(sessionId, drmId);
+
+            // Defer event handlers until license is loaded.
+            assert mSessionEventDeferrer == null;
+            mSessionEventDeferrer = new SessionEventDeferrer(sessionId);
+
+            assert sessionId.keySetId() != null;
+            mMediaDrm.restoreKeys(sessionId.drmId(), sessionId.keySetId());
+
+            onPromiseResolvedWithSession(promiseId, sessionId);
+
+            mSessionEventDeferrer.fire();
+            mSessionEventDeferrer = null;
+
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+                onSessionKeysChange(sessionId,
+                        getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE).toArray(), true, false);
+            }
+        } catch (android.media.NotProvisionedException e) {
+            // If device isn't provisioned, storage loading should fail.
+            assert false;
+        } catch (java.lang.IllegalStateException e) {
+            // license doesn't exist
+            if (sessionId.drmId() == null) {
+                // TODO(yucliu): Check if the license is released or doesn't exist.
+                onPersistentLicenseNoExist(promiseId);
+                return;
+            }
+
+            closeSessionNoException(sessionId);
+            mSessionManager.clearPersistentSessionInfo(sessionId, new Callback<Boolean>() {
+                @Override
+                public void onResult(Boolean success) {
+                    if (!success) {
+                        Log.w(TAG, "Failed to clear persistent storage for non-exist license");
+                    }
+
+                    onPersistentLicenseNoExist(promiseId);
+                }
+            });
+        }
+    }
+
+    private void onPersistentLicenseNoExist(long promiseId) {
+        // Chromium CDM API requires resolve the promise with empty session id for non-exist
+        // license. See media/base/content_decryption_module.h LoadSession for more details.
+        onPromiseResolvedWithSession(promiseId, SessionId.createNoExistSessionId());
+    }
+
+    /**
+     * Remove session from device. This will mark the key as released and
+     * generate a key release request. The license is removed from the device
+     * when the session is updated with a license release response.
+     */
+    @CalledByNative
+    private void removeSession(byte[] emeId, long promiseId) {
+        Log.d(TAG, "removeSession()");
+        SessionId sessionId = getSessionIdByEmeId(emeId);
+
+        if (sessionId == null) {
+            onPromiseRejected(promiseId, "Session doesn't exist");
+            return;
+        }
+
+        SessionInfo sessionInfo = mSessionManager.get(sessionId);
+        if (sessionInfo.keyType() != MediaDrm.KEY_TYPE_OFFLINE) {
+            // TODO(yucliu): Support 'remove' of temporary session.
+            onPromiseRejected(promiseId, "Removing temporary session isn't implemented");
+            return;
+        }
+
+        assert sessionId.keySetId() != null;
+
+        mSessionManager.markKeyReleased(sessionId);
+
+        try {
+            // Get key release request.
+            MediaDrm.KeyRequest request = getKeyRequest(
+                    sessionId, null, sessionInfo.mimeType(), MediaDrm.KEY_TYPE_RELEASE, null);
+
+            if (request == null) {
+                onPromiseRejected(promiseId, "Fail to generate key release request");
+                return;
+            }
+
+            // According to EME spec:
+            // https://www.w3.org/TR/encrypted-media/#dom-mediakeysession-remove
+            // 5.5 ... run the Queue a "message" Event ...
+            // 5.6 Resolve promise
+            // Since event is queued, JS will receive event after promise is
+            // resolved. So resolve the promise before firing the event here.
+            onPromiseResolved(promiseId);
+            onSessionMessage(sessionId, request);
+        } catch (android.media.NotProvisionedException e) {
+            Log.e(TAG, "removeSession called on unprovisioned device");
+            onPromiseRejected(promiseId, "Unknown failure");
         }
     }
 
@@ -969,6 +1135,19 @@
         return false;
     }
 
+    /**
+     * Delay session event handler if |mSessionEventDeferrer| exists and
+     * matches |sessionId|. Otherwise run the handler immediately.
+     */
+    private void deferEventHandleIfNeeded(SessionId sessionId, Runnable handler) {
+        if (mSessionEventDeferrer != null && mSessionEventDeferrer.shouldDefer(sessionId)) {
+            mSessionEventDeferrer.defer(handler);
+            return;
+        }
+
+        handler.run();
+    }
+
     // Helper functions to make native calls.
 
     private void onMediaCryptoReady(MediaCrypto mediaCrypto) {
@@ -1022,10 +1201,10 @@
     }
 
     private void onSessionKeysChange(final SessionId sessionId, final Object[] keysInfo,
-            final boolean hasAdditionalUsableKey) {
+            final boolean hasAdditionalUsableKey, final boolean isKeyRelease) {
         if (isNativeMediaDrmBridgeValid()) {
-            nativeOnSessionKeysChange(
-                    mNativeMediaDrmBridge, sessionId.emeId(), keysInfo, hasAdditionalUsableKey);
+            nativeOnSessionKeysChange(mNativeMediaDrmBridge, sessionId.emeId(), keysInfo,
+                    hasAdditionalUsableKey, isKeyRelease);
         }
     }
 
@@ -1059,13 +1238,13 @@
                 return;
             }
 
+            SessionInfo sessionInfo = mSessionManager.get(sessionId);
             switch(event) {
                 case MediaDrm.EVENT_KEY_REQUIRED:
                     Log.d(TAG, "MediaDrm.EVENT_KEY_REQUIRED");
                     if (mProvisioningPending) {
                         return;
                     }
-                    SessionInfo sessionInfo = mSessionManager.get(sessionId);
                     MediaDrm.KeyRequest request = null;
                     try {
                         request = getKeyRequest(sessionId, data, sessionInfo.mimeType(),
@@ -1082,7 +1261,7 @@
                             onSessionKeysChange(sessionId,
                                     getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_INTERNAL_ERROR)
                                             .toArray(),
-                                    false);
+                                    false, false);
                         }
                         Log.e(TAG, "EventListener: getKeyRequest failed.");
                         return;
@@ -1093,7 +1272,7 @@
                     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
                         onSessionKeysChange(sessionId,
                                 getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_EXPIRED).toArray(),
-                                false);
+                                false, sessionInfo.keyType() == MediaDrm.KEY_TYPE_RELEASE);
                     }
                     break;
                 case MediaDrm.EVENT_VENDOR_DEFINED:
@@ -1120,14 +1299,25 @@
 
         @Override
         public void onKeyStatusChange(MediaDrm md, byte[] drmSessionId,
-                List<MediaDrm.KeyStatus> keyInformation, boolean hasNewUsableKey) {
-            SessionId sessionId = getSessionIdByDrmId(drmSessionId);
+                final List<MediaDrm.KeyStatus> keyInformation, final boolean hasNewUsableKey) {
+            final SessionId sessionId = getSessionIdByDrmId(drmSessionId);
 
             assert sessionId != null;
+            assert mSessionManager.get(sessionId) != null;
 
-            Log.d(TAG, "KeysStatusChange: " + sessionId.toHexString() + ", " + hasNewUsableKey);
+            final boolean isKeyRelease =
+                    mSessionManager.get(sessionId).keyType() == MediaDrm.KEY_TYPE_RELEASE;
 
-            onSessionKeysChange(sessionId, getKeysInfo(keyInformation).toArray(), hasNewUsableKey);
+            deferEventHandleIfNeeded(sessionId, new Runnable() {
+                @Override
+                public void run() {
+                    Log.d(TAG,
+                            "KeysStatusChange: " + sessionId.toHexString() + ", "
+                                    + hasNewUsableKey);
+                    onSessionKeysChange(sessionId, getKeysInfo(keyInformation).toArray(),
+                            hasNewUsableKey, isKeyRelease);
+                }
+            });
         }
     }
 
@@ -1135,13 +1325,51 @@
     @MainDex
     private class ExpirationUpdateListener implements MediaDrm.OnExpirationUpdateListener {
         @Override
-        public void onExpirationUpdate(MediaDrm md, byte[] drmSessionId, long expirationTime) {
-            SessionId sessionId = getSessionIdByDrmId(drmSessionId);
+        public void onExpirationUpdate(
+                MediaDrm md, byte[] drmSessionId, final long expirationTime) {
+            final SessionId sessionId = getSessionIdByDrmId(drmSessionId);
 
             assert sessionId != null;
 
-            Log.d(TAG, "ExpirationUpdate: " + sessionId.toHexString() + ", " + expirationTime);
-            onSessionExpirationUpdate(sessionId, expirationTime);
+            deferEventHandleIfNeeded(sessionId, new Runnable() {
+                @Override
+                public void run() {
+                    Log.d(TAG,
+                            "ExpirationUpdate: " + sessionId.toHexString() + ", " + expirationTime);
+                    onSessionExpirationUpdate(sessionId, expirationTime);
+                }
+            });
+        }
+    }
+
+    @MainDex
+    private class KeyUpdatedCallback extends Callback<Boolean> {
+        private final SessionId mSessionId;
+        private final long mPromiseId;
+        private final boolean mIsKeyRelease;
+
+        KeyUpdatedCallback(SessionId sessionId, long promiseId, boolean isKeyRelease) {
+            mSessionId = sessionId;
+            mPromiseId = promiseId;
+            mIsKeyRelease = isKeyRelease;
+        }
+
+        @Override
+        public void onResult(Boolean success) {
+            if (!success) {
+                onPromiseRejected(mPromiseId, "failed to update key after response accepted");
+                return;
+            }
+
+            Log.d(TAG, "Key successfully %s for session %s", mIsKeyRelease ? "released" : "added",
+                    mSessionId.toHexString());
+            onPromiseResolved(mPromiseId);
+
+            if (!mIsKeyRelease && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+                onSessionKeysChange(mSessionId,
+                        getDummyKeysInfo(MediaDrm.KeyStatus.STATUS_USABLE).toArray(), true,
+                        mIsKeyRelease);
+            }
         }
     }
 
@@ -1163,7 +1391,7 @@
             long nativeMediaDrmBridge, byte[] emeSessionId, int requestType, byte[] message);
     private native void nativeOnSessionClosed(long nativeMediaDrmBridge, byte[] emeSessionId);
     private native void nativeOnSessionKeysChange(long nativeMediaDrmBridge, byte[] emeSessionId,
-            Object[] keysInfo, boolean hasAdditionalUsableKey);
+            Object[] keysInfo, boolean hasAdditionalUsableKey, boolean isKeyRelease);
     private native void nativeOnSessionExpirationUpdate(
             long nativeMediaDrmBridge, byte[] emeSessionId, long expirationTime);
 
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmSessionManager.java b/media/base/android/java/src/org/chromium/media/MediaDrmSessionManager.java
index 42e6675..8bf38f5 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmSessionManager.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmSessionManager.java
@@ -87,6 +87,13 @@
             return new SessionId(drmId, drmId, null /* keySetId */);
         }
 
+        /**
+         * Create session ID used to report session doesn't exist.
+         */
+        static SessionId createNoExistSessionId() {
+            return createTemporarySessionId(new byte[0]);
+        }
+
         private SessionId(byte[] emeId, byte[] drmId, byte[] keySetId) {
             assert emeId != null;
             assert drmId != null || keySetId != null;
@@ -165,6 +172,16 @@
 
             return new PersistentInfo(mSessionId.emeId(), mSessionId.keySetId(), mMimeType);
         }
+
+        private static SessionInfo fromPersistentInfo(PersistentInfo persistentInfo) {
+            assert persistentInfo != null;
+            assert persistentInfo.emeId() != null;
+            assert persistentInfo.keySetId() != null;
+
+            SessionId sessionId = new SessionId(
+                    persistentInfo.emeId(), null /* drmId */, persistentInfo.keySetId());
+            return new SessionInfo(sessionId, persistentInfo.mimeType(), MediaDrm.KEY_TYPE_OFFLINE);
+        }
     }
 
     // Maps from DRM/EME session ID to SessionInfo. SessionInfo contains
@@ -189,6 +206,20 @@
     }
 
     /**
+     * Set drm ID. It should only be called for persistent license session
+     * without an opened drm session.
+     */
+    void setDrmId(SessionId sessionId, byte[] drmId) {
+        SessionInfo info = get(sessionId);
+
+        assert info != null;
+        assert info.sessionId().isEqual(sessionId);
+
+        sessionId.setDrmId(drmId);
+        mDrmSessionInfoMap.put(ByteBuffer.wrap(drmId), info);
+    }
+
+    /**
      * Set key set ID. It should only be called for persistent license session.
      */
     void setKeySetId(SessionId sessionId, byte[] keySetId, Callback<Boolean> callback) {
@@ -202,6 +233,50 @@
     }
 
     /**
+     * Mark key as released. It should only be called for persistent license
+     * session.
+     */
+    void markKeyReleased(SessionId sessionId) {
+        SessionInfo info = get(sessionId);
+
+        assert info != null;
+        assert info.keyType() == MediaDrm.KEY_TYPE_OFFLINE;
+
+        info.setKeyType(MediaDrm.KEY_TYPE_RELEASE);
+    }
+
+    /**
+     * Load |emeId|'s session data from persistent storage.
+     */
+    void load(byte[] emeId, final Callback<SessionId> callback) {
+        mStorage.loadInfo(emeId, new Callback<PersistentInfo>() {
+            @Override
+            public void onResult(PersistentInfo persistentInfo) {
+                if (persistentInfo == null) {
+                    callback.onResult(null);
+                    return;
+                }
+
+                // Loading same persistent license into different sessions isn't
+                // supported.
+                assert getSessionIdByEmeId(persistentInfo.emeId()) == null;
+
+                SessionInfo info = SessionInfo.fromPersistentInfo(persistentInfo);
+                mEmeSessionInfoMap.put(ByteBuffer.wrap(persistentInfo.emeId()), info);
+                callback.onResult(info.sessionId());
+            }
+        });
+    }
+
+    /**
+     * Remove persistent license info from persistent storage.
+     */
+    void clearPersistentSessionInfo(SessionId sessionId, Callback<Boolean> callback) {
+        sessionId.setKeySetId(null);
+        mStorage.clearInfo(sessionId.emeId(), callback);
+    }
+
+    /**
      * Remove session and related infomration from memory, but doesn't touch
      * persistent storage.
      */
diff --git a/media/base/android/java/src/org/chromium/media/MediaDrmStorageBridge.java b/media/base/android/java/src/org/chromium/media/MediaDrmStorageBridge.java
index c085f1d9..92c90ac 100644
--- a/media/base/android/java/src/org/chromium/media/MediaDrmStorageBridge.java
+++ b/media/base/android/java/src/org/chromium/media/MediaDrmStorageBridge.java
@@ -42,6 +42,18 @@
             mKeySetId = keySetId;
             mMimeType = mime;
         }
+
+        byte[] emeId() {
+            return mEmeId;
+        }
+
+        byte[] keySetId() {
+            return mKeySetId;
+        }
+
+        String mimeType() {
+            return mMimeType;
+        }
     }
 
     MediaDrmStorageBridge(long nativeMediaDrmStorageBridge) {
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index 83b14ae..4ec2eed 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -124,12 +124,14 @@
   return ContentDecryptionModule::LICENSE_REQUEST;
 }
 
-CdmKeyInformation::KeyStatus ConvertKeyStatus(KeyStatus key_status) {
+CdmKeyInformation::KeyStatus ConvertKeyStatus(KeyStatus key_status,
+                                              bool is_key_release) {
   switch (key_status) {
     case KeyStatus::KEY_STATUS_USABLE:
       return CdmKeyInformation::USABLE;
     case KeyStatus::KEY_STATUS_EXPIRED:
-      return CdmKeyInformation::EXPIRED;
+      return is_key_release ? CdmKeyInformation::RELEASED
+                            : CdmKeyInformation::EXPIRED;
     case KeyStatus::KEY_STATUS_OUTPUT_NOT_ALLOWED:
       return CdmKeyInformation::OUTPUT_RESTRICTED;
     case KeyStatus::KEY_STATUS_PENDING:
@@ -256,6 +258,13 @@
   return true;
 }
 
+bool IsPersistentLicenseTypeSupportedByMediaDrm() {
+  return MediaDrmBridge::IsAvailable() &&
+         // In development. See http://crbug.com/493521
+         base::FeatureList::IsEnabled(kMediaDrmPersistentLicense) &&
+         base::android::BuildInfo::GetInstance()->sdk_int() >= 23;
+}
+
 }  // namespace
 
 // MediaDrm is not generally usable without MediaCodec. Thus, both the MediaDrm
@@ -281,15 +290,9 @@
 // static
 bool MediaDrmBridge::IsPersistentLicenseTypeSupported(
     const std::string& key_system) {
-  if (!MediaDrmBridge::IsAvailable())
-    return false;
-
-  if (!base::FeatureList::IsEnabled(kMediaDrmPersistentLicense)) {
-    return false;
-  }
-
-  NOTIMPLEMENTED() << "In development. See http://crbug.com/493521";
-  return false;
+  // TODO(yucliu): Check |key_system| if persistent license is supported by
+  // MediaDrm.
+  return IsPersistentLicenseTypeSupportedByMediaDrm();
 }
 
 // static
@@ -460,11 +463,20 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
   DVLOG(2) << __func__;
 
-  DCHECK(base::FeatureList::IsEnabled(kMediaDrmPersistentLicense));
+  DCHECK(IsPersistentLicenseTypeSupportedByMediaDrm());
 
-  NOTIMPLEMENTED() << "EME persistent sessions not yet supported on Android.";
-  promise->reject(CdmPromise::NOT_SUPPORTED_ERROR, 0,
-                  "LoadSession() is not supported.");
+  if (session_type != CdmSessionType::PERSISTENT_LICENSE_SESSION) {
+    promise->reject(
+        CdmPromise::NOT_SUPPORTED_ERROR, 0,
+        "LoadSession() is only supported for 'persistent-license'.");
+    return;
+  }
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> j_session_id =
+      StringToJavaBytes(env, session_id);
+  uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
+  Java_MediaDrmBridge_loadSession(env, j_media_drm_, j_session_id, promise_id);
 }
 
 void MediaDrmBridge::UpdateSession(
@@ -477,9 +489,8 @@
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jbyteArray> j_response =
       base::android::ToJavaByteArray(env, response.data(), response.size());
-  ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray(
-      env, reinterpret_cast<const uint8_t*>(session_id.data()),
-      session_id.size());
+  ScopedJavaLocalRef<jbyteArray> j_session_id =
+      StringToJavaBytes(env, session_id);
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
   Java_MediaDrmBridge_updateSession(env, j_media_drm_, j_session_id, j_response,
                                     promise_id);
@@ -492,9 +503,8 @@
   DVLOG(2) << __func__;
 
   JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jbyteArray> j_session_id = base::android::ToJavaByteArray(
-      env, reinterpret_cast<const uint8_t*>(session_id.data()),
-      session_id.size());
+  ScopedJavaLocalRef<jbyteArray> j_session_id =
+      StringToJavaBytes(env, session_id);
   uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
   Java_MediaDrmBridge_closeSession(env, j_media_drm_, j_session_id, promise_id);
 }
@@ -505,9 +515,12 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
   DVLOG(2) << __func__;
 
-  NOTIMPLEMENTED() << "EME persistent sessions not yet supported on Android.";
-  promise->reject(CdmPromise::NOT_SUPPORTED_ERROR, 0,
-                  "RemoveSession() is not supported.");
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> j_session_id =
+      StringToJavaBytes(env, session_id);
+  uint32_t promise_id = cdm_promise_adapter_.SavePromise(std::move(promise));
+  Java_MediaDrmBridge_removeSession(env, j_media_drm_, j_session_id,
+                                    promise_id);
 }
 
 CdmContext* MediaDrmBridge::GetCdmContext() {
@@ -698,7 +711,8 @@
     const JavaParamRef<jobject>& j_media_drm,
     const JavaParamRef<jbyteArray>& j_session_id,
     const JavaParamRef<jobjectArray>& j_keys_info,
-    bool has_additional_usable_key) {
+    bool has_additional_usable_key,
+    bool is_key_release) {
   DVLOG(2) << __func__;
 
   CdmKeysInfo cdm_keys_info;
@@ -718,7 +732,7 @@
 
     jint j_status_code = Java_KeyStatus_getStatusCode(env, j_key_status);
     CdmKeyInformation::KeyStatus key_status =
-        ConvertKeyStatus(static_cast<KeyStatus>(j_status_code));
+        ConvertKeyStatus(static_cast<KeyStatus>(j_status_code), is_key_release);
 
     DVLOG(2) << __func__ << "Key status change: "
              << base::HexEncode(&key_id[0], key_id.size()) << ", "
@@ -916,8 +930,7 @@
 
   JNIEnv* env = AttachCurrentThread();
 
-  ScopedJavaLocalRef<jbyteArray> j_response = base::android::ToJavaByteArray(
-      env, reinterpret_cast<const uint8_t*>(response.data()), response.size());
+  ScopedJavaLocalRef<jbyteArray> j_response = StringToJavaBytes(env, response);
 
   Java_MediaDrmBridge_processProvisionResponse(env, j_media_drm_, success,
                                                j_response);
diff --git a/media/base/android/media_drm_bridge.h b/media/base/android/media_drm_bridge.h
index 598d20f..d86ee79 100644
--- a/media/base/android/media_drm_bridge.h
+++ b/media/base/android/media_drm_bridge.h
@@ -214,12 +214,17 @@
       const base::android::JavaParamRef<jobject>& j_media_drm,
       const base::android::JavaParamRef<jbyteArray>& j_session_id);
 
+  // Called when key statuses of session are changed. |is_key_release| is set to
+  // true when releasing keys. Some of the MediaDrm key status codes should be
+  // mapped to CDM key status differently (e.g. EXPIRE -> RELEASED).
   void OnSessionKeysChange(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& j_media_drm,
       const base::android::JavaParamRef<jbyteArray>& j_session_id,
+      // List<KeyStatus>
       const base::android::JavaParamRef<jobjectArray>& j_keys_info,
-      bool has_additional_usable_key);
+      bool has_additional_usable_key,
+      bool is_key_release);
 
   // |expiry_time_ms| is the new expiration time for the keys in the session.
   // The time is in milliseconds, relative to the Unix epoch. A time of 0
diff --git a/media/base/eme_constants.h b/media/base/eme_constants.h
index 7a7d933..1d9fd910 100644
--- a/media/base/eme_constants.h
+++ b/media/base/eme_constants.h
@@ -25,22 +25,23 @@
   EME_CODEC_NONE = 0,
   EME_CODEC_WEBM_OPUS = 1 << 0,
   EME_CODEC_WEBM_VORBIS = 1 << 1,
-  EME_CODEC_WEBM_AUDIO_ALL = EME_CODEC_WEBM_OPUS | EME_CODEC_WEBM_VORBIS,
   EME_CODEC_WEBM_VP8 = 1 << 2,
   EME_CODEC_WEBM_VP9 = 1 << 3,
-  EME_CODEC_WEBM_VIDEO_ALL = (EME_CODEC_WEBM_VP8 | EME_CODEC_WEBM_VP9),
+  EME_CODEC_MP4_AAC = 1 << 4,
+  EME_CODEC_MP4_AVC1 = 1 << 5,
+  EME_CODEC_COMMON_VP9 = 1 << 6,
+  EME_CODEC_MP4_HEVC = 1 << 7,
+  EME_CODEC_WEBM_AUDIO_ALL = EME_CODEC_WEBM_OPUS | EME_CODEC_WEBM_VORBIS,
+  EME_CODEC_WEBM_VIDEO_ALL =
+      (EME_CODEC_WEBM_VP8 | EME_CODEC_WEBM_VP9 | EME_CODEC_COMMON_VP9),
   EME_CODEC_WEBM_ALL = (EME_CODEC_WEBM_AUDIO_ALL | EME_CODEC_WEBM_VIDEO_ALL),
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-  EME_CODEC_MP4_AAC = 1 << 4,
   EME_CODEC_MP4_AUDIO_ALL = EME_CODEC_MP4_AAC,
-  EME_CODEC_MP4_AVC1 = 1 << 5,
-  EME_CODEC_MP4_VP9 = 1 << 6,
 #if !BUILDFLAG(ENABLE_HEVC_DEMUXING)
-  EME_CODEC_MP4_VIDEO_ALL = (EME_CODEC_MP4_AVC1 | EME_CODEC_MP4_VP9),
+  EME_CODEC_MP4_VIDEO_ALL = (EME_CODEC_MP4_AVC1 | EME_CODEC_COMMON_VP9),
 #else
-  EME_CODEC_MP4_HEVC = 1 << 7,
   EME_CODEC_MP4_VIDEO_ALL =
-      (EME_CODEC_MP4_AVC1 | EME_CODEC_MP4_VP9 | EME_CODEC_MP4_HEVC),
+      (EME_CODEC_MP4_AVC1 | EME_CODEC_COMMON_VP9 | EME_CODEC_MP4_HEVC),
 #endif
   EME_CODEC_MP4_ALL = (EME_CODEC_MP4_AUDIO_ALL | EME_CODEC_MP4_VIDEO_ALL),
   EME_CODEC_AUDIO_ALL = (EME_CODEC_WEBM_AUDIO_ALL | EME_CODEC_MP4_AUDIO_ALL),
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc
index 4dee18a..27bd0877 100644
--- a/media/base/key_systems.cc
+++ b/media/base/key_systems.cc
@@ -57,8 +57,8 @@
     {"vp8.0", EME_CODEC_WEBM_VP8},      // VP8.
     {"vp9", EME_CODEC_WEBM_VP9},        // VP9.
     {"vp9.0", EME_CODEC_WEBM_VP9},      // VP9.
+    {"vp09", EME_CODEC_COMMON_VP9},     // New multi-part VP9 for WebM and MP4.
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-    {"vp09", EME_CODEC_MP4_VP9},   // VP9 in MP4.
     {"mp4a", EME_CODEC_MP4_AAC},   // AAC.
     {"avc1", EME_CODEC_MP4_AVC1},  // AVC1.
     {"avc3", EME_CODEC_MP4_AVC1},  // AVC3.
@@ -599,15 +599,21 @@
   // necessary because |codecs| may be empty.)
   SupportedCodecs mime_type_codec_mask =
       GetCodecMaskForMimeType(container_mime_type);
-  if ((key_system_codec_mask & mime_type_codec_mask) == 0)
+  if ((key_system_codec_mask & mime_type_codec_mask) == 0) {
+    DVLOG(2) << " Container " << container_mime_type << " not supported by "
+             << key_system;
     return EmeConfigRule::NOT_SUPPORTED;
+  }
 
   // Check that the codecs are supported by the key system and container.
   EmeConfigRule support = EmeConfigRule::SUPPORTED;
   for (size_t i = 0; i < codecs.size(); i++) {
     SupportedCodecs codec = GetCodecForString(codecs[i]);
-    if ((codec & key_system_codec_mask & mime_type_codec_mask) == 0)
+    if ((codec & key_system_codec_mask & mime_type_codec_mask) == 0) {
+      DVLOG(2) << " Container/codec pair (" << container_mime_type << " / "
+               << codecs[i] << ") not supported by " << key_system;
       return EmeConfigRule::NOT_SUPPORTED;
+    }
 #if defined(OS_ANDROID)
     // Check whether the codec supports a hardware-secure mode. The goal is to
     // prevent mixing of non-hardware-secure codecs with hardware-secure codecs,
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc
index 9bb4099..affb8cc3 100644
--- a/media/base/mime_util_internal.cc
+++ b/media/base/mime_util_internal.cc
@@ -202,12 +202,16 @@
     if (!ParseCodecString(mime_type_lower_case, codecs[i], &codec,
                           &ambiguous_codec_string, &video_profile, &video_level,
                           &color_space)) {
+      DVLOG(2) << __func__ << " Failed to parse codec string:" << codecs[i];
       return IsNotSupported;
     }
 
     // Bail if codec not in supported list for given container.
-    if (supported_codecs.find(codec) == supported_codecs.end())
+    if (supported_codecs.find(codec) == supported_codecs.end()) {
+      DVLOG(2) << __func__ << " Codec " << codecs[i]
+               << " not supported in container " << mime_type_lower_case;
       return IsNotSupported;
+    }
 
     // Make conservative guesses to resolve ambiguity before checking platform
     // support. H264 and VP9 are the only allowed ambiguous video codec. DO NOT
@@ -228,8 +232,11 @@
     SupportsType result =
         IsCodecSupported(mime_type_lower_case, codec, video_profile,
                          video_level, color_space, is_encrypted);
-    if (result == IsNotSupported)
+    if (result == IsNotSupported) {
+      DVLOG(2) << __func__ << " Codec " << codecs[i]
+               << " not supported by platform";
       return IsNotSupported;
+    }
 
     // If any codec is "MayBeSupported", return Maybe for the combined result.
     // Downgrade to MayBeSupported if we had to guess the meaning of one of the
diff --git a/media/blink/key_system_config_selector.cc b/media/blink/key_system_config_selector.cc
index 5fcd5675b..6026675a 100644
--- a/media/blink/key_system_config_selector.cc
+++ b/media/blink/key_system_config_selector.cc
@@ -323,8 +323,11 @@
   // contentTypes must provide a codec string unless the container implies a
   // particular codec. For EME, none of the currently supported containers
   // imply a codec, so |codecs| must be provided.
-  if (codecs.empty())
+  if (codecs.empty()) {
+    DVLOG(3) << __func__ << " KeySystemConfig for " << container_mime_type
+             << " does not specify necessary codecs.";
     return false;
+  }
 
   // Check that |container_mime_type| and |codecs| are supported by Chrome. This
   // is done primarily to validate extended codecs, but it also ensures that the
diff --git a/media/mojo/common/media_type_converters.cc b/media/mojo/common/media_type_converters.cc
index f8f7225..61b8922 100644
--- a/media/mojo/common/media_type_converters.cc
+++ b/media/mojo/common/media_type_converters.cc
@@ -218,6 +218,7 @@
   config->extra_data = input.extra_data();
   config->encryption_scheme =
       media::mojom::EncryptionScheme::From(input.encryption_scheme());
+  config->color_space_info = input.color_space_info();
   return config;
 }
 
@@ -230,6 +231,7 @@
                     input->color_space, input->coded_size, input->visible_rect,
                     input->natural_size, input->extra_data,
                     input->encryption_scheme.To<media::EncryptionScheme>());
+  config.set_color_space_info(input->color_space_info);
   return config;
 }
 
diff --git a/media/mojo/common/media_type_converters_unittest.cc b/media/mojo/common/media_type_converters_unittest.cc
index 82c741d..f9e0fac 100644
--- a/media/mojo/common/media_type_converters_unittest.cc
+++ b/media/mojo/common/media_type_converters_unittest.cc
@@ -347,6 +347,19 @@
   EXPECT_TRUE(result.Matches(config));
 }
 
+TEST(MediaTypeConvertersTest, ConvertVideoDecoderConfig_ColorSpaceInfo) {
+  VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12,
+                            COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect,
+                            kNaturalSize, EmptyExtraData(), Unencrypted());
+  config.set_color_space_info(VideoColorSpace(
+      VideoColorSpace::PrimaryID::BT2020,
+      VideoColorSpace::TransferID::SMPTEST2084,
+      VideoColorSpace::MatrixID::BT2020_CL, gfx::ColorSpace::RangeID::LIMITED));
+  mojom::VideoDecoderConfigPtr ptr(mojom::VideoDecoderConfig::From(config));
+  VideoDecoderConfig result(ptr.To<VideoDecoderConfig>());
+  EXPECT_TRUE(result.Matches(config));
+}
+
 TEST(MediaTypeConvertersTest, ConvertCdmConfig) {
   CdmConfig config;
   config.allow_distinctive_identifier = true;
diff --git a/media/mojo/interfaces/media_types.mojom b/media/mojo/interfaces/media_types.mojom
index bd91003..ae20147 100644
--- a/media/mojo/interfaces/media_types.mojom
+++ b/media/mojo/interfaces/media_types.mojom
@@ -65,6 +65,27 @@
   Pattern pattern;
 };
 
+// This defines a mojo transport format for media::VideoColorSpace.
+// See media/base/video_color_space.h for description.
+struct VideoColorSpace {
+  [Native]
+  enum PrimaryID;
+
+  [Native]
+  enum TransferID;
+
+  [Native]
+  enum MatrixID;
+
+  [Native]
+  enum RangeID;
+
+  PrimaryID primaries;
+  TransferID transfer;
+  MatrixID matrix;
+  RangeID range;
+};
+
 // This defines a mojo transport format for media::AudioDecoderConfig.
 // See media/base/audio_decoder_config.h for descriptions.
 struct AudioDecoderConfig {
@@ -90,6 +111,7 @@
   gfx.mojom.Size natural_size;
   array<uint8> extra_data;
   EncryptionScheme encryption_scheme;
+  VideoColorSpace color_space_info;
 };
 
 // Native struct media::SubsampleEntry;
diff --git a/media/mojo/interfaces/typemaps.gni b/media/mojo/interfaces/typemaps.gni
index 2bde9f0..1f0377b 100644
--- a/media/mojo/interfaces/typemaps.gni
+++ b/media/mojo/interfaces/typemaps.gni
@@ -9,4 +9,5 @@
   "//media/mojo/interfaces/demuxer_stream.typemap",
   "//media/mojo/interfaces/media_types.typemap",
   "//media/mojo/interfaces/pipeline_statistics.typemap",
+  "//media/mojo/interfaces/video_color_space.typemap",
 ]
diff --git a/media/mojo/interfaces/video_color_space.typemap b/media/mojo/interfaces/video_color_space.typemap
new file mode 100644
index 0000000..70be1d9
--- /dev/null
+++ b/media/mojo/interfaces/video_color_space.typemap
@@ -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.
+
+mojom = "//media/mojo/interfaces/media_types.mojom"
+public_headers = [
+  "//media/base/video_color_space.h",
+  "//ui/gfx/color_space.h",
+]
+traits_headers = [ "//media/mojo/interfaces/video_color_space_struct_traits.h" ]
+type_mappings = [
+  "media.mojom.VideoColorSpace.PrimaryID=media::VideoColorSpace::PrimaryID",
+  "media.mojom.VideoColorSpace.TransferID=media::VideoColorSpace::TransferID",
+  "media.mojom.VideoColorSpace.MatrixID=media::VideoColorSpace::MatrixID",
+  "media.mojom.VideoColorSpace.RangeID=gfx::ColorSpace::RangeID",
+  "media.mojom.VideoColorSpace=media::VideoColorSpace",
+]
diff --git a/media/mojo/interfaces/video_color_space_struct_traits.h b/media/mojo/interfaces/video_color_space_struct_traits.h
new file mode 100644
index 0000000..6e6f7321
--- /dev/null
+++ b/media/mojo/interfaces/video_color_space_struct_traits.h
@@ -0,0 +1,47 @@
+// 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 MEDIA_MOJO_INTERFACES_VIDEO_COLOR_SPACE_STRUCT_TRAITS_H_
+#define MEDIA_MOJO_INTERFACES_VIDEO_COLOR_SPACE_STRUCT_TRAITS_H_
+
+#include "media/base/video_color_space.h"
+#include "media/mojo/interfaces/media_types.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<media::mojom::VideoColorSpaceDataView,
+                    media::VideoColorSpace> {
+  static media::VideoColorSpace::PrimaryID primaries(
+      const media::VideoColorSpace& input) {
+    return input.primaries;
+  }
+  static media::VideoColorSpace::TransferID transfer(
+      const media::VideoColorSpace& input) {
+    return input.transfer;
+  }
+  static media::VideoColorSpace::MatrixID matrix(
+      const media::VideoColorSpace& input) {
+    return input.matrix;
+  }
+  static gfx::ColorSpace::RangeID range(const media::VideoColorSpace& input) {
+    return input.range;
+  }
+
+  static bool Read(media::mojom::VideoColorSpaceDataView data,
+                   media::VideoColorSpace* output) {
+    output->primaries =
+        static_cast<media::VideoColorSpace::PrimaryID>(data.primaries());
+    output->transfer =
+        static_cast<media::VideoColorSpace::TransferID>(data.transfer());
+    output->matrix =
+        static_cast<media::VideoColorSpace::MatrixID>(data.matrix());
+    output->range = static_cast<gfx::ColorSpace::RangeID>(data.range());
+    return true;
+  }
+};
+
+}  // namespace mojo
+
+#endif  // MEDIA_MOJO_INTERFACES_VIDEO_COLOR_SPACE_STRUCT_TRAITS_H_
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index fcff283..e250ceea 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -217,7 +217,8 @@
       enable_ip_based_pooling_(enable_ip_based_pooling),
       delegate_(delegate),
       job_type_(job_type),
-      using_ssl_(false),
+      using_ssl_(origin_url_.SchemeIs(url::kHttpsScheme) ||
+                 origin_url_.SchemeIs(url::kWssScheme)),
       using_spdy_(false),
       using_quic_(false),
       quic_request_(session_->quic_stream_factory(),
@@ -871,8 +872,6 @@
     return OK;
   }
 
-  using_ssl_ = origin_url_.SchemeIs(url::kHttpsScheme) ||
-               origin_url_.SchemeIs(url::kWssScheme);
   using_spdy_ = false;
 
   if (ShouldForceQuic())
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index 0ae7222..4000a25 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -436,8 +436,8 @@
 
   const JobType job_type_;
 
-  // True if handling a HTTPS request, or using SPDY with SSL
-  bool using_ssl_;
+  // True if handling a HTTPS request.
+  const bool using_ssl_;
 
   // True if this network transaction is using SPDY instead of HTTP.
   bool using_spdy_;
@@ -449,9 +449,6 @@
   // True if this job used an existing QUIC session.
   bool using_existing_quic_session_;
 
-  // Force quic for a specific port.
-  int force_quic_port_;
-
   scoped_refptr<HttpAuthController>
       auth_controllers_[HttpAuth::AUTH_NUM_TARGETS];
 
diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc
index b05bacf..c821af32 100644
--- a/net/http/http_stream_factory_impl_job_controller.cc
+++ b/net/http/http_stream_factory_impl_job_controller.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/memory_usage_estimator.h"
 #include "base/values.h"
 #include "net/base/host_mapping_rules.h"
 #include "net/base/proxy_delegate.h"
@@ -681,12 +682,8 @@
 }
 
 size_t HttpStreamFactoryImpl::JobController::EstimateMemoryUsage() const {
-  size_t estimated_size = 0;
-  if (main_job_)
-    estimated_size += main_job_->EstimateMemoryUsage();
-  if (alternative_job_)
-    estimated_size += alternative_job_->EstimateMemoryUsage();
-  return estimated_size;
+  return base::trace_event::EstimateMemoryUsage(main_job_) +
+         base::trace_event::EstimateMemoryUsage(alternative_job_);
 }
 
 WebSocketHandshakeStreamBase::CreateHelper* HttpStreamFactoryImpl::
diff --git a/net/quic/chromium/quic_chromium_client_session.cc b/net/quic/chromium/quic_chromium_client_session.cc
index 64a3a8f4..f58bd05 100644
--- a/net/quic/chromium/quic_chromium_client_session.cc
+++ b/net/quic/chromium/quic_chromium_client_session.cc
@@ -670,11 +670,8 @@
   connect_timing_.connect_start = base::TimeTicks::Now();
   RecordHandshakeState(STATE_STARTED);
   DCHECK(flow_controller());
-  crypto_stream_->CryptoConnect();
 
-  // Check if the connection is still open, issues during CryptoConnect like
-  // packet write error could cause the connection to be torn down.
-  if (!connection()->connected())
+  if (!crypto_stream_->CryptoConnect())
     return ERR_QUIC_HANDSHAKE_FAILED;
 
   if (IsCryptoHandshakeConfirmed()) {
@@ -691,20 +688,6 @@
   return ERR_IO_PENDING;
 }
 
-int QuicChromiumClientSession::ResumeCryptoConnect(
-    const CompletionCallback& callback) {
-  if (IsCryptoHandshakeConfirmed()) {
-    connect_timing_.connect_end = base::TimeTicks::Now();
-    return OK;
-  }
-
-  if (!connection()->connected())
-    return ERR_QUIC_HANDSHAKE_FAILED;
-
-  callback_ = callback;
-  return ERR_IO_PENDING;
-}
-
 int QuicChromiumClientSession::GetNumSentClientHellos() const {
   return crypto_stream_->num_sent_client_hellos();
 }
diff --git a/net/quic/chromium/quic_chromium_client_session.h b/net/quic/chromium/quic_chromium_client_session.h
index 7d9a87b..359df91 100644
--- a/net/quic/chromium/quic_chromium_client_session.h
+++ b/net/quic/chromium/quic_chromium_client_session.h
@@ -216,9 +216,6 @@
   // Performs a crypto handshake with the server.
   int CryptoConnect(const CompletionCallback& callback);
 
-  // Resumes a crypto handshake with the server after a timeout.
-  int ResumeCryptoConnect(const CompletionCallback& callback);
-
   // Causes the QuicConnectionHelper to start reading from all sockets
   // and passing the data along to the QuicConnection.
   void StartReading();
diff --git a/net/quic/chromium/quic_http_stream.cc b/net/quic/chromium/quic_http_stream.cc
index 3b031b9..4debbec0 100644
--- a/net/quic/chromium/quic_http_stream.cc
+++ b/net/quic/chromium/quic_http_stream.cc
@@ -274,7 +274,6 @@
     // A request with a body is ineligible for push, so reset the
     // promised stream and request a new stream.
     if (found_promise_) {
-      found_promise_ = false;
       std::string url(request_info_->url.spec());
       QuicClientPromisedInfo* promised =
           session_->push_promise_index()->GetPromised(url);
@@ -301,10 +300,13 @@
 
   int rv;
 
-  if (found_promise_) {
+  if (!found_promise_) {
+    next_state_ = STATE_SET_REQUEST_PRIORITY;
+  } else if (!request_body_stream_) {
     next_state_ = STATE_HANDLE_PROMISE;
   } else {
-    next_state_ = STATE_SET_REQUEST_PRIORITY;
+    found_promise_ = false;
+    next_state_ = STATE_REQUEST_STREAM;
   }
   rv = DoLoop(OK);
 
diff --git a/net/quic/chromium/quic_network_transaction_unittest.cc b/net/quic/chromium/quic_network_transaction_unittest.cc
index c6a8fee8..b346728a6 100644
--- a/net/quic/chromium/quic_network_transaction_unittest.cc
+++ b/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -454,6 +454,17 @@
                                                std::move(headers), nullptr);
   }
 
+  std::unique_ptr<QuicEncryptedPacket> ConstructClientMultipleDataFramesPacket(
+      QuicPacketNumber packet_number,
+      QuicStreamId stream_id,
+      bool should_include_version,
+      bool fin,
+      const std::vector<std::string>& data,
+      QuicStreamOffset offset) {
+    return client_maker_.MakeMultipleDataFramesPacket(
+        packet_number, stream_id, should_include_version, fin, offset, data);
+  }
+
   std::unique_ptr<QuicEncryptedPacket> ConstructServerPushPromisePacket(
       QuicPacketNumber packet_number,
       QuicStreamId stream_id,
@@ -717,7 +728,7 @@
 
   const QuicVersion version_;
   QuicFlagSaver flags_;  // Save/restore all QUIC flag values.
-  MockClock* clock_;  // Owned by QuicStreamFactory after CreateSession.
+  MockClock* clock_;     // Owned by QuicStreamFactory after CreateSession.
   QuicTestPacketMaker client_maker_;
   QuicTestPacketMaker server_maker_;
   std::unique_ptr<HttpNetworkSession> session_;
@@ -1019,8 +1030,7 @@
   // TODO(rch): the connection should be "to" the origin, so if the cert is
   // valid for the origin but not the alternative, that should work too.
   EXPECT_TRUE(cert->VerifyNameMatch(origin.host(), false));
-  EXPECT_TRUE(
-      cert->VerifyNameMatch(alternative.host(), false));
+  EXPECT_TRUE(cert->VerifyNameMatch(alternative.host(), false));
   ProofVerifyDetailsChromium verify_details;
   verify_details.cert_verify_result.verified_cert = cert;
   crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details);
@@ -3581,5 +3591,78 @@
   EXPECT_TRUE(AllDataConsumed());
 }
 
+// crbug.com/705109 - this confirms that matching request with a body
+// triggers a crash (pre-fix).
+TEST_P(QuicNetworkTransactionTest, QuicServerPushMatchesRequestWithBody) {
+  params_.origins_to_force_quic_on.insert(
+      HostPortPair::FromString("mail.example.org:443"));
+
+  MockQuicData mock_quic_data;
+  QuicStreamOffset header_stream_offset = 0;
+  mock_quic_data.AddWrite(ConstructSettingsPacket(
+      1, SETTINGS_MAX_HEADER_LIST_SIZE, kDefaultMaxUncompressedHeaderSize,
+      &header_stream_offset));
+  mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+      2, kClientDataStreamId1, true, true,
+      GetRequestHeaders("GET", "https", "/"), &header_stream_offset));
+  QuicStreamOffset server_header_offset = 0;
+  mock_quic_data.AddRead(ConstructServerPushPromisePacket(
+      1, kClientDataStreamId1, kServerDataStreamId1, false,
+      GetRequestHeaders("GET", "https", "/pushed.jpg"), &server_header_offset,
+      &server_maker_));
+  mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+      2, kClientDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+      &server_header_offset));
+  mock_quic_data.AddWrite(ConstructClientAckPacket(3, 2, 1, 1));
+  mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+      3, kServerDataStreamId1, false, false, GetResponseHeaders("200 OK"),
+      &server_header_offset));
+  mock_quic_data.AddRead(ConstructServerDataPacket(4, kClientDataStreamId1,
+                                                   false, true, 0, "hello!"));
+  mock_quic_data.AddWrite(ConstructClientAckPacket(4, 4, 3, 1));
+  mock_quic_data.AddRead(ConstructServerDataPacket(
+      5, kServerDataStreamId1, false, true, 0, "and hello!"));
+
+  // Because the matching request has a body, we will see the push
+  // stream get cancelled, and the matching request go out on the
+  // wire.
+  mock_quic_data.AddWrite(ConstructClientAckAndRstPacket(
+      5, kServerDataStreamId1, QUIC_STREAM_CANCELLED, 5, 5, 1));
+  const char kBody[] = "1";
+  mock_quic_data.AddWrite(ConstructClientRequestHeadersPacket(
+      6, kClientDataStreamId2, false, false,
+      GetRequestHeaders("GET", "https", "/pushed.jpg"), &header_stream_offset));
+  mock_quic_data.AddWrite(ConstructClientMultipleDataFramesPacket(
+      7, kClientDataStreamId2, false, true, {kBody}, 0));
+
+  // We see the same response as for the earlier pushed and cancelled
+  // stream.
+  mock_quic_data.AddRead(ConstructServerResponseHeadersPacket(
+      6, kClientDataStreamId2, false, false, GetResponseHeaders("200 OK"),
+      &server_header_offset));
+  mock_quic_data.AddRead(ConstructServerDataPacket(
+      7, kClientDataStreamId2, false, true, 0, "and hello!"));
+
+  mock_quic_data.AddWrite(ConstructClientAckPacket(8, 7, 6, 1));
+  mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING);  // No more data to read
+  mock_quic_data.AddRead(ASYNC, 0);               // EOF
+  mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+  // The non-alternate protocol job needs to hang in order to guarantee that
+  // the alternate-protocol job will "win".
+  AddHangingNonAlternateProtocolSocketData();
+
+  CreateSession();
+
+  // PUSH_PROMISE handling in the http layer gets exercised here.
+  SendRequestAndExpectQuicResponse("hello!");
+
+  request_.url = GURL("https://mail.example.org/pushed.jpg");
+  ChunkedUploadDataStream upload_data(0);
+  upload_data.AppendData("1", 1, true);
+  request_.upload_data_stream = &upload_data;
+  SendRequestAndExpectQuicResponse("and hello!");
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/core/quic_crypto_client_stream.cc b/net/quic/core/quic_crypto_client_stream.cc
index 14a36cb..ee8d6432 100644
--- a/net/quic/core/quic_crypto_client_stream.cc
+++ b/net/quic/core/quic_crypto_client_stream.cc
@@ -143,9 +143,10 @@
   DoHandshakeLoop(&message);
 }
 
-void QuicCryptoClientStream::CryptoConnect() {
+bool QuicCryptoClientStream::CryptoConnect() {
   next_state_ = STATE_INITIALIZE;
   DoHandshakeLoop(nullptr);
+  return session()->connection()->connected();
 }
 
 int QuicCryptoClientStream::num_sent_client_hellos() const {
diff --git a/net/quic/core/quic_crypto_client_stream.h b/net/quic/core/quic_crypto_client_stream.h
index 7327f311..2b7bd4a 100644
--- a/net/quic/core/quic_crypto_client_stream.h
+++ b/net/quic/core/quic_crypto_client_stream.h
@@ -30,8 +30,9 @@
 
   ~QuicCryptoClientStreamBase() override{};
 
-  // Performs a crypto handshake with the server.
-  virtual void CryptoConnect() = 0;
+  // Performs a crypto handshake with the server. Returns true if the connection
+  // is still connected.
+  virtual bool CryptoConnect() = 0;
 
   // num_sent_client_hellos returns the number of client hello messages that
   // have been sent. If the handshake has completed then this is one greater
@@ -83,7 +84,7 @@
   ~QuicCryptoClientStream() override;
 
   // From QuicCryptoClientStreamBase
-  void CryptoConnect() override;
+  bool CryptoConnect() override;
   int num_sent_client_hellos() const override;
 
   int num_scup_messages_received() const override;
diff --git a/net/quic/test_tools/mock_crypto_client_stream.cc b/net/quic/test_tools/mock_crypto_client_stream.cc
index 2f0089a..1a2449a8 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.cc
+++ b/net/quic/test_tools/mock_crypto_client_stream.cc
@@ -42,7 +42,7 @@
                              "Forced mock failure");
 }
 
-void MockCryptoClientStream::CryptoConnect() {
+bool MockCryptoClientStream::CryptoConnect() {
   if (proof_verify_details_) {
     if (!proof_verify_details_->cert_verify_result.verified_cert
              ->VerifyNameMatch(server_id_.host(), false)) {
@@ -51,7 +51,7 @@
       session()->connection()->CloseConnection(
           QUIC_PROOF_INVALID, "proof invalid",
           ConnectionCloseBehavior::SILENT_CLOSE);
-      return;
+      return false;
     }
   }
 
@@ -106,6 +106,8 @@
       break;
     }
   }
+
+  return session()->connection()->connected();
 }
 
 void MockCryptoClientStream::SendOnCryptoHandshakeEvent(
diff --git a/net/quic/test_tools/mock_crypto_client_stream.h b/net/quic/test_tools/mock_crypto_client_stream.h
index ffec4aa..0d0f5a4 100644
--- a/net/quic/test_tools/mock_crypto_client_stream.h
+++ b/net/quic/test_tools/mock_crypto_client_stream.h
@@ -58,7 +58,7 @@
   void OnHandshakeMessage(const CryptoHandshakeMessage& message) override;
 
   // QuicCryptoClientStream implementation.
-  void CryptoConnect() override;
+  bool CryptoConnect() override;
 
   // Invokes the sessions's CryptoHandshakeEvent method with the specified
   // event.
diff --git a/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java b/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java
index 3d2bb492..3c7796d 100644
--- a/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java
+++ b/remoting/android/java/src/org/chromium/chromoting/ChromotingUtil.java
@@ -11,11 +11,11 @@
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.support.v4.content.ContextCompat;
 import android.util.TypedValue;
 import android.view.Menu;
 import android.view.MenuItem;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Log;
 
 /** Utility methods for chromoting code. */
@@ -63,7 +63,7 @@
 
         if (typedValue.resourceId != 0) {
             // Attribute is a resource.
-            return ApiCompatibilityUtils.getColor(context.getResources(), typedValue.resourceId);
+            return ContextCompat.getColor(context, typedValue.resourceId);
         } else if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT
                 && typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) {
             // Attribute is a raw color value.
diff --git a/services/shape_detection/DEPS b/services/shape_detection/DEPS
index 1987787..a2872a2 100644
--- a/services/shape_detection/DEPS
+++ b/services/shape_detection/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+media/capture/video/scoped_result_callback.h",
-  "+skia/ext/skia_utils_mac.h",
   "+third_party/skia/include",
   "+ui/gfx/codec",
   "+ui/gl/gl_switches.h"
diff --git a/services/shape_detection/barcode_detection_impl_mac.h b/services/shape_detection/barcode_detection_impl_mac.h
index 6a5609a..a7779897 100644
--- a/services/shape_detection/barcode_detection_impl_mac.h
+++ b/services/shape_detection/barcode_detection_impl_mac.h
@@ -7,7 +7,6 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "services/shape_detection/public/interfaces/barcodedetection.mojom.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 
 @class CIDetector;
 
@@ -19,7 +18,9 @@
   BarcodeDetectionImplMac();
   ~BarcodeDetectionImplMac() override;
 
-  void Detect(const SkBitmap& bitmap,
+  void Detect(mojo::ScopedSharedBufferHandle frame_data,
+              uint32_t width,
+              uint32_t height,
               const shape_detection::mojom::BarcodeDetection::DetectCallback&
                   callback) override;
 
diff --git a/services/shape_detection/barcode_detection_impl_mac.mm b/services/shape_detection/barcode_detection_impl_mac.mm
index 2abbc03..ec0ac0b 100644
--- a/services/shape_detection/barcode_detection_impl_mac.mm
+++ b/services/shape_detection/barcode_detection_impl_mac.mm
@@ -50,20 +50,22 @@
 
 BarcodeDetectionImplMac::~BarcodeDetectionImplMac() {}
 
-void BarcodeDetectionImplMac::Detect(const SkBitmap& bitmap,
+void BarcodeDetectionImplMac::Detect(mojo::ScopedSharedBufferHandle frame_data,
+                                     uint32_t width,
+                                     uint32_t height,
                                      const DetectCallback& callback) {
   media::ScopedResultCallback<DetectCallback> scoped_callback(
       base::Bind(&RunCallbackWithBarcodes, callback),
       base::Bind(&RunCallbackWithNoBarcodes));
 
-  base::scoped_nsobject<CIImage> ci_image = CreateCIImageFromSkBitmap(bitmap);
+  base::scoped_nsobject<CIImage> ci_image =
+      CreateCIImageFromSharedMemory(std::move(frame_data), width, height);
   if (!ci_image)
     return;
 
   NSArray* const features = [detector_ featuresInImage:ci_image];
 
   std::vector<mojom::BarcodeDetectionResultPtr> results;
-  const int height = bitmap.height();
   for (CIQRCodeFeature* const f in features) {
     shape_detection::mojom::BarcodeDetectionResultPtr result =
         shape_detection::mojom::BarcodeDetectionResult::New();
diff --git a/services/shape_detection/barcode_detection_impl_mac_unittest.mm b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
index d3c305c..55c2cd27 100644
--- a/services/shape_detection/barcode_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
@@ -12,7 +12,6 @@
 #include "base/run_loop.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/utils/mac/SkCGUtils.h"
 #include "ui/gl/gl_switches.h"
 
 namespace shape_detection {
@@ -65,6 +64,7 @@
 
   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]);
 
@@ -73,16 +73,30 @@
   EXPECT_EQ(static_cast<size_t>(size.width()), CGImageGetWidth(cg_image));
   EXPECT_EQ(static_cast<size_t>(size.height()), CGImageGetHeight(cg_image));
 
-  SkBitmap bitmap;
-  ASSERT_TRUE(SkCreateBitmapFromCGImage(&bitmap, 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(bitmap, base::Bind(&BarcodeDetectionImplMacTest::DetectCallback,
-                                  base::Unretained(this)));
+  impl_.Detect(std::move(handle), size.width(), size.height(),
+               base::Bind(&BarcodeDetectionImplMacTest::DetectCallback,
+                          base::Unretained(this)));
 
   run_loop.Run();
 }
diff --git a/services/shape_detection/detection_utils_mac.h b/services/shape_detection/detection_utils_mac.h
index 69e46426..98e3c0f 100644
--- a/services/shape_detection/detection_utils_mac.h
+++ b/services/shape_detection/detection_utils_mac.h
@@ -9,14 +9,15 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "services/shape_detection/public/interfaces/barcodedetection.mojom.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 
 namespace shape_detection {
 
 // Takes a ScopedSharedBufferHandle with dimensions and produces a new CIImage
 // with the same contents, or a null scoped_nsobject is something goes wrong.
-base::scoped_nsobject<CIImage> CreateCIImageFromSkBitmap(
-    const SkBitmap& bitmap);
+base::scoped_nsobject<CIImage> CreateCIImageFromSharedMemory(
+    mojo::ScopedSharedBufferHandle frame_data,
+    uint32_t width,
+    uint32_t height);
 
 }  // namespace shape_detection
 
diff --git a/services/shape_detection/detection_utils_mac.mm b/services/shape_detection/detection_utils_mac.mm
index 554cd7e5..4e87812e99 100644
--- a/services/shape_detection/detection_utils_mac.mm
+++ b/services/shape_detection/detection_utils_mac.mm
@@ -9,31 +9,61 @@
 #include "base/memory/shared_memory.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/shape_detection/barcode_detection_impl.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "third_party/skia/include/utils/mac/SkCGUtils.h"
 
 namespace shape_detection {
 
-base::scoped_nsobject<CIImage> CreateCIImageFromSkBitmap(
-    const SkBitmap& bitmap) {
+// These formats are available but not public until Mac 10.11.
+#if !defined(MAC_OS_X_VERSION_10_11) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
+const int kCIFormatRGBA8 = 24;
+#else
+//static_assert(kCIFormatRGBA8 == 24, "RGBA8 format enum index.");
+#endif
+
+base::scoped_nsobject<CIImage> CreateCIImageFromSharedMemory(
+    mojo::ScopedSharedBufferHandle frame_data,
+    uint32_t width,
+    uint32_t height) {
   base::CheckedNumeric<uint32_t> num_pixels =
-      base::CheckedNumeric<uint32_t>(bitmap.width()) * bitmap.height();
+      base::CheckedNumeric<uint32_t>(width) * height;
   base::CheckedNumeric<uint32_t> num_bytes = num_pixels * 4;
   if (!num_bytes.IsValid()) {
     DLOG(ERROR) << "Data overflow";
     return base::scoped_nsobject<CIImage>();
   }
 
-  // First convert SkBitmap to CGImageRef.
-  base::ScopedCFTypeRef<CGImageRef> cg_image(
-      SkCreateCGImageRefWithColorspace(bitmap, NULL));
-  if (!cg_image) {
-    DLOG(ERROR) << "Failed to create CGImageRef";
+  base::SharedMemoryHandle memory_handle;
+  size_t memory_size = 0;
+  bool read_only_flag = false;
+  const MojoResult result = mojo::UnwrapSharedMemoryHandle(
+      std::move(frame_data), &memory_handle, &memory_size, &read_only_flag);
+  DCHECK_EQ(MOJO_RESULT_OK, result) << "Failed to unwrap SharedBufferHandle";
+  if (!memory_size || memory_size != num_bytes.ValueOrDie()) {
+    DLOG(ERROR) << "Invalid image size";
     return base::scoped_nsobject<CIImage>();
   }
 
-  base::scoped_nsobject<CIImage> ci_image(
-      [[CIImage alloc] initWithCGImage:cg_image]);
+  auto shared_memory =
+      base::MakeUnique<base::SharedMemory>(memory_handle, true /* read_only */);
+  if (!shared_memory->Map(memory_size)) {
+    DLOG(ERROR) << "Failed to map bytes from shared memory";
+    return base::scoped_nsobject<CIImage>();
+  }
+
+  NSData* byte_data = [NSData dataWithBytesNoCopy:shared_memory->memory()
+                                           length:num_bytes.ValueOrDie()
+                                     freeWhenDone:NO];
+
+  base::ScopedCFTypeRef<CGColorSpaceRef> colorspace(
+      CGColorSpaceCreateWithName(kCGColorSpaceSRGB));
+
+  // CIImage will return nil if RGBA8 is not supported in a certain version.
+  base::scoped_nsobject<CIImage> ci_image([[CIImage alloc]
+      initWithBitmapData:byte_data
+             bytesPerRow:width * 4
+                    size:CGSizeMake(width, height)
+                  format:kCIFormatRGBA8
+              colorSpace:colorspace]);
   if (!ci_image) {
     DLOG(ERROR) << "Failed to create CIImage";
     return base::scoped_nsobject<CIImage>();
diff --git a/services/shape_detection/face_detection_impl_mac.h b/services/shape_detection/face_detection_impl_mac.h
index 459ffa7..fb978c7 100644
--- a/services/shape_detection/face_detection_impl_mac.h
+++ b/services/shape_detection/face_detection_impl_mac.h
@@ -7,7 +7,6 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "services/shape_detection/public/interfaces/facedetection.mojom.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 
 @class CIDetector;
 
@@ -19,7 +18,9 @@
       shape_detection::mojom::FaceDetectorOptionsPtr options);
   ~FaceDetectionImplMac() override;
 
-  void Detect(const SkBitmap& bitmap,
+  void Detect(mojo::ScopedSharedBufferHandle frame_data,
+              uint32_t width,
+              uint32_t height,
               const shape_detection::mojom::FaceDetection::DetectCallback&
                   callback) override;
 
diff --git a/services/shape_detection/face_detection_impl_mac.mm b/services/shape_detection/face_detection_impl_mac.mm
index 8bece619..151e0a7c 100644
--- a/services/shape_detection/face_detection_impl_mac.mm
+++ b/services/shape_detection/face_detection_impl_mac.mm
@@ -47,19 +47,21 @@
 
 FaceDetectionImplMac::~FaceDetectionImplMac() {}
 
-void FaceDetectionImplMac::Detect(const SkBitmap& bitmap,
+void FaceDetectionImplMac::Detect(mojo::ScopedSharedBufferHandle frame_data,
+                                  uint32_t width,
+                                  uint32_t height,
                                   const DetectCallback& callback) {
   media::ScopedResultCallback<DetectCallback> scoped_callback(
       base::Bind(&RunCallbackWithFaces, callback),
       base::Bind(&RunCallbackWithNoFaces));
 
-  base::scoped_nsobject<CIImage> ci_image = CreateCIImageFromSkBitmap(bitmap);
+  base::scoped_nsobject<CIImage> ci_image =
+      CreateCIImageFromSharedMemory(std::move(frame_data), width, height);
   if (!ci_image)
     return;
 
   NSArray* const features = [detector_ featuresInImage:ci_image];
 
-  const int height = bitmap.height();
   shape_detection::mojom::FaceDetectionResultPtr faces =
       shape_detection::mojom::FaceDetectionResult::New();
   for (CIFaceFeature* const f in features) {
diff --git a/services/shape_detection/face_detection_impl_mac_unittest.mm b/services/shape_detection/face_detection_impl_mac_unittest.mm
index 9b9c569..e07f700f 100644
--- a/services/shape_detection/face_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/face_detection_impl_mac_unittest.mm
@@ -76,12 +76,24 @@
   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(*image, base::Bind(&FaceDetectionImplMacTest::DetectCallback,
-                                   base::Unretained(this)));
+  impl_->Detect(std::move(handle), size.width(), size.height(),
+                base::Bind(&FaceDetectionImplMacTest::DetectCallback,
+                           base::Unretained(this)));
 
   run_loop.Run();
 }
diff --git a/services/shape_detection/public/interfaces/BUILD.gn b/services/shape_detection/public/interfaces/BUILD.gn
index 44522415..953742864 100644
--- a/services/shape_detection/public/interfaces/BUILD.gn
+++ b/services/shape_detection/public/interfaces/BUILD.gn
@@ -14,7 +14,6 @@
   ]
 
   public_deps = [
-    "//skia/public/interfaces",
     "//ui/gfx/geometry/mojo",
   ]
 }
diff --git a/services/shape_detection/public/interfaces/barcodedetection.mojom b/services/shape_detection/public/interfaces/barcodedetection.mojom
index 5ae9aef5..27f95ecd 100644
--- a/services/shape_detection/public/interfaces/barcodedetection.mojom
+++ b/services/shape_detection/public/interfaces/barcodedetection.mojom
@@ -6,7 +6,6 @@
 
 module shape_detection.mojom;
 
-import "skia/public/interfaces/bitmap.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 struct BarcodeDetectionResult {
@@ -18,7 +17,9 @@
 };
 
 interface BarcodeDetection {
-  // |bitmap_data| contains tightly packed image pixels in row-major order.
-  Detect(skia.mojom.Bitmap bitmap_data)
+  // |frame_data| contains tightly packed image pixels in ARGB32 format,
+  // row-major order.
+  // TODO(mcasas): Consider using mojo::Bitmap here, https://crbug.com/665488.
+  Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height)
     => (array<BarcodeDetectionResult> results);
 };
diff --git a/services/shape_detection/public/interfaces/facedetection.mojom b/services/shape_detection/public/interfaces/facedetection.mojom
index 0ee1390..38102f8 100644
--- a/services/shape_detection/public/interfaces/facedetection.mojom
+++ b/services/shape_detection/public/interfaces/facedetection.mojom
@@ -6,7 +6,6 @@
 
 module shape_detection.mojom;
 
-import "skia/public/interfaces/bitmap.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 // Since "//ui/gfx/geometry/mojo" is not exposed to blink, we need to declare
@@ -22,7 +21,9 @@
 };
 
 interface FaceDetection {
-  // |bitmap_data| contains tightly packed image pixels in row-major order.
-  Detect(skia.mojom.Bitmap bitmap_data)
+  // |frame_data| contains tightly packed image pixels in ARGB32 format,
+  // row-major order.
+  // TODO(mcasas): Consider using mojo::Bitmap here, https://crbug.com/665488.
+  Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height)
     => (FaceDetectionResult result);
 };
diff --git a/services/shape_detection/public/interfaces/textdetection.mojom b/services/shape_detection/public/interfaces/textdetection.mojom
index 7a0fed5..6e8bb01 100644
--- a/services/shape_detection/public/interfaces/textdetection.mojom
+++ b/services/shape_detection/public/interfaces/textdetection.mojom
@@ -4,7 +4,6 @@
 
 module shape_detection.mojom;
 
-import "skia/public/interfaces/bitmap.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 struct TextDetectionResult {
@@ -13,7 +12,8 @@
 };
 
 interface TextDetection {
-  // |bitmap_data| contains tightly packed image pixels in row-major order.
-  Detect(skia.mojom.Bitmap bitmap_data)
+  // |frame_data| contains tightly packed image pixels in ARGB32 format,
+  // row-major order.
+  Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height)
     => (array<TextDetectionResult> results);
 };
diff --git a/services/shape_detection/text_detection_impl_mac.h b/services/shape_detection/text_detection_impl_mac.h
index 738d8da..d86be927 100644
--- a/services/shape_detection/text_detection_impl_mac.h
+++ b/services/shape_detection/text_detection_impl_mac.h
@@ -17,7 +17,9 @@
   TextDetectionImplMac();
   ~TextDetectionImplMac() override;
 
-  void Detect(const SkBitmap& bitmap,
+  void Detect(mojo::ScopedSharedBufferHandle frame_data,
+              uint32_t width,
+              uint32_t height,
               const mojom::TextDetection::DetectCallback& callback) override;
 
  private:
diff --git a/services/shape_detection/text_detection_impl_mac.mm b/services/shape_detection/text_detection_impl_mac.mm
index 45d8d46..3894770a 100644
--- a/services/shape_detection/text_detection_impl_mac.mm
+++ b/services/shape_detection/text_detection_impl_mac.mm
@@ -48,20 +48,22 @@
 
 TextDetectionImplMac::~TextDetectionImplMac() {}
 
-void TextDetectionImplMac::Detect(const SkBitmap& bitmap,
+void TextDetectionImplMac::Detect(mojo::ScopedSharedBufferHandle frame_data,
+                                  uint32_t width,
+                                  uint32_t height,
                                   const DetectCallback& callback) {
   DCHECK(base::mac::IsAtLeastOS10_11());
   media::ScopedResultCallback<DetectCallback> scoped_callback(
       base::Bind(&RunCallbackWithResults, callback),
       base::Bind(&RunCallbackWithNoResults));
 
-  base::scoped_nsobject<CIImage> ci_image = CreateCIImageFromSkBitmap(bitmap);
+  base::scoped_nsobject<CIImage> ci_image =
+      CreateCIImageFromSharedMemory(std::move(frame_data), width, height);
   if (!ci_image)
     return;
 
   NSArray* const features = [detector_ featuresInImage:ci_image];
 
-  const int height = bitmap.height();
   std::vector<mojom::TextDetectionResultPtr> results;
   for (CIRectangleFeature* const f in features) {
     // CIRectangleFeature only has bounding box information.
diff --git a/services/shape_detection/text_detection_impl_mac_unittest.mm b/services/shape_detection/text_detection_impl_mac_unittest.mm
index 7b27fe0..5333a51 100644
--- a/services/shape_detection/text_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/text_detection_impl_mac_unittest.mm
@@ -12,7 +12,6 @@
 #include "base/run_loop.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/utils/mac/SkCGUtils.h"
 #include "ui/gl/gl_switches.h"
 
 namespace shape_detection {
@@ -82,15 +81,29 @@
   EXPECT_EQ(static_cast<size_t>(width), CGImageGetWidth(cg_image));
   EXPECT_EQ(static_cast<size_t>(height), CGImageGetHeight(cg_image));
 
-  SkBitmap bitmap;
-  ASSERT_TRUE(SkCreateBitmapFromCGImage(&bitmap, cg_image));
+  base::ScopedCFTypeRef<CFDataRef> raw_cg_image_data(
+      CGDataProviderCopyData(CGImageGetDataProvider(cg_image)));
+  EXPECT_TRUE(CFDataGetBytePtr(raw_cg_image_data));
+  const int num_bytes = width * height * 4;
+  EXPECT_EQ(num_bytes, CFDataGetLength(raw_cg_image_data));
+
+  // Generate a new ScopedSharedBufferHandle of the aproppriate size, map it and
+  // copy the generated text image pixels into it.
+  auto 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 to Detect() and expect the response in callback.
   EXPECT_CALL(*this, Detection(1)).WillOnce(RunClosure(quit_closure));
-  impl_.Detect(bitmap, base::Bind(&TextDetectionImplMacTest::DetectCallback,
-                                  base::Unretained(this)));
+  impl_.Detect(std::move(handle), width, height,
+               base::Bind(&TextDetectionImplMacTest::DetectCallback,
+                          base::Unretained(this)));
 
   run_loop.Run();
 }
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index 5bd3bfd..c5ea71d 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -367,9 +367,6 @@
 crbug.com/647192 [ Win Debug ] virtual/stable/webexposed/global-interface-listing.html [ Slow ]
 crbug.com/647192 [ Win Debug ] webexposed/global-interface-listing.html [ Slow ]
 
-# Slow because it tests every SVG interface
-crbug.com/709030 external/wpt/svg/interfaces.html [ Slow ]
-
 # These tests are slow with our MESA backend. They may be less slow when we have
 # bots running tests on real hardware or maybe when using SwiftShader.
 crbug.com/646528 compositing/lots-of-img-layers.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index bef6fe73..d6999b5 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -63,10 +63,6 @@
 crbug.com/619427 [ Mac Linux ] virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash3.html [ Pass Failure ]
 # --- End SPV2 Tests ---
 
-crbug.com/624709 [ Win ] virtual/gpu-rasterization/images/webp-color-profile-lossy.html [ Failure ]
-crbug.com/587737 [ Mac ] virtual/gpu-rasterization/images/color-profile-filter.html [ Timeout Failure ]
-crbug.com/624233 virtual/gpu-rasterization/images/color-profile-background-clip-text.html [ Pass Failure Crash ]
-
 ########## Ref tests can't be rebaselined ##########
 crbug.com/504613 crbug.com/524248 paint/images/image-backgrounds-not-antialiased.html [ Failure ]
 crbug.com/504613 crbug.com/524248 virtual/disable-spinvalidation/paint/images/image-backgrounds-not-antialiased.html [ Failure ]
@@ -97,6 +93,8 @@
 crbug.com/703403 virtual/disable-spinvalidation/paint/inline/focus-ring-under-absolute-with-relative-continuation.html [ Failure ]
 
 ########## Genuinely flaky ##########
+crbug.com/624233 virtual/gpu-rasterization/images/color-profile-background-clip-text.html [ Pass Failure ]
+
 crbug.com/653722 compositing/reflections/nested-reflection-anchor-point.html [ Pass Failure ]
 crbug.com/653722 compositing/reflections/nested-reflection-animated.html [ Pass Failure ]
 crbug.com/653722 compositing/reflections/nested-reflection-transition.html [ Pass Failure ]
@@ -1870,6 +1868,78 @@
 crbug.com/626703 external/wpt/domxpath/001.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/FileAPI/url/url_createobjecturl_file_img-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/offline/browser-state/navigator_online_event-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/offline/manifest_main_empty-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/offline/manifest_notchanged_online-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/offline/manifest_section_empty-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/offline/manifest_section_many-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/offline/section_network_offline-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/offline/section_network_online-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/windows/noreferrer-cross-origin-close-manual.sub.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/windows/noreferrer-cross-origin-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/windows/noreferrer-cross-origin-window-name-manual.sub.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/windows/opener-cross-origin-manual.sub.html [ Skip ]
+crbug.com/626703 external/wpt/html/browsers/windows/targeting-multiple-cross-origin-manual.sub.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/activation/click-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/003-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/004-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/005-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/006-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/007-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/008-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/009-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/010-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/011-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/012-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/013-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/102-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/103-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/104-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/105-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/106-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/107-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/108-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/109-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/110-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/111-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/112-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/113-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/114-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/115-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/116-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/117-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/118-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/editing/dnd/target-origin/201-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-down-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-left-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-right-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-up-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-scrollamount-effect-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-start-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-stop-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/audio_controls_present-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/audio_muted_overriding_volume-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/audio_muted_present-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/audio_volume_loudest-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/audio_volume_silent-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/video_controls_present-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/video_muted_overriding_volume-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/video_muted_present-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/video_volume_loudest-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/embedded-content/media-elements/video_volume_silent-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/forms/the-optgroup-element/optgroup-disabled-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/forms/the-option-element/option-disabled-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/forms/the-textarea-element/textarea-placeholder-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/forms/the-textarea-element/textarea-select-manual.html [ Skip ]
+crbug.com/626703 external/wpt/html/semantics/selectors/pseudo-classes/checked-001-manual.html [ Skip ]
+crbug.com/626703 external/wpt/uievents/keyboard/key-101en-us-manual.html [ Skip ]
+crbug.com/626703 external/wpt/uievents/keyboard/key-102fr-fr-manual.html [ Skip ]
+crbug.com/626703 external/wpt/webstorage/storage_local-manual.html [ Skip ]
+crbug.com/626703 external/wpt/webstorage/storage_session-manual.html [ Skip ]
+crbug.com/626703 virtual/mojo-localstorage/external/wpt/webstorage/storage_local-manual.html [ Skip ]
+crbug.com/626703 virtual/mojo-localstorage/external/wpt/webstorage/storage_session-manual.html [ Skip ]
 crbug.com/626703 [ Mac ] external/wpt/pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html [ Timeout ]
 #crbug.com/626703 external/wpt/css/css-cascade-4/revert-val-001.html [ Failure ]
 #crbug.com/626703 external/wpt/css/css-ui-3/box-sizing-026.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/aria-tables-expected.txt b/third_party/WebKit/LayoutTests/accessibility/aria-tables-expected.txt
index eede4c6..f22eb8d 100644
--- a/third_party/WebKit/LayoutTests/accessibility/aria-tables-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/aria-tables-expected.txt
@@ -12,33 +12,33 @@
 AXRole: AXWebArea
     AXRole: AXTable
         AXRole: AXRow
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
         AXRole: AXRow
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
         AXRole: AXRow
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
     AXRole: AXParagraph
diff --git a/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt b/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
index 825374b..b0f68bc3 100644
--- a/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/element-role-mapping-normal-expected.txt
@@ -173,18 +173,18 @@
             AXRole: AXStaticText "Caption"
                 AXRole: AXInlineTextBox "Caption"
         AXRole: AXRow
-            AXRole: AXCell
+            AXRole: AXCell "Cell1"
                 AXRole: AXStaticText "Cell1"
                     AXRole: AXInlineTextBox "Cell1"
-            AXRole: AXCell
+            AXRole: AXCell "Cell2"
                 AXRole: AXStaticText "Cell2"
                     AXRole: AXInlineTextBox "Cell2"
         AXRole: AXColumn
-            AXRole: AXCell
+            AXRole: AXCell "Cell1"
                 AXRole: AXStaticText "Cell1"
                     AXRole: AXInlineTextBox "Cell1"
         AXRole: AXColumn
-            AXRole: AXCell
+            AXRole: AXCell "Cell2"
                 AXRole: AXStaticText "Cell2"
                     AXRole: AXInlineTextBox "Cell2"
         AXRole: AXTableHeaderContainer
diff --git a/third_party/WebKit/LayoutTests/accessibility/table-cell-spans-expected.txt b/third_party/WebKit/LayoutTests/accessibility/table-cell-spans-expected.txt
index 782a57c..cdebea7 100644
--- a/third_party/WebKit/LayoutTests/accessibility/table-cell-spans-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/table-cell-spans-expected.txt
@@ -8,31 +8,31 @@
 4,2	4,3	4,4
 ----------------------
 { 0, 0 }
-
+Cell A COLSPAN="2" ROWSPAN="2"
 AXRole: AXCell
 {0, 2}, {0, 2}
 
 ----------------------
 { 1, 1 }
-
+Cell A COLSPAN="2" ROWSPAN="2"
 AXRole: AXCell
 {0, 2}, {0, 2}
 
 ----------------------
 { 3, 0 }
-
+Cell C ROWSPAN="2"
 AXRole: AXCell
 {2, 2}, {0, 1}
 
 ----------------------
 { 2, 0 }
-
+Cell C ROWSPAN="2"
 AXRole: AXCell
 {2, 2}, {0, 1}
 
 ----------------------
 { 2, 3 }
-
+3,4
 AXRole: AXCell
 {2, 1}, {3, 1}
 
diff --git a/third_party/WebKit/LayoutTests/accessibility/table-cells-expected.txt b/third_party/WebKit/LayoutTests/accessibility/table-cells-expected.txt
index cdfe6e9..7d632e45 100644
--- a/third_party/WebKit/LayoutTests/accessibility/table-cells-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/table-cells-expected.txt
@@ -10,23 +10,23 @@
 South	3333	1111	2222
 ------------------------
 [0,0]
-
+Ruritanian Population Survey
 AXRole: AXColumnHeader
 ------------------------
 [3,1]
-
+Males
 AXRole: AXColumnHeader
 ------------------------
 [1,1]
-
+Ruritanian Population Survey
 AXRole: AXColumnHeader
 ------------------------
 [2,2]
-
+3333
 AXRole: AXCell
 ------------------------
 [3,5]
-
+1111
 AXRole: AXCell
 ------------------------
 [100,0]
diff --git a/third_party/WebKit/LayoutTests/accessibility/table-header-column-row-expected.txt b/third_party/WebKit/LayoutTests/accessibility/table-header-column-row-expected.txt
index fb6ce01d..9b3b74c 100644
--- a/third_party/WebKit/LayoutTests/accessibility/table-header-column-row-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/table-header-column-row-expected.txt
@@ -30,33 +30,33 @@
             AXRole: AXStaticText "scope test"
                 AXRole: AXInlineTextBox "scope test"
         AXRole: AXRow
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
         AXRole: AXRow
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
         AXRole: AXRow
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
     AXRole: AXTable "row header and column header (1)"
@@ -64,33 +64,33 @@
             AXRole: AXStaticText "row header and column header (1)"
                 AXRole: AXInlineTextBox "row header and column header (1)"
         AXRole: AXRow
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "column head"
                 AXRole: AXStaticText "column head"
                     AXRole: AXInlineTextBox "column head"
         AXRole: AXRow
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "column head"
                 AXRole: AXStaticText "column head"
                     AXRole: AXInlineTextBox "column head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "column head"
                 AXRole: AXStaticText "column head"
                     AXRole: AXInlineTextBox "column head"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
         AXRole: AXRow
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
     AXRole: AXTable "row header and column header (2)"
@@ -98,33 +98,33 @@
             AXRole: AXStaticText "row header and column header (2)"
                 AXRole: AXInlineTextBox "row header and column header (2)"
         AXRole: AXRow
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
         AXRole: AXRow
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "column head"
                 AXRole: AXStaticText "column head"
                     AXRole: AXInlineTextBox "column head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "column head"
                 AXRole: AXStaticText "column head"
                     AXRole: AXInlineTextBox "column head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "column head"
                 AXRole: AXStaticText "column head"
                     AXRole: AXInlineTextBox "column head"
         AXRole: AXRow
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
     AXRole: AXTable "row header and column header (3)"
@@ -133,24 +133,24 @@
                 AXRole: AXInlineTextBox "row header and column header (3)"
         AXRole: AXRow
             AXRole: AXCell
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
         AXRole: AXRow
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
         AXRole: AXRow
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
-            AXRole: AXCell
+            AXRole: AXCell "data"
                 AXRole: AXStaticText "data"
                     AXRole: AXInlineTextBox "data"
     AXRole: AXTable "row header and column header (4)"
@@ -158,14 +158,14 @@
             AXRole: AXStaticText "row header and column header (4)"
                 AXRole: AXInlineTextBox "row header and column header (4)"
         AXRole: AXRow
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
-            AXRole: AXColumnHeader
+            AXRole: AXColumnHeader "col head"
                 AXRole: AXStaticText "col head"
                     AXRole: AXInlineTextBox "col head"
         AXRole: AXRow
-            AXRole: AXRowHeader
+            AXRole: AXRowHeader "row head"
                 AXRole: AXStaticText "row head"
                     AXRole: AXInlineTextBox "row head"
     AXRole: AXParagraph
diff --git a/third_party/WebKit/LayoutTests/accessibility/table-with-empty-thead-causes-crash-expected.txt b/third_party/WebKit/LayoutTests/accessibility/table-with-empty-thead-causes-crash-expected.txt
index 0eaea935..d4b06ee8 100644
--- a/third_party/WebKit/LayoutTests/accessibility/table-with-empty-thead-causes-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/accessibility/table-with-empty-thead-causes-crash-expected.txt
@@ -9,10 +9,10 @@
 AXRole: AXWebArea
     AXRole: AXTable "table"
         AXRole: AXRow
-            AXRole: AXCell
+            AXRole: AXCell "1"
                 AXRole: AXStaticText "1"
                     AXRole: AXInlineTextBox "1"
-            AXRole: AXCell
+            AXRole: AXCell "2"
                 AXRole: AXStaticText "2"
                     AXRole: AXInlineTextBox "2"
     AXRole: AXParagraph
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 26e82fe1..0fae601 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -1,6 +1,12 @@
 {
  "items": {
   "manual": {
+   "FileAPI/url/url_createobjecturl_file_img-manual.html": [
+    [
+     "/FileAPI/url/url_createobjecturl_file_img-manual.html",
+     {}
+    ]
+   ],
    "auxclick/auxclick_event-manual.html": [
     [
      "/auxclick/auxclick_event-manual.html",
@@ -5461,6 +5467,48 @@
      {}
     ]
    ],
+   "html/browsers/offline/browser-state/navigator_online_event-manual.html": [
+    [
+     "/html/browsers/offline/browser-state/navigator_online_event-manual.html",
+     {}
+    ]
+   ],
+   "html/browsers/offline/manifest_main_empty-manual.html": [
+    [
+     "/html/browsers/offline/manifest_main_empty-manual.html",
+     {}
+    ]
+   ],
+   "html/browsers/offline/manifest_notchanged_online-manual.html": [
+    [
+     "/html/browsers/offline/manifest_notchanged_online-manual.html",
+     {}
+    ]
+   ],
+   "html/browsers/offline/manifest_section_empty-manual.html": [
+    [
+     "/html/browsers/offline/manifest_section_empty-manual.html",
+     {}
+    ]
+   ],
+   "html/browsers/offline/manifest_section_many-manual.html": [
+    [
+     "/html/browsers/offline/manifest_section_many-manual.html",
+     {}
+    ]
+   ],
+   "html/browsers/offline/section_network_offline-manual.html": [
+    [
+     "/html/browsers/offline/section_network_offline-manual.html",
+     {}
+    ]
+   ],
+   "html/browsers/offline/section_network_online-manual.html": [
+    [
+     "/html/browsers/offline/section_network_online-manual.html",
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/the-windowproxy-object/test-window-proxy-locationbar-manual.html": [
     [
      "/html/browsers/the-window-object/the-windowproxy-object/test-window-proxy-locationbar-manual.html",
@@ -5497,18 +5545,336 @@
      {}
     ]
    ],
+   "html/browsers/windows/noreferrer-cross-origin-close-manual.sub.html": [
+    [
+     "/html/browsers/windows/noreferrer-cross-origin-close-manual.sub.html",
+     {}
+    ]
+   ],
+   "html/browsers/windows/noreferrer-cross-origin-manual.html": [
+    [
+     "/html/browsers/windows/noreferrer-cross-origin-manual.html",
+     {}
+    ]
+   ],
+   "html/browsers/windows/noreferrer-cross-origin-window-name-manual.sub.html": [
+    [
+     "/html/browsers/windows/noreferrer-cross-origin-window-name-manual.sub.html",
+     {}
+    ]
+   ],
+   "html/browsers/windows/opener-cross-origin-manual.sub.html": [
+    [
+     "/html/browsers/windows/opener-cross-origin-manual.sub.html",
+     {}
+    ]
+   ],
+   "html/browsers/windows/targeting-multiple-cross-origin-manual.sub.html": [
+    [
+     "/html/browsers/windows/targeting-multiple-cross-origin-manual.sub.html",
+     {}
+    ]
+   ],
+   "html/editing/activation/click-manual.html": [
+    [
+     "/html/editing/activation/click-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/003-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/003-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/004-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/004-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/005-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/005-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/006-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/006-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/007-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/007-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/008-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/008-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/009-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/009-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/010-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/010-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/011-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/011-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/012-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/012-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/013-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/013-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/102-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/102-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/103-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/103-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/104-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/104-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/105-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/105-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/106-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/106-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/107-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/107-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/108-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/108-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/109-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/109-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/110-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/110-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/111-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/111-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/112-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/112-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/113-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/113-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/114-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/114-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/115-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/115-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/116-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/116-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/117-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/117-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/118-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/118-manual.html",
+     {}
+    ]
+   ],
+   "html/editing/dnd/target-origin/201-manual.html": [
+    [
+     "/html/editing/dnd/target-origin/201-manual.html",
+     {}
+    ]
+   ],
+   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-down-manual.html": [
+    [
+     "/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-down-manual.html",
+     {}
+    ]
+   ],
+   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-left-manual.html": [
+    [
+     "/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-left-manual.html",
+     {}
+    ]
+   ],
+   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-right-manual.html": [
+    [
+     "/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-right-manual.html",
+     {}
+    ]
+   ],
+   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-up-manual.html": [
+    [
+     "/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-up-manual.html",
+     {}
+    ]
+   ],
+   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-scrollamount-effect-manual.html": [
+    [
+     "/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-scrollamount-effect-manual.html",
+     {}
+    ]
+   ],
+   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-start-manual.html": [
+    [
+     "/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-start-manual.html",
+     {}
+    ]
+   ],
+   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-stop-manual.html": [
+    [
+     "/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-stop-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/audio_controls_present-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/audio_controls_present-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/audio_muted_overriding_volume-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/audio_muted_overriding_volume-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/audio_muted_present-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/audio_muted_present-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/audio_volume_loudest-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/audio_volume_loudest-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/audio_volume_silent-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/audio_volume_silent-manual.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/media-elements/loading-the-media-resource/stable-state-dialogs-manual.html": [
     [
      "/html/semantics/embedded-content/media-elements/loading-the-media-resource/stable-state-dialogs-manual.html",
      {}
     ]
    ],
+   "html/semantics/embedded-content/media-elements/video_controls_present-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/video_controls_present-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/video_muted_overriding_volume-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/video_muted_overriding_volume-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/video_muted_present-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/video_muted_present-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/video_volume_loudest-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/video_volume_loudest-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/embedded-content/media-elements/video_volume_silent-manual.html": [
+    [
+     "/html/semantics/embedded-content/media-elements/video_volume_silent-manual.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-iframe-element/iframe_sandbox_allow_top_navigation_by_user_activation-manual.html": [
     [
      "/html/semantics/embedded-content/the-iframe-element/iframe_sandbox_allow_top_navigation_by_user_activation-manual.html",
      {}
     ]
    ],
+   "html/semantics/forms/attributes-common-to-form-controls/dirname-rtl-manual.html": [
+    [
+     "/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl-manual.html",
+     {}
+    ]
+   ],
    "html/semantics/forms/constraints/tooShort-input-email-add-manual.html": [
     [
      "/html/semantics/forms/constraints/tooShort-input-email-add-manual.html",
@@ -5551,12 +5917,42 @@
      {}
     ]
    ],
+   "html/semantics/forms/the-optgroup-element/optgroup-disabled-manual.html": [
+    [
+     "/html/semantics/forms/the-optgroup-element/optgroup-disabled-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/forms/the-option-element/option-disabled-manual.html": [
+    [
+     "/html/semantics/forms/the-option-element/option-disabled-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/forms/the-textarea-element/textarea-placeholder-manual.html": [
+    [
+     "/html/semantics/forms/the-textarea-element/textarea-placeholder-manual.html",
+     {}
+    ]
+   ],
+   "html/semantics/forms/the-textarea-element/textarea-select-manual.html": [
+    [
+     "/html/semantics/forms/the-textarea-element/textarea-select-manual.html",
+     {}
+    ]
+   ],
    "html/semantics/interactive-elements/context-menus/contextmenu-event-manual.htm": [
     [
      "/html/semantics/interactive-elements/context-menus/contextmenu-event-manual.htm",
      {}
     ]
    ],
+   "html/semantics/selectors/pseudo-classes/checked-001-manual.html": [
+    [
+     "/html/semantics/selectors/pseudo-classes/checked-001-manual.html",
+     {}
+    ]
+   ],
    "html/webappapis/scripting/events/event-handler-processing-algorithm-manual.html": [
     [
      "/html/webappapis/scripting/events/event-handler-processing-algorithm-manual.html",
@@ -6067,6 +6463,18 @@
      {}
     ]
    ],
+   "uievents/keyboard/key-101en-us-manual.html": [
+    [
+     "/uievents/keyboard/key-101en-us-manual.html",
+     {}
+    ]
+   ],
+   "uievents/keyboard/key-102fr-fr-manual.html": [
+    [
+     "/uievents/keyboard/key-102fr-fr-manual.html",
+     {}
+    ]
+   ],
    "uievents/keyboard/key-manual.css": [
     [
      "/uievents/keyboard/key-manual.css",
@@ -6090,6 +6498,18 @@
      "/uievents/order-of-events/mouse-events/mouseover-out-manual.html",
      {}
     ]
+   ],
+   "webstorage/storage_local-manual.html": [
+    [
+     "/webstorage/storage_local-manual.html",
+     {}
+    ]
+   ],
+   "webstorage/storage_session-manual.html": [
+    [
+     "/webstorage/storage_session-manual.html",
+     {}
+    ]
    ]
   },
   "reftest": {
@@ -8265,6 +8685,18 @@
      {}
     ]
    ],
+   "css/css-align-3/distribution-values/space-evenly-001.html": [
+    [
+     "/css/css-align-3/distribution-values/space-evenly-001.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-display-3/display-contents-alignment-001.html": [
     [
      "/css/css-display-3/display-contents-alignment-001.html",
@@ -14313,6 +14745,78 @@
      {}
     ]
    ],
+   "css/css-rhythm-1/line-height-step-basic-001.html": [
+    [
+     "/css/css-rhythm-1/line-height-step-basic-001.html",
+     [
+      [
+       "/css/css-rhythm-1/reference/line-height-step-basic-001.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/line-height-step-boundary-001.html": [
+    [
+     "/css/css-rhythm-1/line-height-step-boundary-001.html",
+     [
+      [
+       "/css/css-rhythm-1/reference/line-height-step-boundary-001.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/line-height-step-ruby-001.html": [
+    [
+     "/css/css-rhythm-1/line-height-step-ruby-001.html",
+     [
+      [
+       "/css/css-rhythm-1/reference/line-height-step-ruby-001.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/line-height-step-valign-001.html": [
+    [
+     "/css/css-rhythm-1/line-height-step-valign-001.html",
+     [
+      [
+       "/css/css-rhythm-1/reference/line-height-step-valign-001.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/line-height-step-writing-mode-vrl-001.html": [
+    [
+     "/css/css-rhythm-1/line-height-step-writing-mode-vrl-001.html",
+     [
+      [
+       "/css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-001.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/line-height-step-writing-mode-vrl-ruby-001.html": [
+    [
+     "/css/css-rhythm-1/line-height-step-writing-mode-vrl-ruby-001.html",
+     [
+      [
+       "/css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-ruby-001.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-scoping-1/css-scoping-shadow-assigned-node-with-before-after.html": [
     [
      "/css/css-scoping-1/css-scoping-shadow-assigned-node-with-before-after.html",
@@ -26437,6 +26941,30 @@
      {}
     ]
    ],
+   "css/selectors4/focus-within-007.html": [
+    [
+     "/css/selectors4/focus-within-007.html",
+     [
+      [
+       "/css/selectors4/focus-within-007-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/selectors4/focus-within-008.html": [
+    [
+     "/css/selectors4/focus-within-008.html",
+     [
+      [
+       "/css/selectors4/focus-within-007-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/selectors4/of-type-selectors.xhtml": [
     [
      "/css/selectors4/of-type-selectors.xhtml",
@@ -36790,7 +37318,12 @@
      {}
     ]
    ],
-   "bluetooth/idl-Bluetooth.html": [
+   "beacon/headers/header-referrer.js": [
+    [
+     {}
+    ]
+   ],
+   "beacon/resources/inspect-header.py": [
     [
      {}
     ]
@@ -38425,6 +38958,11 @@
      {}
     ]
    ],
+   "css-timing-1/testcommon.js": [
+    [
+     {}
+    ]
+   ],
    "css-typed-om/CSSMatrixComponent-DOMMatrix-mutable-expected.txt": [
     [
      {}
@@ -40700,6 +41238,36 @@
      {}
     ]
    ],
+   "css/css-rhythm-1/reference/line-height-step-basic-001.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/reference/line-height-step-boundary-001.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/reference/line-height-step-ruby-001.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/reference/line-height-step-valign-001.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-001.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-ruby-001.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-scoping-1/reference/green-box.html": [
     [
      {}
@@ -46800,11 +47368,6 @@
      {}
     ]
    ],
-   "css/css-writing-modes-3/support/mplus-1p-regular.ttf": [
-    [
-     {}
-    ]
-   ],
    "css/css-writing-modes-3/support/mplus-1p-regular.woff": [
     [
      {}
@@ -48235,6 +48798,11 @@
      {}
     ]
    ],
+   "css/selectors4/focus-within-007-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/selectors4/focus-within-shadow-001-ref.html": [
     [
      {}
@@ -50730,16 +51298,6 @@
      {}
     ]
    ],
-   "encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4": [
-    [
-     {}
-    ]
-   ],
-   "encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4": [
-    [
-     {}
-    ]
-   ],
    "encrypted-media/polyfill/cast-polyfill.js": [
     [
      {}
@@ -52935,6 +53493,11 @@
      {}
     ]
    ],
+   "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html": [
+    [
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/garbage-collection-and-browsing-contexts/discard_iframe_history_1-1.html": [
     [
      {}
@@ -65415,6 +65978,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/echo-message-to-source-worker.js": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/empty-but-slow-worker.js": [
     [
      {}
@@ -65935,6 +66503,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/respond-then-throw-worker.js": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/service-worker-csp-worker.py": [
     [
      {}
@@ -66250,12 +66823,12 @@
      {}
     ]
    ],
-   "storage/interfaces-expected.txt": [
+   "storage/interfaces.idl": [
     [
      {}
     ]
    ],
-   "storage/interfaces.idl": [
+   "storage/storage-estimate-indexeddb.js": [
     [
      {}
     ]
@@ -67225,6 +67798,26 @@
      {}
     ]
    ],
+   "web-animations/animation-model/animation-types/spacing-keyframes-filters-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "web-animations/animation-model/animation-types/spacing-keyframes-shapes-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "web-animations/animation-model/animation-types/spacing-keyframes-transform-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "web-animations/animation-model/combining-effects/effect-composition-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "web-animations/animation-model/keyframe-effects/effect-value-context-expected.txt": [
     [
      {}
@@ -67240,6 +67833,11 @@
      {}
     ]
    ],
+   "web-animations/interfaces/Animation/constructor-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "web-animations/interfaces/Animation/effect-expected.txt": [
     [
      {}
@@ -67250,6 +67848,11 @@
      {}
     ]
    ],
+   "web-animations/interfaces/Animation/finished-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "web-animations/interfaces/Animation/reverse-expected.txt": [
     [
      {}
@@ -67290,11 +67893,21 @@
      {}
     ]
    ],
+   "web-animations/interfaces/KeyframeEffect/composite-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "web-animations/interfaces/KeyframeEffect/constructor-expected.txt": [
     [
      {}
     ]
    ],
+   "web-animations/interfaces/KeyframeEffect/copy-contructor-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "web-animations/interfaces/KeyframeEffect/getComputedTiming-expected.txt": [
     [
      {}
@@ -67325,6 +67938,11 @@
      {}
     ]
    ],
+   "web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "web-animations/interfaces/KeyframeEffectReadOnly/spacing-expected.txt": [
     [
      {}
@@ -67375,6 +67993,11 @@
      {}
     ]
    ],
+   "web-animations/timing-model/animations/set-the-target-effect-of-an-animation-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "web-animations/timing-model/animations/set-the-timeline-of-an-animation-expected.txt": [
     [
      {}
@@ -67685,11 +68308,6 @@
      {}
     ]
    ],
-   "webvtt/interfaces-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "webvtt/parsing/README.md": [
     [
      {}
@@ -72393,6 +73011,60 @@
      {}
     ]
    ],
+   "beacon/headers/header-referrer-no-referrer-when-downgrade.https.html": [
+    [
+     "/beacon/headers/header-referrer-no-referrer-when-downgrade.https.html",
+     {}
+    ]
+   ],
+   "beacon/headers/header-referrer-no-referrer.html": [
+    [
+     "/beacon/headers/header-referrer-no-referrer.html",
+     {}
+    ]
+   ],
+   "beacon/headers/header-referrer-origin-when-cross-origin.html": [
+    [
+     "/beacon/headers/header-referrer-origin-when-cross-origin.html",
+     {}
+    ]
+   ],
+   "beacon/headers/header-referrer-origin.html": [
+    [
+     "/beacon/headers/header-referrer-origin.html",
+     {}
+    ]
+   ],
+   "beacon/headers/header-referrer-same-origin.html": [
+    [
+     "/beacon/headers/header-referrer-same-origin.html",
+     {}
+    ]
+   ],
+   "beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html": [
+    [
+     "/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html",
+     {}
+    ]
+   ],
+   "beacon/headers/header-referrer-strict-origin.https.html": [
+    [
+     "/beacon/headers/header-referrer-strict-origin.https.html",
+     {}
+    ]
+   ],
+   "beacon/headers/header-referrer-unsafe-url.https.html": [
+    [
+     "/beacon/headers/header-referrer-unsafe-url.https.html",
+     {}
+    ]
+   ],
+   "bluetooth/idl-Bluetooth.html": [
+    [
+     "/bluetooth/idl-Bluetooth.html",
+     {}
+    ]
+   ],
    "clear-site-data/navigation.html": [
     [
      "/clear-site-data/navigation.html",
@@ -73173,6 +73845,12 @@
      {}
     ]
    ],
+   "content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html": [
+    [
+     "/content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html",
+     {}
+    ]
+   ],
    "content-security-policy/embedded-enforcement/embedding_csp-header.html": [
     [
      "/content-security-policy/embedded-enforcement/embedding_csp-header.html",
@@ -73705,6 +74383,12 @@
      {}
     ]
    ],
+   "content-security-policy/script-src/script-src-strict_dynamic_worker.https.html": [
+    [
+     "/content-security-policy/script-src/script-src-strict_dynamic_worker.https.html",
+     {}
+    ]
+   ],
    "content-security-policy/securitypolicyviolation/blockeduri-eval.html": [
     [
      "/content-security-policy/securitypolicyviolation/blockeduri-eval.html",
@@ -74035,6 +74719,30 @@
      {}
     ]
    ],
+   "css-timing-1/cubic-bezier-timing-functions-output.html": [
+    [
+     "/css-timing-1/cubic-bezier-timing-functions-output.html",
+     {}
+    ]
+   ],
+   "css-timing-1/frames-timing-functions-output.html": [
+    [
+     "/css-timing-1/frames-timing-functions-output.html",
+     {}
+    ]
+   ],
+   "css-timing-1/frames-timing-functions-syntax.html": [
+    [
+     "/css-timing-1/frames-timing-functions-syntax.html",
+     {}
+    ]
+   ],
+   "css-timing-1/step-timing-functions-output.html": [
+    [
+     "/css-timing-1/step-timing-functions-output.html",
+     {}
+    ]
+   ],
    "css-typed-om/CSSMatrixComponent-DOMMatrix-mutable.html": [
     [
      "/css-typed-om/CSSMatrixComponent-DOMMatrix-mutable.html",
@@ -74731,6 +75439,18 @@
      {}
     ]
    ],
+   "css/css-rhythm-1/line-height-step-dynamic-001.html": [
+    [
+     "/css/css-rhythm-1/line-height-step-dynamic-001.html",
+     {}
+    ]
+   ],
+   "css/css-rhythm-1/line-height-step-parsing-001.html": [
+    [
+     "/css/css-rhythm-1/line-height-step-parsing-001.html",
+     {}
+    ]
+   ],
    "css/css-scoping-1/shadow-cascade-order-001.html": [
     [
      "/css/css-scoping-1/shadow-cascade-order-001.html",
@@ -75835,12 +76555,6 @@
      {}
     ]
    ],
-   "css/cssom-view-1/window-screen-height-mutation-throws.html": [
-    [
-     "/css/cssom-view-1/window-screen-height-mutation-throws.html",
-     {}
-    ]
-   ],
    "css/cssom-view-1/window-screen-height.html": [
     [
      "/css/cssom-view-1/window-screen-height.html",
@@ -75853,18 +76567,18 @@
      {}
     ]
    ],
-   "css/cssom-view-1/window-screen-width-mutation-throws.html": [
-    [
-     "/css/cssom-view-1/window-screen-width-mutation-throws.html",
-     {}
-    ]
-   ],
    "css/cssom-view-1/window-screen-width.html": [
     [
      "/css/cssom-view-1/window-screen-width.html",
      {}
     ]
    ],
+   "css/selectors4/focus-within-009.html": [
+    [
+     "/css/selectors4/focus-within-009.html",
+     {}
+    ]
+   ],
    "cssom-view/HTMLBody-ScrollArea_quirksmode.html": [
     [
      "/cssom-view/HTMLBody-ScrollArea_quirksmode.html",
@@ -81441,6 +82155,12 @@
      }
     ]
    ],
+   "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001.html": [
+    [
+     "/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001.html",
+     {}
+    ]
+   ],
    "html/browsers/the-window-object/garbage-collection-and-browsing-contexts/discard_iframe_history_1.html": [
     [
      "/html/browsers/the-window-object/garbage-collection-and-browsing-contexts/discard_iframe_history_1.html",
@@ -84425,6 +85145,18 @@
      {}
     ]
    ],
+   "html/semantics/forms/textfieldselection/selection-start-end.html": [
+    [
+     "/html/semantics/forms/textfieldselection/selection-start-end.html",
+     {}
+    ]
+   ],
+   "html/semantics/forms/textfieldselection/selection-value-interactions.html": [
+    [
+     "/html/semantics/forms/textfieldselection/selection-value-interactions.html",
+     {}
+    ]
+   ],
    "html/semantics/forms/textfieldselection/selection.html": [
     [
      "/html/semantics/forms/textfieldselection/selection.html",
@@ -85186,7 +85918,9 @@
    "html/semantics/scripting-1/the-script-element/module/execorder.html": [
     [
      "/html/semantics/scripting-1/the-script-element/module/execorder.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "html/semantics/scripting-1/the-script-element/module/imports.html": [
@@ -87153,6 +87887,12 @@
      {}
     ]
    ],
+   "html/webappapis/idle-callbacks/callback-removed-frame.html": [
+    [
+     "/html/webappapis/idle-callbacks/callback-removed-frame.html",
+     {}
+    ]
+   ],
    "html/webappapis/idle-callbacks/callback-suspended.html": [
     [
      "/html/webappapis/idle-callbacks/callback-suspended.html",
@@ -87747,6 +88487,30 @@
      {}
     ]
    ],
+   "html/webappapis/timers/negative-setinterval.html": [
+    [
+     "/html/webappapis/timers/negative-setinterval.html",
+     {}
+    ]
+   ],
+   "html/webappapis/timers/negative-settimeout.html": [
+    [
+     "/html/webappapis/timers/negative-settimeout.html",
+     {}
+    ]
+   ],
+   "html/webappapis/timers/type-long-setinterval.html": [
+    [
+     "/html/webappapis/timers/type-long-setinterval.html",
+     {}
+    ]
+   ],
+   "html/webappapis/timers/type-long-settimeout.html": [
+    [
+     "/html/webappapis/timers/type-long-settimeout.html",
+     {}
+    ]
+   ],
    "infrastructure/failing-test.html": [
     [
      "/infrastructure/failing-test.html",
@@ -87843,6 +88607,18 @@
      {}
     ]
    ],
+   "mediacapture-record/BlobEvent-constructor.html": [
+    [
+     "/mediacapture-record/BlobEvent-constructor.html",
+     {}
+    ]
+   ],
+   "mediacapture-record/idlharness.html": [
+    [
+     "/mediacapture-record/idlharness.html",
+     {}
+    ]
+   ],
    "mediacapture-streams/GUM-api.https.html": [
     [
      "/mediacapture-streams/GUM-api.https.html",
@@ -98867,6 +99643,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/fetch-event-throws-after-respond-with.https.html": [
+    [
+     "/service-workers/service-worker/fetch-event-throws-after-respond-with.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/fetch-event-within-sw.https.html": [
     [
      "/service-workers/service-worker/fetch-event-within-sw.https.html",
@@ -99129,6 +99911,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/postmessage-from-waiting-serviceworker.https.html": [
+    [
+     "/service-workers/service-worker/postmessage-from-waiting-serviceworker.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/postmessage-msgport-to-client.https.html": [
     [
      "/service-workers/service-worker/postmessage-msgport-to-client.https.html",
@@ -99887,9 +100675,21 @@
      {}
     ]
    ],
-   "storage/interfaces.html": [
+   "storage/estimate-indexeddb-worker.https.html": [
     [
-     "/storage/interfaces.html",
+     "/storage/estimate-indexeddb-worker.https.html",
+     {}
+    ]
+   ],
+   "storage/estimate-indexeddb.https.html": [
+    [
+     "/storage/estimate-indexeddb.https.html",
+     {}
+    ]
+   ],
+   "storage/interfaces.https.html": [
+    [
+     "/storage/interfaces.https.html",
      {}
     ]
    ],
@@ -99905,6 +100705,12 @@
      {}
     ]
    ],
+   "storage/storagemanager-estimate.https.html": [
+    [
+     "/storage/storagemanager-estimate.https.html",
+     {}
+    ]
+   ],
    "streams/byte-length-queuing-strategy.dedicatedworker.html": [
     [
      "/streams/byte-length-queuing-strategy.dedicatedworker.html",
@@ -102063,6 +102869,12 @@
      {}
     ]
    ],
+   "webrtc/rtcpeerconnection/canTrickleIceCandidates.html": [
+    [
+     "/webrtc/rtcpeerconnection/canTrickleIceCandidates.html",
+     {}
+    ]
+   ],
    "webrtc/rtcpeerconnection/iceGatheringState.html": [
     [
      "/webrtc/rtcpeerconnection/iceGatheringState.html",
@@ -102507,12 +103319,6 @@
      {}
     ]
    ],
-   "webvtt/interfaces.html": [
-    [
-     "/webvtt/interfaces.html",
-     {}
-    ]
-   ],
    "webvtt/parsing/cue-text-parsing/tests/entities.html": [
     [
      "/webvtt/parsing/cue-text-parsing/tests/entities.html",
@@ -104839,7 +105645,7 @@
    "support"
   ],
   "./check_stability.py": [
-   "0a76eadbdc8a007cc439a909b55f0992fd8ba549",
+   "8c416e2ed1af63ca9ad682f27d50692a3e51949b",
    "support"
   ],
   "./ci_built_diff.sh": [
@@ -105050,6 +105856,10 @@
    "bfd9cbe17c74e7b181156c47228beb694d8375af",
    "testharness"
   ],
+  "FileAPI/url/url_createobjecturl_file_img-manual.html": [
+   "8b8c7324f9978c31cac34f0049d02417f47bf7f7",
+   "manual"
+  ],
   "FileAPI/url/url_xmlhttprequest.html": [
    "bb1311c54b236f9c731d31b48323690fce4759bc",
    "testharness"
@@ -105459,7 +106269,7 @@
    "testharness"
   ],
   "IndexedDB/idbdatabase-transaction-exception-order.html": [
-   "8033f0b03f01eb4363291dbc4ef16ae4b66c5bc5",
+   "c0e6f03eb0169ea46dcf2117ee9f379157c95bf0",
    "testharness"
   ],
   "IndexedDB/idbdatabase_close.htm": [
@@ -105519,7 +106329,7 @@
    "testharness"
   ],
   "IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm": [
-   "a806d39408f9a8fd9b5d2e623e19075e513d4c37",
+   "79ee4c1e5ec47887b081c9b3a8e66281023844ba",
    "testharness"
   ],
   "IndexedDB/idbdatabase_deleteObjectStore.htm": [
@@ -106051,7 +106861,7 @@
    "testharness"
   ],
   "IndexedDB/idbobjectstore_deleted.htm": [
-   "32ea0d23154b34e009839539cc482209105dec2d",
+   "b47fa902b979d5c2e270cb196cfd6f2e1d395298",
    "testharness"
   ],
   "IndexedDB/idbobjectstore_get.htm": [
@@ -106530,10 +107340,50 @@
    "0c959d5fa41c3db70c326b83e064b8261a6f90b4",
    "testharness"
   ],
-  "bluetooth/idl-Bluetooth.html": [
-   "b01463cb164865da8d516a2b68219280e7fadc0f",
+  "beacon/headers/header-referrer-no-referrer-when-downgrade.https.html": [
+   "273c7d0110d5efc9fac0029cd257256894d3eb4b",
+   "testharness"
+  ],
+  "beacon/headers/header-referrer-no-referrer.html": [
+   "26a0a9453b36efbadb05c8185efe7f9a0d9d54c9",
+   "testharness"
+  ],
+  "beacon/headers/header-referrer-origin-when-cross-origin.html": [
+   "9633758fe59279cfe93333989d26c017f59ab2ac",
+   "testharness"
+  ],
+  "beacon/headers/header-referrer-origin.html": [
+   "1329850363c327533f50e509c6a48f6e4b1ed4bb",
+   "testharness"
+  ],
+  "beacon/headers/header-referrer-same-origin.html": [
+   "9701f2f0a83c6eeefe781d7de2c0cdbcff38b58e",
+   "testharness"
+  ],
+  "beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html": [
+   "295ef746c475fca0ae8b492375a48948b4ea19c3",
+   "testharness"
+  ],
+  "beacon/headers/header-referrer-strict-origin.https.html": [
+   "295ef746c475fca0ae8b492375a48948b4ea19c3",
+   "testharness"
+  ],
+  "beacon/headers/header-referrer-unsafe-url.https.html": [
+   "a7b6e697be165124ed5d6846335c8d3a38ee98f5",
+   "testharness"
+  ],
+  "beacon/headers/header-referrer.js": [
+   "8185d2b31fbf67a573444d3c8f828f96422526f5",
    "support"
   ],
+  "beacon/resources/inspect-header.py": [
+   "e70503e7fb71617b9be631d5f2a9e73cacd83e3f",
+   "support"
+  ],
+  "bluetooth/idl-Bluetooth.html": [
+   "cfe60f252017491dc85a00b1eb028fb3fe893c42",
+   "testharness"
+  ],
   "clear-site-data/navigation.html": [
    "daf340429ca71997c7d9c6021354522f0285c4d1",
    "testharness"
@@ -107914,8 +108764,12 @@
    "70aeb617f5d580917b385346ba629e035f062c32",
    "testharness"
   ],
+  "content-security-policy/embedded-enforcement/embedding_csp-header-invalid-format.html": [
+   "3747c23fd624aefa80c2906095084e843843f3d8",
+   "testharness"
+  ],
   "content-security-policy/embedded-enforcement/embedding_csp-header.html": [
-   "f3df200f0162d3e9a1cc2d944b3a821126105d59",
+   "3a9f255c0b99f7750fe487ae6e68063954184d05",
    "testharness"
   ],
   "content-security-policy/embedded-enforcement/iframe-csp-attribute.html": [
@@ -108578,6 +109432,10 @@
    "a50a792b1ef19fe452196e5e50036d6de01dc6e5",
    "support"
   ],
+  "content-security-policy/script-src/script-src-strict_dynamic_worker.https.html": [
+   "a59f7f33614eb541a216b317f0916271f359ba1b",
+   "testharness"
+  ],
   "content-security-policy/script-src/simpleSourcedScript.js": [
    "549c6ea1f1bae2b78f933b5da0a5f2f72bae2564",
    "support"
@@ -108926,6 +109784,26 @@
    "ff4d7ca289ea20fa00bca535fdcf929876a2278b",
    "testharness"
   ],
+  "css-timing-1/cubic-bezier-timing-functions-output.html": [
+   "77a45437209844f7e5128bd6aa2efeeacf876187",
+   "testharness"
+  ],
+  "css-timing-1/frames-timing-functions-output.html": [
+   "fe9a931466f31605f1a09d5f95589cc54ee34663",
+   "testharness"
+  ],
+  "css-timing-1/frames-timing-functions-syntax.html": [
+   "7ac5eef9cec74746aa076912285398f525b01c06",
+   "testharness"
+  ],
+  "css-timing-1/step-timing-functions-output.html": [
+   "4b514aac1efca5813e5a551290f8c84f678bd41d",
+   "testharness"
+  ],
+  "css-timing-1/testcommon.js": [
+   "a39c8c7fdd3b58d03d5a544ebe51f82e65ac5645",
+   "support"
+  ],
   "css-typed-om/CSSMatrixComponent-DOMMatrix-mutable-expected.txt": [
    "b382ae164d95402e1b19a9199e647316cb41ba4c",
    "support"
@@ -110514,6 +111392,10 @@
    "f84ca76042d8475cfad273903157044125ce73a0",
    "testharness"
   ],
+  "css/css-align-3/distribution-values/space-evenly-001.html": [
+   "6fd28a5bf615ce822ed935de90ce5c1a41d39104",
+   "reftest"
+  ],
   "css/css-align-3/reference/ttwf-reftest-alignContent-ref.html": [
    "d87177e45f584e4a67695529b8dbf2d3c3c52839",
    "support"
@@ -114354,6 +115236,62 @@
    "dff3ac6f63d3adf9646a1dc48f54385064131ac7",
    "support"
   ],
+  "css/css-rhythm-1/line-height-step-basic-001.html": [
+   "92adb69ad49ca72e57da844fd71f7776c8223d2d",
+   "reftest"
+  ],
+  "css/css-rhythm-1/line-height-step-boundary-001.html": [
+   "708b1a684dcf6630e4cd42b7cd4a4434ad5036d0",
+   "reftest"
+  ],
+  "css/css-rhythm-1/line-height-step-dynamic-001.html": [
+   "0a54980b73d222838fb492316417b0133a07a6d0",
+   "testharness"
+  ],
+  "css/css-rhythm-1/line-height-step-parsing-001.html": [
+   "b40210b0e116ec0bd49b9b9abe2a1d183e6748a2",
+   "testharness"
+  ],
+  "css/css-rhythm-1/line-height-step-ruby-001.html": [
+   "c390f0b1a09531ef643e1dfa69ab5431a669e28d",
+   "reftest"
+  ],
+  "css/css-rhythm-1/line-height-step-valign-001.html": [
+   "65ed3586e233e37dd50f34e4d50c2528a9d33eed",
+   "reftest"
+  ],
+  "css/css-rhythm-1/line-height-step-writing-mode-vrl-001.html": [
+   "76b9311bfd206a246b2d4f7ed15e9edcf74afbb7",
+   "reftest"
+  ],
+  "css/css-rhythm-1/line-height-step-writing-mode-vrl-ruby-001.html": [
+   "95badb9f74c5f0aa8ae2423130029f53606455ed",
+   "reftest"
+  ],
+  "css/css-rhythm-1/reference/line-height-step-basic-001.html": [
+   "093a06eecc7016b77e85878bbde0e27e70fe18ff",
+   "support"
+  ],
+  "css/css-rhythm-1/reference/line-height-step-boundary-001.html": [
+   "d18806fbb5eb973ded1cecb9b0bf7e7c59b13b61",
+   "support"
+  ],
+  "css/css-rhythm-1/reference/line-height-step-ruby-001.html": [
+   "121f409a58d927c6246396ab7757a772f0b90ef2",
+   "support"
+  ],
+  "css/css-rhythm-1/reference/line-height-step-valign-001.html": [
+   "bb5d6ea40b4b9e06b8903d1a38b9a3352733c5c0",
+   "support"
+  ],
+  "css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-001.html": [
+   "e2d1d2d740788e4d8d62a8737a948ab6376ca21a",
+   "support"
+  ],
+  "css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-ruby-001.html": [
+   "3660f64d1cc081596b9aa472001970bebbe0a0da",
+   "support"
+  ],
   "css/css-scoping-1/css-scoping-shadow-assigned-node-with-before-after.html": [
    "85c525233e98f69e6da1f8d25270d16ce0555dd8",
    "reftest"
@@ -120699,7 +121637,7 @@
    "manual"
   ],
   "css/css-ui-3/nav-down-012.html": [
-   "9035a3e0dc0a12fad9bef11a8ed059ef2e481f2a",
+   "5a4a950a40dd6432d8d936c59ae3ad01dd4078b4",
    "manual"
   ],
   "css/css-ui-3/nav-down-013.html": [
@@ -121955,7 +122893,7 @@
    "support"
   ],
   "css/css-ui-3/support/nav-down-012-frame.html": [
-   "52ef7619103e6b91f1a196b8b7412c861b56aef4",
+   "7797c9a924743668033a652b5c6984270a9dc311",
    "support"
   ],
   "css/css-ui-3/support/nav-down-013-frame.html": [
@@ -126790,10 +127728,6 @@
    "1460613a50fb9a4da1b61542a8cf64170f4a1902",
    "support"
   ],
-  "css/css-writing-modes-3/support/mplus-1p-regular.ttf": [
-   "0170dca2414233ba050ec59250e9bed31acde21f",
-   "support"
-  ],
   "css/css-writing-modes-3/support/mplus-1p-regular.woff": [
    "708040c72a525e3ca122156c0212ca7ec14852bd",
    "support"
@@ -127503,7 +128437,7 @@
    "manual"
   ],
   "css/css-writing-modes-3/text-orientation-mixed-vrl-002.xht": [
-   "647e6bfd4c8aa78b2eedef8e4197eb4b1d00297f",
+   "da19d6136b8f893a2cebf4d2ad93a366c4f5a46d",
    "visual"
   ],
   "css/css-writing-modes-3/text-orientation-mixed-vrl-100-ref.html": [
@@ -127987,7 +128921,7 @@
    "testharness"
   ],
   "css/cssom-1/medialist-interfaces-002.html": [
-   "887bb52b994adbf7deb6be5c7aa76137db4369bf",
+   "114fac94342afe2e7fe432a67c4b0bbf03d24bc4",
    "testharness"
   ],
   "css/cssom-1/medialist-interfaces-003.html": [
@@ -128462,10 +129396,6 @@
    "7225c6d6eba532f1041cc67b0da8a40afa9f83f9",
    "testharness"
   ],
-  "css/cssom-view-1/window-screen-height-mutation-throws.html": [
-   "d02191d1a1a91703db82a693040babcfd92002d4",
-   "testharness"
-  ],
   "css/cssom-view-1/window-screen-height.html": [
    "b4c5ad3fbf782873faadd9a4b97d825d9738c8f4",
    "testharness"
@@ -128474,10 +129404,6 @@
    "e4ee8fd26e4a69631628a31537255a13ad4d6245",
    "testharness"
   ],
-  "css/cssom-view-1/window-screen-width-mutation-throws.html": [
-   "e6e352d7775e88fa8beecad57c36a497aac4c9d8",
-   "testharness"
-  ],
   "css/cssom-view-1/window-screen-width.html": [
    "da25c6d4f87e11fa716a8d028c5f0a90425d31f1",
    "testharness"
@@ -128847,11 +129773,11 @@
    "support"
   ],
   "css/selectors4/focus-within-001-ref.html": [
-   "adc2f571e88c5f770d3815f76fe34d8646c181ed",
+   "cd36270f1a34ea74b10b761cb153a7eb85b221bc",
    "support"
   ],
   "css/selectors4/focus-within-001.html": [
-   "5333c6011f01ae309103fee1a8b6406b58648456",
+   "2df6de53583a964dca7f6212a31a98880702aa6c",
    "manual"
   ],
   "css/selectors4/focus-within-002.html": [
@@ -128874,6 +129800,22 @@
    "c289bcc3ac7a48737ca0a1b961bf8b6bd4f7e52c",
    "manual"
   ],
+  "css/selectors4/focus-within-007-ref.html": [
+   "013d27b858852d7d12ddf21ef90ee21ea87bc590",
+   "support"
+  ],
+  "css/selectors4/focus-within-007.html": [
+   "ba7c8004d7da79bc5a7ba68ed80258f6b6487754",
+   "reftest"
+  ],
+  "css/selectors4/focus-within-008.html": [
+   "3d6d2dc6766fd3be3c70bfe0c55631d7b096d5c5",
+   "reftest"
+  ],
+  "css/selectors4/focus-within-009.html": [
+   "443e4d2892aced8fd5bef0cf83c62933437c3702",
+   "testharness"
+  ],
   "css/selectors4/focus-within-shadow-001-ref.html": [
    "a594bdfc84502ca2e175f390345b3cdc3292319e",
    "support"
@@ -131935,7 +132877,7 @@
    "support"
   ],
   "dom/lists/DOMTokenList-iteration.html": [
-   "9f57e9de064ac0ed809eaac749c5f2f167bebe65",
+   "342caa772b445868f2d548709c6bf4da5c81a34b",
    "testharness"
   ],
   "dom/lists/DOMTokenList-stringifier.html": [
@@ -134255,7 +135197,7 @@
    "support"
   ],
   "encrypted-media/content/content-metadata.js": [
-   "4089766ce88368170d45b6a5b0e8db48fa2ef891",
+   "5bb828a1f1a9f05d74fd2103d06bc33d28174bbc",
    "support"
   ],
   "encrypted-media/content/video_512x288_h264-360k_clear_dashinit.mp4": [
@@ -134286,14 +135228,6 @@
    "0fb6d575a357dd5fdc4544a55cb8ef4e25f0f449",
    "support"
   ],
-  "encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4": [
-   "da39a3ee5e6b4b0d3255bfef95601890afd80709",
-   "support"
-  ],
-  "encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4": [
-   "13a90556e91d127b0b8cf4a5ea3aec1dc99c2339",
-   "support"
-  ],
   "encrypted-media/drm-check-initdata-type.html": [
    "ae0f79ae94465890ded3e3a6bfd60f320b23ad44",
    "testharness"
@@ -137526,6 +138460,10 @@
    "a08540b1a71a7512a8b9cc2b0af28fd5c64bfe25",
    "testharness"
   ],
+  "html/browsers/offline/browser-state/navigator_online_event-manual.html": [
+   "6ad5311783547501b80d05eea9b7a414348b151a",
+   "manual"
+  ],
   "html/browsers/offline/browser-state/navigator_online_online.html": [
    "a06d993d34908fb332aca34a3a2002a917db9ee5",
    "testharness"
@@ -137554,6 +138492,22 @@
    "1558fa802305fe5238fac58f47203f901805ea53",
    "testharness"
   ],
+  "html/browsers/offline/manifest_main_empty-manual.html": [
+   "92ec1cd83c5a9509d19763f33720aa256e199ce2",
+   "manual"
+  ],
+  "html/browsers/offline/manifest_notchanged_online-manual.html": [
+   "f3228a9349a536ece39789a6625eb2d53444181a",
+   "manual"
+  ],
+  "html/browsers/offline/manifest_section_empty-manual.html": [
+   "da1aff7c25acc12be27193a52b5c173e2ddcf87b",
+   "manual"
+  ],
+  "html/browsers/offline/manifest_section_many-manual.html": [
+   "54c51d8c86cc5378ebde985570dca89c20a24fa0",
+   "manual"
+  ],
   "html/browsers/offline/manifest_url_check.html": [
    "0959d9811748aa674d4863bd31a5cca2d2db0d15",
    "testharness"
@@ -137610,6 +138564,14 @@
    "302b651285dd9e4367a90ce48070a3854ad3d0a2",
    "support"
   ],
+  "html/browsers/offline/section_network_offline-manual.html": [
+   "e63dc04a5b870d923689cc892168f0cd22b72405",
+   "manual"
+  ],
+  "html/browsers/offline/section_network_online-manual.html": [
+   "6a403d69ed90abeea5a4c61f6f09778224a5c184",
+   "manual"
+  ],
   "html/browsers/origin/cross-origin-objects/cross-origin-objects-expected.txt": [
    "94b45bfb4fbf4ebd1b3c126df025440d176209ac",
    "support"
@@ -137619,7 +138581,7 @@
    "testharness"
   ],
   "html/browsers/origin/cross-origin-objects/cross-origin-objects.html": [
-   "4acb7047fa505deba20030e6ee83e9e4b55349a8",
+   "a49a73b44a8484a240b14fc3877b0abed64e16dc",
    "testharness"
   ],
   "html/browsers/origin/cross-origin-objects/frame.html": [
@@ -137774,6 +138736,14 @@
    "c4f0da17299d37f70b316d709dbde0ff6a1f62fb",
    "support"
   ],
+  "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001.html": [
+   "4d40dc6b41bd10fcdb1a37894827b601b2168e1c",
+   "testharness"
+  ],
+  "html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html": [
+   "7be5d6853d829e7af8baaf96c4ef42cf858a3526",
+   "support"
+  ],
   "html/browsers/the-window-object/garbage-collection-and-browsing-contexts/discard_iframe_history_1-1.html": [
    "b1869558ff78f12b3e2b8605f90d5ac684784a80",
    "support"
@@ -138170,6 +139140,18 @@
    "3fbe2a993024f1b148bae96f942aa287836e0710",
    "testharness"
   ],
+  "html/browsers/windows/noreferrer-cross-origin-close-manual.sub.html": [
+   "7b433ceb6ee8b0800dc9151e698c8e1810032a95",
+   "manual"
+  ],
+  "html/browsers/windows/noreferrer-cross-origin-manual.html": [
+   "0c0fde6d9d61505361f1af546bc8f92846f02267",
+   "manual"
+  ],
+  "html/browsers/windows/noreferrer-cross-origin-window-name-manual.sub.html": [
+   "994b2b10b7d302ec7903c689c58b422fbd478d87",
+   "manual"
+  ],
   "html/browsers/windows/noreferrer-null-opener.html": [
    "cfced8fc2302ae4111c9c44976f36fe211ae379c",
    "testharness"
@@ -138178,6 +139160,10 @@
    "163e478a1fb6bb341d10f2ac94f868207b71bbf1",
    "testharness"
   ],
+  "html/browsers/windows/opener-cross-origin-manual.sub.html": [
+   "5bf457a85bc29c7b6da10a3a1ed829bea4b1607c",
+   "manual"
+  ],
   "html/browsers/windows/resources/browsing-context-window.html": [
    "391d8d5a5d0d8d8cfb98e4938a5bc4a5946eb13e",
    "support"
@@ -138226,6 +139212,10 @@
    "81b59630c8973be637f2ef2f379e126ea6dca69d",
    "testharness"
   ],
+  "html/browsers/windows/targeting-multiple-cross-origin-manual.sub.html": [
+   "bd24d62276b1426627f138f4a1bee27cd4c4517c",
+   "manual"
+  ],
   "html/dom/documents/dom-tree-accessors/Document.body.html": [
    "a9c8feb21f69d7a1c4824fa3dab73a7ae45dfd8f",
    "testharness"
@@ -139930,6 +140920,10 @@
    "e3e7f3973cf8f9b466d4f22d1ec3b9b9241fb906",
    "support"
   ],
+  "html/editing/activation/click-manual.html": [
+   "b07249eacb63c9532ef93c4392363cf129a0ef6c",
+   "manual"
+  ],
   "html/editing/activation/click.html": [
    "67a574b4b6721eacfaa940d934d1907c3b2b49cd",
    "testharness"
@@ -143062,54 +144056,170 @@
    "c4a4f9718167c650acb20648700311a60e2744cc",
    "testharness"
   ],
+  "html/editing/dnd/target-origin/003-manual.html": [
+   "e69d11159f774836e61e5f2546e6d9fbeff5ca53",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/004-1.html": [
    "33d7eef7bee461aff964e96d1fb3394529cbc6d0",
    "support"
   ],
+  "html/editing/dnd/target-origin/004-manual.html": [
+   "c77294bf317f351ff76243ab555ec7b71c5ab71e",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/005-1.html": [
    "37ce96f7a8681a6e0956c95a2dbc43fd779a3dc6",
    "support"
   ],
+  "html/editing/dnd/target-origin/005-manual.html": [
+   "7f66f99412f884ebdc4b25d51bb9795deb250273",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/006-manual.html": [
+   "656c884288500bb0429e4d92f9caec6b8e924e63",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/007-manual.html": [
+   "d737ee3882a5ad1b0d9042a2c5f5ca4d16cea5c8",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/008-manual.html": [
+   "b52f42121599104973962348e800b7812c757cf7",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/009-manual.html": [
+   "42c8d336dcb7a1cb75171808bb44fbc7e96a5455",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/010-manual.html": [
+   "68336689ef2f125ea2b06c801c8d7e677d94891d",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/011-manual.html": [
+   "445dea90323b62ecf8bfb417ae5fda657d499f06",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/012-manual.html": [
+   "ab67a181b30a3fd44f070be75b083068a884b728",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/013-manual.html": [
+   "e40dbfec1ecc3352161e631be76518c6d2858876",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/102-manual.html": [
+   "9ece8b77c568879ff207702635c6cb25356d15c0",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/103-1.html": [
    "a32f92d11624e06618768aa3cf706f4995359146",
    "support"
   ],
+  "html/editing/dnd/target-origin/103-manual.html": [
+   "527a8a34f19921326f889fc1f65dc1c07bbca7f6",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/104-1.html": [
    "2115efbc1490ad8bc7d37159a8ba69179bc0c369",
    "support"
   ],
+  "html/editing/dnd/target-origin/104-manual.html": [
+   "2c58aa33fce9ddfd473c4b526fb672e5299357c9",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/105-1.html": [
    "6375d254fbae051da48268de7d1b293d3460f421",
    "support"
   ],
+  "html/editing/dnd/target-origin/105-manual.html": [
+   "7917f47d0d74a051d6c714ae6c311a5d96b7f745",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/106-1.html": [
    "aee5cd9da9e1343594bb8bf7788d6925be0d0fb7",
    "support"
   ],
+  "html/editing/dnd/target-origin/106-manual.html": [
+   "4d0cce566bad31410a2a358634d4dea564a79c6f",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/107-1.html": [
    "1bbd9e32f8da544d3c41c10b7e720408c3e58a76",
    "support"
   ],
+  "html/editing/dnd/target-origin/107-manual.html": [
+   "25cf395aabe9156b3858008e72d48631b0bada9d",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/108-1.html": [
    "a29c950b5ad6ee56380b20c98c69d9606a14e04a",
    "support"
   ],
+  "html/editing/dnd/target-origin/108-manual.html": [
+   "6f010e7732b6c825a5e821d1e8d006705dbd9600",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/109-1.html": [
    "0d2fad56c7282aee5252e8f7a0a00156e6b10b32",
    "support"
   ],
+  "html/editing/dnd/target-origin/109-manual.html": [
+   "8ddef20c18fb6b2292686d450dc75fa7a6888584",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/110-1.html": [
    "b53437ad02958585eeddf89576bced8dab40f5da",
    "support"
   ],
+  "html/editing/dnd/target-origin/110-manual.html": [
+   "8b128fd12178e69443603e4fde7ddb7f5dc007ec",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/111-manual.html": [
+   "51edc8c2b06af629706177f02f09b1e6b233a32d",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/112-manual.html": [
+   "7993a414b0d604f588bfe0a3af1bf3b2ea41724c",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/113-manual.html": [
+   "8491b5284e04f949be78ce363eafa1747cee6d76",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/114-manual.html": [
+   "16a683ae1250c4f520be4f29d2e3ed27a022d236",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/115-manual.html": [
+   "1c325556a7bc97687551dcb6bd7a56259930498b",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/116-manual.html": [
+   "b7e014e3809996a49266c9b04bf8afd31be2b756",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/117-1.html": [
    "279f22f2811747da2c9a6233daf2c493de573dd6",
    "support"
   ],
+  "html/editing/dnd/target-origin/117-manual.html": [
+   "3b6966dae64c77c239d1e0986a8fd202edfd3b76",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/118-1.html": [
    "6144ac93a048df6ecf60fdbf8a646db99bc15d40",
    "support"
   ],
+  "html/editing/dnd/target-origin/118-manual.html": [
+   "5e3e6a22510cfed07c212c4f13c0a41ed3c61d67",
+   "manual"
+  ],
+  "html/editing/dnd/target-origin/201-manual.html": [
+   "93ee484628fad1b812589616ea5fac54842444d5",
+   "manual"
+  ],
   "html/editing/dnd/target-origin/202-expected.txt": [
    "07bdd966169a58835d9d4cea77156fc0dbb5f00c",
    "support"
@@ -143466,6 +144576,22 @@
    "e3e7f3973cf8f9b466d4f22d1ec3b9b9241fb906",
    "support"
   ],
+  "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-down-manual.html": [
+   "0c95bf0a298c18e6ba33c3ec56558c0a3594ba65",
+   "manual"
+  ],
+  "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-left-manual.html": [
+   "e153d40043df3389e7b9e37c77c01df9420d965b",
+   "manual"
+  ],
+  "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-right-manual.html": [
+   "2ef3b81bfe304f44715f1ec700917eb2e11b1896",
+   "manual"
+  ],
+  "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-up-manual.html": [
+   "1d013b5e6392d28fbd2cffea02609bce865376ef",
+   "manual"
+  ],
   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-events.html": [
    "5c8fa784e1adb2a3e63b1cb11907df61f06594cf",
    "testharness"
@@ -143474,6 +144600,10 @@
    "9a98aa21aaeac6629268de06ea796ad835c7a2c5",
    "testharness"
   ],
+  "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-scrollamount-effect-manual.html": [
+   "a7a7790cd018419a7cc0ebb32589633bee1c630b",
+   "manual"
+  ],
   "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-scrollamount.html": [
    "34721e8a877f559df50991dd1ba955c47cb59d0b",
    "testharness"
@@ -143486,6 +144616,14 @@
    "02f00d35b00fd8c08f7063ab8920171ab5070a71",
    "testharness"
   ],
+  "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-start-manual.html": [
+   "e63a7fd287ddd3d5e148edd589df5953d7933dfc",
+   "manual"
+  ],
+  "html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-stop-manual.html": [
+   "2896b41f40702a36e2e35ebdc1bc0a049c7be909",
+   "manual"
+  ],
   "html/rendering/bindings/the-button-element/button-type-menu-historical-ref.html": [
    "95f61bd62a89467229aac48744a2ccefd62e81c6",
    "support"
@@ -143923,7 +145061,7 @@
    "support"
   ],
   "html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html": [
-   "29e2eedb67a0a8e80c5bc09cbda5acb3d74bed74",
+   "2eaa79128917a0d0888b7155adfa0fb83bcb7c1f",
    "reftest"
   ],
   "html/rendering/replaced-elements/embedded-content-rendering-rules/canvas_scale.html": [
@@ -144258,10 +145396,30 @@
    "81e9d89988e89b3ee4c6913a346a8ac3f2a78ab3",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/audio_controls_present-manual.html": [
+   "9dacdb9cf50ff61b0b7d31cba1304bfddc2b9a58",
+   "manual"
+  ],
+  "html/semantics/embedded-content/media-elements/audio_muted_overriding_volume-manual.html": [
+   "38a1bdd2f5d5da661e43482e9050b6b708837863",
+   "manual"
+  ],
+  "html/semantics/embedded-content/media-elements/audio_muted_present-manual.html": [
+   "5b250c9e2229093a94054e2ff57ee2780bc1f098",
+   "manual"
+  ],
   "html/semantics/embedded-content/media-elements/audio_volume_check.html": [
    "cff6959699195d9c6ff68dacb4afc82b5f278633",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/audio_volume_loudest-manual.html": [
+   "53b839b42a2ae96f3d92e14bb6d17115a757946e",
+   "manual"
+  ],
+  "html/semantics/embedded-content/media-elements/audio_volume_silent-manual.html": [
+   "33bf062c202724a1ca7cd6db052614317acba1f8",
+   "manual"
+  ],
   "html/semantics/embedded-content/media-elements/contains.json": [
    "c4e395b396f7f8d9aac3e687d34c2df47dde5589",
    "support"
@@ -144746,10 +145904,30 @@
    "087f17d5f7a75ac1990ef7ecb413fc4eaf312be5",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/video_controls_present-manual.html": [
+   "9c0b04737cb4aa758d017d3f17dd0e71e6e4adcb",
+   "manual"
+  ],
+  "html/semantics/embedded-content/media-elements/video_muted_overriding_volume-manual.html": [
+   "8cacab3375c6e43e59a733319268fdd1f7a5a3ce",
+   "manual"
+  ],
+  "html/semantics/embedded-content/media-elements/video_muted_present-manual.html": [
+   "6a56b5d15989c6a3cbc8a2c7518d5d16f8dd518c",
+   "manual"
+  ],
   "html/semantics/embedded-content/media-elements/video_volume_check.html": [
    "db84177dab89555eaa16ca3efbda137095ef3b9b",
    "testharness"
   ],
+  "html/semantics/embedded-content/media-elements/video_volume_loudest-manual.html": [
+   "759e27321c7879b6e8d00fc05dd89274cd04306e",
+   "manual"
+  ],
+  "html/semantics/embedded-content/media-elements/video_volume_silent-manual.html": [
+   "1a49e63bead4193320af13bb6deaf130ff4397eb",
+   "manual"
+  ],
   "html/semantics/embedded-content/media-elements/volume_nonfinite.html": [
    "8840fa9072d9367f358721ed757bd3d23dd64967",
    "testharness"
@@ -145194,6 +146372,10 @@
    "7b3b0eaa8b9f8f2637fef56c93ab168e58eb0038",
    "testharness"
   ],
+  "html/semantics/forms/attributes-common-to-form-controls/dirname-rtl-manual.html": [
+   "3e9b3bfe4d164122770ef5ef4359a3de558f612d",
+   "manual"
+  ],
   "html/semantics/forms/attributes-common-to-form-controls/disabled-elements-01.html": [
    "800debbaa17f2bceb5fc2e85f50fa2dcb1639bec",
    "testharness"
@@ -145410,16 +146592,24 @@
    "3763f117f8973ca9a994354ccbf22cb7114ece7a",
    "testharness"
   ],
+  "html/semantics/forms/textfieldselection/selection-start-end.html": [
+   "e38a79075e27780327f49e7ae9cadd2558165eac",
+   "testharness"
+  ],
+  "html/semantics/forms/textfieldselection/selection-value-interactions.html": [
+   "0f93258e5237c49fa24efe5180409e48721e8025",
+   "testharness"
+  ],
   "html/semantics/forms/textfieldselection/selection.html": [
-   "d869799718137671a2eacc323aa26ea4364e845f",
+   "7f3969423e86313ec20846c84f8deecc95048b82",
    "testharness"
   ],
   "html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html": [
-   "b715f32cbedd8ff2b92f476032544b4e793e7288",
+   "f824af3b23cc1d0412783dbcbcbdee818a501d56",
    "testharness"
   ],
   "html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html": [
-   "9185143b495f110c289b1f8f4dc3d93821ff36fb",
+   "a3f85905acb42372806d07259e09d75e2fd8db1f",
    "testharness"
   ],
   "html/semantics/forms/the-button-element/OWNERS": [
@@ -145754,10 +146944,18 @@
    "63f4331aa44145b71888c967d4b252610cd3ebc3",
    "testharness"
   ],
+  "html/semantics/forms/the-optgroup-element/optgroup-disabled-manual.html": [
+   "d5adddda9e4c60593b71630fe395b2da8cac4c98",
+   "manual"
+  ],
   "html/semantics/forms/the-option-element/OWNERS": [
    "e3e7f3973cf8f9b466d4f22d1ec3b9b9241fb906",
    "support"
   ],
+  "html/semantics/forms/the-option-element/option-disabled-manual.html": [
+   "566d5202b873e0dddbbdf76d2a07fdb28554b709",
+   "manual"
+  ],
   "html/semantics/forms/the-option-element/option-form.html": [
    "d5a7b7f4c0ed63c3062382ac90074dfe9172e75b",
    "testharness"
@@ -145870,6 +147068,14 @@
    "b8417ba9dd70255892de6d8bde5761c0afddf374",
    "reftest"
   ],
+  "html/semantics/forms/the-textarea-element/textarea-placeholder-manual.html": [
+   "3996346ce063917b066de8b0b20b731666af6476",
+   "manual"
+  ],
+  "html/semantics/forms/the-textarea-element/textarea-select-manual.html": [
+   "7b513a17599ea93eb430a81bbff8d5aa94d07c3c",
+   "manual"
+  ],
   "html/semantics/forms/the-textarea-element/textarea-type.html": [
    "81a270bc3c9304f8b2e7dd526519f4eab7d94f45",
    "testharness"
@@ -146559,7 +147765,7 @@
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/execorder.html": [
-   "66a5dcd461023501ed125402aa5393c168031614",
+   "a1b14284d50eda5bd745c113cf9df10a621895f2",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports-a.js": [
@@ -147022,6 +148228,10 @@
    "e3e7f3973cf8f9b466d4f22d1ec3b9b9241fb906",
    "support"
   ],
+  "html/semantics/selectors/pseudo-classes/checked-001-manual.html": [
+   "6be1e4a40962036b4fc0a300e8b13a082b391713",
+   "manual"
+  ],
   "html/semantics/selectors/pseudo-classes/checked-expected.txt": [
    "a80532a871d559cac125eb59c34f48f49ba7f160",
    "support"
@@ -148131,7 +149341,7 @@
    "testharness"
   ],
   "html/webappapis/idle-callbacks/callback-idle-periods.html": [
-   "29559d93a0401a3bc62b2cb717c438a01c1f439a",
+   "65056dde042c8c0a25d3f9c375f0925aabab955f",
    "testharness"
   ],
   "html/webappapis/idle-callbacks/callback-iframe.html": [
@@ -148146,6 +149356,10 @@
    "6375309c43a1e7c9fafdc95f01fcccb4c92f8afc",
    "testharness"
   ],
+  "html/webappapis/idle-callbacks/callback-removed-frame.html": [
+   "ff034276659407d2dea91d2b0ed0e5919b875904",
+   "testharness"
+  ],
   "html/webappapis/idle-callbacks/callback-suspended-expected.txt": [
    "cc31200fbead20c404cf4a4eee28488be9c76e44",
    "support"
@@ -148802,6 +150016,22 @@
    "49fd55dbbf64c6973a0e76284c0e3d8b7bf0ef3c",
    "testharness"
   ],
+  "html/webappapis/timers/negative-setinterval.html": [
+   "405046cab9cd15a88d57eace1f293ebdd7b1b3e2",
+   "testharness"
+  ],
+  "html/webappapis/timers/negative-settimeout.html": [
+   "e5673e7cca2b006afd3e2e4e5dd3e56fb10efa4e",
+   "testharness"
+  ],
+  "html/webappapis/timers/type-long-setinterval.html": [
+   "83e3c7536d163ead98a008c7d9ff8cf41826371d",
+   "testharness"
+  ],
+  "html/webappapis/timers/type-long-settimeout.html": [
+   "7945f54f8ab924c85f337ad5a50b02677d48e526",
+   "testharness"
+  ],
   "images/anim-gr.gif": [
    "d348de95f364f6654edc197ac5c72ebd4339f11b",
    "support"
@@ -149146,6 +150376,14 @@
    "ceeb48e7982eb88561f4c1630cb0fcf15d9cf73c",
    "testharness"
   ],
+  "mediacapture-record/BlobEvent-constructor.html": [
+   "29d5649ff97ca0631f8c841425a88248525f9774",
+   "testharness"
+  ],
+  "mediacapture-record/idlharness.html": [
+   "d96f50512a47fed449151b716d838ac10d23f47f",
+   "testharness"
+  ],
   "mediacapture-streams/GUM-api.https.html": [
    "6f4e3b2b4fdb287f99935193f273cb21becb9669",
    "testharness"
@@ -159846,6 +161084,10 @@
    "2feaa5022ee31fb980f97075d932b0d87d6efe75",
    "testharness"
   ],
+  "service-workers/service-worker/fetch-event-throws-after-respond-with.https.html": [
+   "41a64740d1d56a839f0888837a56c2b74cab0c77",
+   "testharness"
+  ],
   "service-workers/service-worker/fetch-event-within-sw-manual.https-expected.txt": [
    "3aedda99e8e2af542cd84a73386e11938555e326",
    "support"
@@ -160126,6 +161368,10 @@
    "4ffd522eacbd5ecee11b921d4acc3442ef296514",
    "testharness"
   ],
+  "service-workers/service-worker/postmessage-from-waiting-serviceworker.https.html": [
+   "99519ec3ef70e08fe42fce50bb6e9d643a2daa9f",
+   "testharness"
+  ],
   "service-workers/service-worker/postmessage-msgport-to-client.https.html": [
    "21ae7fb96321dc75e7063c27b7e6838e6b9ff6c6",
    "testharness"
@@ -160203,7 +161449,7 @@
    "testharness"
   ],
   "service-workers/service-worker/request-end-to-end.https.html": [
-   "1e2b1ee0455beeb2a609e927d2bf2655a9a801f6",
+   "0f7bee59205515c72ae6d4aa1f408e8414f9659a",
    "testharness"
   ],
   "service-workers/service-worker/resource-timing.https-expected.txt": [
@@ -160322,6 +161568,10 @@
    "33ab5639bfd8e7b95eb1d8d0b87781d4ffea4d5d",
    "support"
   ],
+  "service-workers/service-worker/resources/echo-message-to-source-worker.js": [
+   "760b04aa2e36f55cfdbea0871a7424f787734a6e",
+   "support"
+  ],
   "service-workers/service-worker/resources/empty-but-slow-worker.js": [
    "36ecac2f5ab2d3738ca72a7a7d1c605dbec97ff1",
    "support"
@@ -160738,6 +161988,10 @@
    "ee7888f2e145700cf2590b6d6de9bab39088a979",
    "support"
   ],
+  "service-workers/service-worker/resources/respond-then-throw-worker.js": [
+   "d57215bcad8a3966175930642dfd34281b11aeff",
+   "support"
+  ],
   "service-workers/service-worker/resources/service-worker-csp-worker.py": [
    "f7c6bb3ba222dc35a09ef806a7c6d145339f9eb2",
    "support"
@@ -161638,11 +162892,15 @@
    "5ce835b9c17e0cd61830abdd4f4e7aa5d5a47d8d",
    "support"
   ],
-  "storage/interfaces-expected.txt": [
-   "2763c4aab3b040727421dbd408d05582fe5ad17f",
-   "support"
+  "storage/estimate-indexeddb-worker.https.html": [
+   "83d656e5ff94d6ba94f5106ea0c17869ee15fc49",
+   "testharness"
   ],
-  "storage/interfaces.html": [
+  "storage/estimate-indexeddb.https.html": [
+   "6e5db2d0c2f5d2d8f1e2d04da953a3f2c50bec7a",
+   "testharness"
+  ],
+  "storage/interfaces.https.html": [
    "76fa61c3a87485266a7f9d6f66e5d08bb7881ff7",
    "testharness"
   ],
@@ -161658,6 +162916,14 @@
    "6ce5a9b14d80030f0adfa1808857294e8c923cb2",
    "testharness"
   ],
+  "storage/storage-estimate-indexeddb.js": [
+   "660d3d068314c34d215df19c0b849ec711f57854",
+   "support"
+  ],
+  "storage/storagemanager-estimate.https.html": [
+   "6319416d647f1671a7b8d36bbb4d79495e76a956",
+   "testharness"
+  ],
   "streams/README.md": [
    "301e457a14a26ed154a55d2811e32d5ceb4b004c",
    "support"
@@ -161735,7 +163001,7 @@
    "testharness"
   ],
   "streams/piping/close-propagation-forward.js": [
-   "0846ba92abb8ace6c5438d918b2db23badc090b2",
+   "955736af478e8ec307dfe00a461f4b72949b110d",
    "support"
   ],
   "streams/piping/close-propagation-forward.serviceworker.https.html": [
@@ -161843,7 +163109,7 @@
    "testharness"
   ],
   "streams/piping/multiple-propagation.js": [
-   "c2a5c855e9abbacfe500a9339ff586a16bb8ae7a",
+   "8d00cd13d84d421a297bff499511d96f7b72c98c",
    "support"
   ],
   "streams/piping/multiple-propagation.serviceworker.https-expected.txt": [
@@ -161879,7 +163145,7 @@
    "testharness"
   ],
   "streams/piping/pipe-through.js": [
-   "08daa95df8e64c57f082b297ffd8bd11cda54d26",
+   "8960662dd6a59e4950c1e8ee86d0ea21de5b1bf7",
    "support"
   ],
   "streams/piping/pipe-through.serviceworker.https-expected.txt": [
@@ -162802,6 +164068,14 @@
    "ee83feb002acf1f134fecf618d985103c906472b",
    "support"
   ],
+  "uievents/keyboard/key-101en-us-manual.html": [
+   "8c4bedcea88fd39cfe291e40b11c3b0cb510267a",
+   "manual"
+  ],
+  "uievents/keyboard/key-102fr-fr-manual.html": [
+   "74ec4ae6f0cfa8ddc2f296d058a70d64977eb28a",
+   "manual"
+  ],
   "uievents/keyboard/key-manual.css": [
    "54d5f8a452d8bbbd040e66af7594debacb6d0377",
    "manual"
@@ -163250,18 +164524,34 @@
    "ebccba780b163032d4aba54cdbbf1b892464bcfa",
    "support"
   ],
+  "web-animations/animation-model/animation-types/spacing-keyframes-filters-expected.txt": [
+   "da8fe0c766d05a527459abf893e11c731c11066f",
+   "support"
+  ],
   "web-animations/animation-model/animation-types/spacing-keyframes-filters.html": [
    "bd771a8a18245560221d92ea3495f81918c09848",
    "testharness"
   ],
+  "web-animations/animation-model/animation-types/spacing-keyframes-shapes-expected.txt": [
+   "1853881a39ce2489749087712bcc4952d0d5af05",
+   "support"
+  ],
   "web-animations/animation-model/animation-types/spacing-keyframes-shapes.html": [
    "03c3ab6815cfa96c07d5f95b6059fb276c50a25f",
    "testharness"
   ],
+  "web-animations/animation-model/animation-types/spacing-keyframes-transform-expected.txt": [
+   "7c7adb24bd8bb6ed9d77064bd04e09240b2ab972",
+   "support"
+  ],
   "web-animations/animation-model/animation-types/spacing-keyframes-transform.html": [
    "c1c5c2ea4580948d00502a048f3e562c61006ab9",
    "testharness"
   ],
+  "web-animations/animation-model/combining-effects/effect-composition-expected.txt": [
+   "81b8e29ad1ee04ce1f5958dfaca07d73a31112ca",
+   "support"
+  ],
   "web-animations/animation-model/combining-effects/effect-composition.html": [
    "8ac06085132d822e908d48de4c1109b66323f19f",
    "testharness"
@@ -163279,7 +164569,7 @@
    "testharness"
   ],
   "web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html": [
-   "59e86254c8c118bd30b5c6742cfeaceba783eaee",
+   "a0f0dc7d2f4833a68c6f8a5f908c498b05c6b22e",
    "testharness"
   ],
   "web-animations/animation-model/keyframe-effects/effect-value-visibility.html": [
@@ -163310,6 +164600,10 @@
    "a28589129c6a2665295695f786b7beb2dd887fb3",
    "testharness"
   ],
+  "web-animations/interfaces/Animation/constructor-expected.txt": [
+   "641ffb2dee3c62704dd4cc90350ac11517d2fcee",
+   "support"
+  ],
   "web-animations/interfaces/Animation/constructor.html": [
    "20604949fc295efc398e297b9e4f755a116f0fbb",
    "testharness"
@@ -163330,6 +164624,10 @@
    "61ab2a2d822c25f2311756baeaaa98b44c3b3a62",
    "testharness"
   ],
+  "web-animations/interfaces/Animation/finished-expected.txt": [
+   "1941345f4d9ee7c00d908395f731feb9de5a7641",
+   "support"
+  ],
   "web-animations/interfaces/Animation/finished.html": [
    "5e3d8fa48b2737202f6bd7c2e21589e904982a6f",
    "testharness"
@@ -163462,6 +164760,10 @@
    "3a626b145f4eb77e816b9020f6fc67630088a00b",
    "testharness"
   ],
+  "web-animations/interfaces/KeyframeEffect/composite-expected.txt": [
+   "8b091c93bb0c13e0935d3b09980f9e905619be7c",
+   "support"
+  ],
   "web-animations/interfaces/KeyframeEffect/composite.html": [
    "2580086b2da9b29d1645484c5ad4e59636a370e5",
    "testharness"
@@ -163474,6 +164776,10 @@
    "1011b4146d1054ee6498cce1905230a10fdb9f96",
    "testharness"
   ],
+  "web-animations/interfaces/KeyframeEffect/copy-contructor-expected.txt": [
+   "a8964b5d29840b1a09c4adc16495650891b0cd99",
+   "support"
+  ],
   "web-animations/interfaces/KeyframeEffect/copy-contructor.html": [
    "e1dfb5c05807a37974ecce98bb8c683cc291bfe4",
    "testharness"
@@ -163526,6 +164832,10 @@
    "2231741d51d2645b5ff97fc4ec6156d5bc6cd442",
    "testharness"
   ],
+  "web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor-expected.txt": [
+   "d6ea5e7b84c29247c588cb7582233525e21c5248",
+   "support"
+  ],
   "web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor.html": [
    "8ef986f13e7fe7ffeb7403f647b4169ac0d6a138",
    "testharness"
@@ -163539,7 +164849,7 @@
    "testharness"
   ],
   "web-animations/resources/easing-tests.js": [
-   "2946cba8cbfa1216e5f1e941d92a1695473dc5f4",
+   "5ef1183a4d3e12ad3edfe678c9fa002e7edce888",
    "support"
   ],
   "web-animations/resources/keyframe-utils.js": [
@@ -163547,7 +164857,7 @@
    "support"
   ],
   "web-animations/testcommon.js": [
-   "001012b71248cdecba02215c827ab437b672e8c6",
+   "26d892976e935d0352ef1ede012435cc67be9f79",
    "support"
   ],
   "web-animations/timing-model/animation-effects/active-time.html": [
@@ -163606,6 +164916,10 @@
    "84afa495b1a4c467e27b1394f6449a18c58ed98d",
    "testharness"
   ],
+  "web-animations/timing-model/animations/set-the-target-effect-of-an-animation-expected.txt": [
+   "f535bf4fa066383c2ce0dc0df4deefeff825f61f",
+   "support"
+  ],
   "web-animations/timing-model/animations/set-the-target-effect-of-an-animation.html": [
    "840be610db4bce6d6fd1c22710e494a75ee95eba",
    "testharness"
@@ -163627,7 +164941,7 @@
    "support"
   ],
   "web-animations/timing-model/time-transformations/transformed-progress.html": [
-   "6eebd47c9e60c9590de4d1747f8b8b7866a4a275",
+   "66e2277c77e4bd7b2d8981a725fb5083a8f5e0f6",
    "testharness"
   ],
   "webmessaging/Channel_postMessage_DataCloneErr.htm": [
@@ -163679,7 +164993,7 @@
    "testharness"
   ],
   "webmessaging/README.md": [
-   "4c7f9f149edb1036692128007742f8ae358e167a",
+   "d126c708f1d34de380f2e063bb8e404f30b6a487",
    "support"
   ],
   "webmessaging/Transferred_objects_unusable.sub.htm": [
@@ -164082,6 +165396,10 @@
    "392d4975b232b9003a75d3771ba5c6f2e992849e",
    "testharness"
   ],
+  "webrtc/rtcpeerconnection/canTrickleIceCandidates.html": [
+   "0f585a89bd8f25aa8f83b6ec39b704cbb8e970b2",
+   "testharness"
+  ],
   "webrtc/rtcpeerconnection/iceGatheringState-expected.txt": [
    "6be33b9fb07075dfc81993ff1753e48a86f295b4",
    "support"
@@ -164135,7 +165453,7 @@
    "support"
   ],
   "webstorage/README.md": [
-   "48097218468237985b9c3275f8e72979e44fe214",
+   "2f211af6d9f953cebb65e8bbfcbf417e50788a45",
    "support"
   ],
   "webstorage/document-domain-expected.txt": [
@@ -164354,6 +165672,10 @@
    "08da6fc4d68c81f62f8672aafb3a853b63b76dec",
    "testharness"
   ],
+  "webstorage/storage_local-manual.html": [
+   "6c9458030433169323987ae7b500fbae274de4a0",
+   "manual"
+  ],
   "webstorage/storage_local_setitem_quotaexceedederr.html": [
    "824fa172c54dcd7bebf6dbab749a169960e2d487",
    "testharness"
@@ -164366,6 +165688,10 @@
    "247aa2db65ada2658d99ed713dca1cf130528bc1",
    "testharness"
   ],
+  "webstorage/storage_session-manual.html": [
+   "000ef52efc45546647e13d3e2e42eae20559fc89",
+   "manual"
+  ],
   "webstorage/storage_session_setitem_quotaexceedederr.html": [
    "16420690823c36d08a83656746a0f05324602036",
    "testharness"
@@ -164403,11 +165729,11 @@
    "testharness"
   ],
   "webvr/idlharness-expected.txt": [
-   "7079dade4dae2bb7e2a669f1ac0c645eb0ac4e9a",
+   "c0960e8c78266a7a6fe49a91c963f393b04dd060",
    "support"
   ],
   "webvr/idlharness.html": [
-   "53ac12278e26e70cc0f6d6f31171fc4d2b6e6667",
+   "236974fe82ab29908e849d25c5ce748f5c0509c3",
    "testharness"
   ],
   "webvtt/README.md": [
@@ -164554,14 +165880,6 @@
    "d3fcb8823fa1a9b40aafc398aec3926951cb6aba",
    "support"
   ],
-  "webvtt/interfaces-expected.txt": [
-   "8dd4d09321332d620e50160d2f7f60ea4a2d2bd6",
-   "support"
-  ],
-  "webvtt/interfaces.html": [
-   "612566f403696557e64a686a1ab68956431666ef",
-   "testharness"
-  ],
   "webvtt/parsing/README.md": [
    "0c79a65dd7cbc9f22cdf7de7b98f71a7fff788fa",
    "support"
@@ -167259,7 +168577,7 @@
    "support"
   ],
   "workers/README.md": [
-   "2660d9dbe4f7a2947ec78b14e6418554c8204d6b",
+   "b32446a62602baf1a316520ee8e2e5d9e60cada3",
    "support"
   ],
   "workers/SharedWorker_blobUrl.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/url_createobjecturl_file_img-manual.html b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/url_createobjecturl_file_img-manual.html
new file mode 100644
index 0000000..534c1de
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/FileAPI/url/url_createobjecturl_file_img-manual.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>FileAPI Test: Creating Blob URL with File as image source</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="JunChen Xia" href="mailto:xjconlyme@gmail.com">
+
+<div>
+  <p>Test steps:</p>
+  <ol>
+    <li>Download <a href="/images/blue96x96.png">blue96x96.png</a> to local.</li>
+    <li>Select the local file (blue96x96.png) to run the test.</li>
+  </ol>
+  <p>Pass/fail criteria:</p>
+  <p>Test passes if there is a filled blue square.</p>
+
+  <p><input type="file" accept="image/*" id="fileChooser"></p>
+  <p><img id="displayImage"></img></p>
+</div>
+
+<script>
+  var fileInput = document.querySelector("#fileChooser");
+  var img = document.querySelector("#displayImage");
+
+  fileInput.addEventListener("change", function(evt) {
+    img.src = window.URL.createObjectURL(fileInput.files[0]);
+  }, false);
+</script>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbdatabase-transaction-exception-order.html b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbdatabase-transaction-exception-order.html
index 686f44ef5..c0021d9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbdatabase-transaction-exception-order.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbdatabase-transaction-exception-order.html
@@ -45,10 +45,10 @@
     assert_throws('NotFoundError', () => {
       db.transaction('no-such-store', 'versionchange');
     }, '"No such store" check (NotFoundError) should precede ' +
-       '"invalid mode" check (InvalidAccessError)');
+       '"invalid mode" check (TypeError)');
     t.done();
   },
-  'IDBDatabase.transaction exception order: NotFoundError vs. InvalidAccessError'
+  'IDBDatabase.transaction exception order: NotFoundError vs. TypeError'
 );
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm
index 0a6dc03a..4a28d40 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbdatabase_createObjectStore9-invalidparameters.htm
@@ -7,11 +7,11 @@
 <script src=support.js></script>
 
 <script>
-    function invalid_optionalParameters(desc, params) {
+    function invalid_optionalParameters(desc, params, exception = "InvalidAccessError") {
         var t = async_test(document.title + " - " + desc);
 
         createdb(t).onupgradeneeded = function(e) {
-            assert_throws(null, function() {
+            assert_throws(exception, function() {
                 e.target.result.createObjectStore("store", params);
             });
 
@@ -20,9 +20,9 @@
     }
 
     invalid_optionalParameters("autoInc and empty keyPath", {autoIncrement: true, keyPath: ""});
-    invalid_optionalParameters("autoInc and keyPath array", {autoIncrement: true, keyPath: []});
+    invalid_optionalParameters("autoInc and keyPath array", {autoIncrement: true, keyPath: []}, "SyntaxError");
     invalid_optionalParameters("autoInc and keyPath array 2", {autoIncrement: true, keyPath: ["hey"]});
-    invalid_optionalParameters("autoInc and keyPath object", {autoIncrement: true, keyPath: {a:"hey", b:2}});
+    invalid_optionalParameters("autoInc and keyPath object", {autoIncrement: true, keyPath: {a:"hey", b:2}}, "SyntaxError");
 
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbobjectstore_deleted.htm b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbobjectstore_deleted.htm
index 1d9421c..74934636 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbobjectstore_deleted.htm
+++ b/third_party/WebKit/LayoutTests/external/wpt/IndexedDB/idbobjectstore_deleted.htm
@@ -28,16 +28,17 @@
         db.deleteObjectStore("store");
         assert_equals(db.objectStoreNames.length, 0, "objectStoreNames.length after delete");
 
-        assert_throws(null, function() { objStore.add(2); });
-        assert_throws(null, function() { objStore.put(3); });
-        assert_throws(null, function() { objStore.get(1); });
-        assert_throws(null, function() { objStore.clear(); });
-        assert_throws(null, function() { objStore.count(); });
-        assert_throws(null, function() { objStore.delete(1); });
-        assert_throws(null, function() { objStore.openCursor(); });
-        assert_throws(null, function() { objStore.index("idx"); });
-        assert_throws(null, function() { objStore.deleteIndex("idx"); });
-        assert_throws(null, function() { objStore.createIndex("idx2", "a"); });
+        const exc = "InvalidStateError"
+        assert_throws(exc, function() { objStore.add(2); });
+        assert_throws(exc, function() { objStore.put(3); });
+        assert_throws(exc, function() { objStore.get(1); });
+        assert_throws(exc, function() { objStore.clear(); });
+        assert_throws(exc, function() { objStore.count(); });
+        assert_throws(exc, function() { objStore.delete(1); });
+        assert_throws(exc, function() { objStore.openCursor(); });
+        assert_throws(exc, function() { objStore.index("idx"); });
+        assert_throws(exc, function() { objStore.deleteIndex("idx"); });
+        assert_throws(exc, function() { objStore.createIndex("idx2", "a"); });
     }
 
     open_rq.onsuccess = function() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer-when-downgrade.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer-when-downgrade.https-expected.txt
new file mode 100644
index 0000000..1a33f92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer-when-downgrade.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS Test referer header https://web-platform.test:8444/beacon/resources/ 
+FAIL Test referer header http://web-platform.test:8001/beacon/resources/ assert_true: SendBeacon Succeeded expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer-when-downgrade.https.html b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer-when-downgrade.https.html
new file mode 100644
index 0000000..c65b9fd6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer-when-downgrade.https.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon Referrer Header No Referrer When Downgrade Policy</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <meta name='referrer' content='no-referrer-when-downgrade'>
+  </head>
+  <body>
+    <script src="/common/utils.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="/beacon/headers/header-referrer.js"></script>
+    <script>
+      var testBase = get_host_info().HTTPS_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerUrl);
+      testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, "");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer.html b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer.html
new file mode 100644
index 0000000..b26db4c2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-no-referrer.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon Referrer Header No Referrer Policy</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <meta name='referrer' content='no-referrer'>
+  </head>
+  <body>
+    <script src="/common/utils.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="header-referrer.js"></script>
+    <script>
+      var testBase = RESOURCES_DIR;
+      testReferrerHeader(testBase, "");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-origin-when-cross-origin.html b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-origin-when-cross-origin.html
new file mode 100644
index 0000000..a23c021
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-origin-when-cross-origin.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon Referrer Header Origin When Cross Origin Policy</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <meta name='referrer' content='origin-when-cross-origin'>
+  </head>
+  <body>
+    <script src="/common/utils.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="header-referrer.js"></script>
+    <script>
+      var testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerUrl);
+      testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerOrigin);
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-origin.html b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-origin.html
new file mode 100644
index 0000000..c7a571e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-origin.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon Referrer Header Origin Policy</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <meta name='referrer' content='origin'>
+  </head>
+  <body>
+    <script src="/common/utils.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="header-referrer.js"></script>
+    <script>
+      var testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerOrigin);
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-same-origin-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-same-origin-expected.txt
new file mode 100644
index 0000000..ec428d1e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-same-origin-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS Test referer header /beacon/resources/ 
+FAIL Test referer header http://www1.web-platform.test:8001/beacon/resources/ assert_equals: Correct referrer header result expected "" but got "http://web-platform.test:8001/beacon/headers/header-referrer-same-origin.html"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-same-origin.html b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-same-origin.html
new file mode 100644
index 0000000..80455ab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-same-origin.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon Referrer Header Same Origin Policy</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <meta name='referrer' content='same-origin'>
+  </head>
+  <body>
+    <script src="/common/utils.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="header-referrer.js"></script>
+    <script>
+      var testBase = RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerUrl);
+      testBase = get_host_info().HTTP_REMOTE_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, "");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https-expected.txt
new file mode 100644
index 0000000..d038c8e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Test referer header https://web-platform.test:8444/beacon/resources/ assert_equals: Correct referrer header result expected "https://web-platform.test:8444/" but got "https://web-platform.test:8444/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html"
+FAIL Test referer header http://web-platform.test:8001/beacon/resources/ assert_true: SendBeacon Succeeded expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html
new file mode 100644
index 0000000..ef6a598
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon Referrer Header Strict Origin Policy</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <meta name='referrer' content='strict-origin'>
+  </head>
+  <body>
+    <script src="/common/utils.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="/beacon/headers/header-referrer.js"></script>
+    <script>
+      var testBase = get_host_info().HTTPS_ORIGIN +  RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerOrigin);
+      testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, "");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin.https-expected.txt
new file mode 100644
index 0000000..338dd5e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL Test referer header https://web-platform.test:8444/beacon/resources/ assert_equals: Correct referrer header result expected "https://web-platform.test:8444/" but got "https://web-platform.test:8444/beacon/headers/header-referrer-strict-origin.https.html"
+FAIL Test referer header http://web-platform.test:8001/beacon/resources/ assert_true: SendBeacon Succeeded expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin.https.html b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin.https.html
new file mode 100644
index 0000000..ef6a598
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-strict-origin.https.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon Referrer Header Strict Origin Policy</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <meta name='referrer' content='strict-origin'>
+  </head>
+  <body>
+    <script src="/common/utils.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="/beacon/headers/header-referrer.js"></script>
+    <script>
+      var testBase = get_host_info().HTTPS_ORIGIN +  RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerOrigin);
+      testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, "");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-unsafe-url.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-unsafe-url.https-expected.txt
new file mode 100644
index 0000000..6c07551
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-unsafe-url.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Test referer header http://web-platform.test:8001/beacon/resources/ assert_true: SendBeacon Succeeded expected true got false
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-unsafe-url.https.html b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-unsafe-url.https.html
new file mode 100644
index 0000000..9a3bccf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer-unsafe-url.https.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>SendBeacon Referrer Header Unsafe Url Policy</title>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+    <meta name='referrer' content='unsafe-url'>
+  </head>
+  <body>
+    <script src="/common/utils.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
+    <script src="/beacon/headers/header-referrer.js"></script>
+    <script>
+      var testBase = get_host_info().HTTP_ORIGIN + RESOURCES_DIR;
+      testReferrerHeader(testBase, referrerUrl);
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer.js b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer.js
new file mode 100644
index 0000000..026b091
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/headers/header-referrer.js
@@ -0,0 +1,41 @@
+var RESOURCES_DIR = "/beacon/resources/";
+
+var referrerOrigin = self.location.origin + '/';
+var referrerUrl = self.location.href;
+
+function testReferrerHeader(testBase, expectedReferrer) {
+  var id = self.token();
+  var testUrl = testBase + "inspect-header.py?header=referer&cmd=put&id=" + id;
+
+  promise_test(function(test) {
+    assert_true(navigator.sendBeacon(testUrl), "SendBeacon Succeeded");
+    return pollResult(expectedReferrer, id) .then(result => {
+      assert_equals(result, expectedReferrer, "Correct referrer header result");
+    });
+  }, "Test referer header " + testBase);
+}
+
+// SendBeacon is an asynchronous and non-blocking request to a web server.
+// We may have to create a poll loop to get result from server
+function pollResult(expectedReferrer, id) {
+  var checkUrl = RESOURCES_DIR + "inspect-header.py?header=referer&cmd=get&id=" + id;
+
+  return new Promise(resolve => {
+    function checkResult() {
+      fetch(checkUrl).then(
+        function(response) {
+          assert_equals(response.status, 200, "Inspect header response's status is 200");
+          let result = response.headers.get("x-request-referer");
+
+          if (result != undefined) {
+            resolve(result);
+          } else {
+            step_timeout(checkResult.bind(this), 100);
+          }
+        });
+    }
+
+    checkResult();
+  });
+
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/resources/inspect-header.py b/third_party/WebKit/LayoutTests/external/wpt/beacon/resources/inspect-header.py
new file mode 100644
index 0000000..e0b0e92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/resources/inspect-header.py
@@ -0,0 +1,18 @@
+def main(request, response):
+    headers = [("Content-Type", "text/plain")]
+    command = request.GET.first("cmd").lower();
+    test_id = request.GET.first("id")
+    header = request.GET.first("header")
+    if command == "put":
+        request.server.stash.put(test_id, request.headers.get(header, ""))
+
+    elif command == "get":
+        stashed_header = request.server.stash.take(test_id)
+        if stashed_header is not None:
+            headers.append(("x-request-" + header, stashed_header ))
+
+    else:
+        response.set_error(400, "Bad Command")
+        return "ERROR: Bad Command!"
+
+    return headers, ""
diff --git a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/idl-Bluetooth.html b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/idl-Bluetooth.html
index d99a473..129a10cd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/bluetooth/idl-Bluetooth.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/bluetooth/idl-Bluetooth.html
@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <title>Bluetooth interface</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 <script>
 'use strict';
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/check_stability.py b/third_party/WebKit/LayoutTests/external/wpt/check_stability.py
index e898b647..79c01de 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/check_stability.py
+++ b/third_party/WebKit/LayoutTests/external/wpt/check_stability.py
@@ -589,7 +589,7 @@
     results = handler.results
     for test_name, test in results.iteritems():
         if is_inconsistent(test["status"], iterations):
-            inconsistent.append((test_name, None, test["status"], None))
+            inconsistent.append((test_name, None, test["status"], []))
         for subtest_name, subtest in test["subtests"].iteritems():
             if is_inconsistent(subtest["status"], iterations):
                 inconsistent.append((test_name, subtest_name, subtest["status"], subtest["messages"]))
@@ -709,7 +709,7 @@
                         action="store",
                         # Travis docs say do not depend on USER env variable.
                         # This is a workaround to get what should be the same value
-                        default=os.environ.get("TRAVIS_REPO_SLUG").split('/')[0],
+                        default=os.environ.get("TRAVIS_REPO_SLUG", "w3c").split('/')[0],
                         help="Travis user name")
     parser.add_argument("--output-bytes",
                         action="store",
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/cubic-bezier-timing-functions-output-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/cubic-bezier-timing-functions-output-expected.txt
new file mode 100644
index 0000000..230202dc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/cubic-bezier-timing-functions-output-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+FAIL cubic-bezier easing with input progress greater than 1 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
+FAIL cubic-bezier easing with input progress greater than 1 and where the tangent on the upper boundary is infinity Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
+FAIL cubic-bezier easing with input progress less than 0 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
+FAIL cubic-bezier easing with input progress less than 0 and where the tangent on the lower boundary is infinity Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/cubic-bezier-timing-functions-output.html b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/cubic-bezier-timing-functions-output.html
new file mode 100644
index 0000000..3068e8c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/cubic-bezier-timing-functions-output.html
@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="assert"
+content="This test checks the output of Cubic Bézier functions" />
+<title>Tests for the output of Cubic Bézier timing functions</title>
+<link rel="help"
+href="https://drafts.csswg.org/css-timing/#cubic-bezier-timing-functions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+function assert_style_left_at(animation, time, easingFunction) {
+  animation.currentTime = time;
+  var portion = time / animation.effect.timing.duration;
+  assert_approx_equals(pxToNum(getComputedStyle(animation.effect.target).left),
+                       easingFunction(portion) * 100,
+                       0.01,
+                       'The left of the animation should be approximately ' +
+                       easingFunction(portion) * 100 + ' at ' + time + 'ms');
+}
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate(
+    // http://cubic-bezier.com/#.5,1,.5,0
+    [ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' },
+      { left: '100px' } ],
+      { duration: 1000,
+        fill: 'forwards',
+        easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+  var keyframeEasing = function(x) {
+    assert_greater_than_equal(x, 0.0,
+      'This function should be called in [0, 1.0] range');
+    assert_less_than_equal(x, 1.0,
+      'This function should be called in [0, 1.0] range');
+    return cubicBezier(0.5, 1, 0.5, 0)(x);
+  }
+  var keyframeEasingExtrapolated = function(x) {
+    assert_greater_than(x, 1.0,
+      'This function should be called in (1.0, infinity) range');
+    // p3x + (p2y - p3y) / (p2x - p3x) * (x - p3x)
+    return 1.0 + (0 - 1) / (0.5 - 1) * (x - 1.0);
+  }
+  var effectEasing = function(x) {
+    return cubicBezier(0, 1.5, 1, 1.5)(x);
+  }
+
+  // The effect-easing produces values greater than 1 in (0.23368794, 1)
+  assert_style_left_at(anim, 0, function(x) {
+    return keyframeEasing(effectEasing(x));
+  });
+  assert_style_left_at(anim, 230, function(x) {
+    return keyframeEasing(effectEasing(x));
+  });
+  assert_style_left_at(anim, 240, function(x) {
+    return keyframeEasingExtrapolated(effectEasing(x));
+  });
+  // Near the extreme point of the effect-easing function
+  assert_style_left_at(anim, 700, function(x) {
+    return keyframeEasingExtrapolated(effectEasing(x));
+  });
+  assert_style_left_at(anim, 990, function(x) {
+    return keyframeEasingExtrapolated(effectEasing(x));
+  });
+  assert_style_left_at(anim, 1000, function(x) {
+    return keyframeEasing(effectEasing(x));
+  });
+}, 'cubic-bezier easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate(
+    // http://cubic-bezier.com/#0,1.5,1,1.5
+    [ { left: '0px', easing: 'cubic-bezier(0, 1.5, 1, 1.5)' },
+      { left: '100px' } ],
+      { duration: 1000,
+        fill: 'forwards',
+        easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+  var easing = function(x) {
+    assert_greater_than_equal(x, 0.0,
+      'This function should be called in [0, 1.0] range');
+    assert_less_than_equal(x, 1.0,
+      'This function should be called in [0, 1.0] range');
+    return cubicBezier(0, 1.5, 1, 1.5)(x);
+  }
+  var easingExtrapolated = function(x) {
+    assert_greater_than(x, 1.0,
+      'This function should be called in negative range');
+    // For cubic-bezier(0, 1.5, 1, 1.5), the tangent at the
+    // endpoint (x = 1.0) is infinity so we should just return 1.0.
+    return 1.0;
+  }
+
+  // The effect-easing produces values greater than 1 in (0.23368794, 1)
+  assert_style_left_at(anim, 0, function(x) {
+    return easing(easing(x))
+  });
+  assert_style_left_at(anim, 230, function(x) {
+    return easing(easing(x))
+  });
+  assert_style_left_at(anim, 240, function(x) {
+    return easingExtrapolated(easing(x));
+  });
+  // Near the extreme point of the effect-easing function
+  assert_style_left_at(anim, 700, function(x) {
+    return easingExtrapolated(easing(x));
+  });
+  assert_style_left_at(anim, 990, function(x) {
+    return easingExtrapolated(easing(x));
+  });
+  assert_style_left_at(anim, 1000, function(x) {
+    return easing(easing(x))
+  });
+}, 'cubic-bezier easing with input progress greater than 1 and where the ' +
+   'tangent on the upper boundary is infinity');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate(
+    // http://cubic-bezier.com/#.5,1,.5,0
+    [ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' },
+      { left: '100px' } ],
+      { duration: 1000,
+        fill: 'forwards',
+        easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+  var keyframeEasing = function(x) {
+    assert_greater_than_equal(x, 0.0,
+      'This function should be called in [0, 1.0] range');
+    assert_less_than_equal(x, 1.0,
+      'This function should be called in [0, 1.0] range');
+    return cubicBezier(0.5, 1, 0.5, 0)(x);
+  }
+  var keyframeEasingExtrapolated = function(x) {
+    assert_less_than(x, 0.0,
+      'This function should be called in negative range');
+    // p0x + (p1y - p0y) / (p1x - p0x) * (x - p0x)
+    return (1 / 0.5) * x;
+  }
+  var effectEasing = function(x) {
+    return cubicBezier(0, -0.5, 1, -0.5)(x);
+  }
+
+  // The effect-easing produces negative values in (0, 0.766312060)
+  assert_style_left_at(anim, 0, function(x) {
+    return keyframeEasing(effectEasing(x));
+  });
+  assert_style_left_at(anim, 10, function(x) {
+    return keyframeEasingExtrapolated(effectEasing(x));
+  });
+  // Near the extreme point of the effect-easing function
+  assert_style_left_at(anim, 300, function(x) {
+    return keyframeEasingExtrapolated(effectEasing(x));
+  });
+  assert_style_left_at(anim, 750, function(x) {
+    return keyframeEasingExtrapolated(effectEasing(x));
+  });
+  assert_style_left_at(anim, 770, function(x) {
+    return keyframeEasing(effectEasing(x));
+  });
+  assert_style_left_at(anim, 1000, function(x) {
+    return keyframeEasing(effectEasing(x));
+  });
+}, 'cubic-bezier easing with input progress less than 0');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate(
+    // http://cubic-bezier.com/#0,-0.5,1,-0.5
+    [ { left: '0px', easing: 'cubic-bezier(0, -0.5, 1, -0.5)' },
+      { left: '100px' } ],
+      { duration: 1000,
+        fill: 'forwards',
+        easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+  var easing = function(x) {
+    assert_greater_than_equal(x, 0.0,
+      'This function should be called in [0, 1.0] range');
+    assert_less_than_equal(x, 1.0,
+      'This function should be called in [0, 1.0] range');
+    return cubicBezier(0, -0.5, 1, -0.5)(x);
+  }
+  var easingExtrapolated = function(x) {
+    assert_less_than(x, 0.0,
+      'This function should be called in negative range');
+    // For cubic-bezier(0, -0.5, 1, -0.5), the tangent at the
+    // endpoint (x = 0.0) is infinity so we should just return 0.0.
+    return 0.0;
+  }
+
+  // The effect-easing produces negative values in (0, 0.766312060)
+  assert_style_left_at(anim, 0, function(x) {
+    return easing(easing(x))
+  });
+  assert_style_left_at(anim, 10, function(x) {
+    return easingExtrapolated(easing(x));
+  });
+  // Near the extreme point of the effect-easing function
+  assert_style_left_at(anim, 300, function(x) {
+    return easingExtrapolated(easing(x));
+  });
+  assert_style_left_at(anim, 750, function(x) {
+    return easingExtrapolated(easing(x));
+  });
+  assert_style_left_at(anim, 770, function(x) {
+    return easing(easing(x))
+  });
+  assert_style_left_at(anim, 1000, function(x) {
+    return easing(easing(x))
+  });
+}, 'cubic-bezier easing with input progress less than 0 and where the ' +
+   'tangent on the lower boundary is infinity');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-output-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-output-expected.txt
new file mode 100644
index 0000000..0ddd60ff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-output-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+FAIL For an input progress of 0.0, the output of a frames timing function is the first frame assert_equals: expected "0px" but got "auto"
+FAIL At a frame boundary, the output of a frames timing function is the next frame assert_equals: expected "0px" but got "auto"
+FAIL For an input progress of 1.0, the output of a frames timing function is the final frame assert_equals: expected "100px" but got "auto"
+FAIL The number of frames is correctly reflected in the frames timing function output assert_equals: expected "0px" but got "auto"
+FAIL The number of frames is correctly reflected in the frames timing function output on CSS Transitions assert_equals: expected "0px" but got "100px"
+FAIL frames easing with input progress greater than 1 Failed to execute 'animate' on 'Element': 'frames(2)' is not a valid value for easing
+FAIL frames easing with input progress greater than 1.5 Failed to execute 'animate' on 'Element': 'frames(2)' is not a valid value for easing
+FAIL frames easing with input progress less than 0 Failed to execute 'animate' on 'Element': 'frames(2)' is not a valid value for easing
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-output.html b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-output.html
new file mode 100644
index 0000000..40e03286
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-output.html
@@ -0,0 +1,152 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="assert"
+content="This test checks the output of frame timing functions with different frame numbers" />
+<title>Frames timing function output tests</title>
+<link rel="help"
+href="https://drafts.csswg.org/css-timing/#frames-timing-functions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="testcommon.js"></script>
+<style>
+@keyframes anim {
+  from { left: 0px; }
+  to   { left: 100px; }
+}
+</style>
+<body>
+<div id="log"></div>
+<script>
+"use strict";
+
+test(function(t) {
+  const div = createDiv(t);
+  div.style.animation = 'anim 10s frames(2) forwards';
+  assert_equals(getComputedStyle(div).left, '0px');
+}, 'For an input progress of 0.0, the output of a frames timing function is ' +
+   'the first frame');
+
+test(function(t) {
+  const div = createDiv(t);
+  div.style.animation = 'anim 10s frames(2) forwards';
+
+  div.style.animationDelay = '-4999ms';
+  assert_equals(getComputedStyle(div).left, '0px');
+  div.style.animationDelay = '-5000ms';
+  assert_equals(getComputedStyle(div).left, '100px');
+}, 'At a frame boundary, the output of a frames timing function is the next ' +
+   'frame');
+
+test(function(t) {
+  const div = createDiv(t);
+  div.style.animation = 'anim 10s frames(2) forwards';
+
+  div.style.animationDelay = '-10s';
+  assert_equals(getComputedStyle(div).left, '100px');
+}, 'For an input progress of 1.0, the output of a frames timing function is ' +
+   'the final frame');
+
+test(function(t) {
+  const div = createDiv(t);
+  div.style.animation = 'anim 11s frames(11) forwards';
+
+  // We have 11 frames in 11s, so the first step happens at 1.0.
+  div.style.animationDelay = '-999ms';
+  assert_equals(getComputedStyle(div).left, '0px');
+  div.style.animationDelay = '-1000ms';
+  assert_equals(getComputedStyle(div).left, '10px');
+}, 'The number of frames is correctly reflected in the frames timing ' +
+   'function output');
+
+test(function(t) {
+  const div = createDiv(t);
+  div.style.transition = 'left 11s frames(11)';
+
+  // We have 11 frames in 11s, so the first step happens at 1.0.
+  div.style.left = '0px';
+  div.style.transitionDelay = '-999ms';
+  getComputedStyle(div).left;
+  div.style.left = '100px';
+  assert_equals(getComputedStyle(div).left, '0px');
+
+  div.style.left = '0px';
+  div.style.transitionDelay = '-1000ms';
+  getComputedStyle(div).left;
+  div.style.left = '100px';
+  assert_equals(getComputedStyle(div).left, '10px');
+}, 'The number of frames is correctly reflected in the frames timing ' +
+   'function output on CSS Transitions');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'frames(2)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values between 0.5 and 1 in
+  // (~0.0442, 0.23368), and values between 1 and 2 in (0.23368794, 1).
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 45;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'frames easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'frames(2)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier funciton produces values:
+  // Input           ->  Output
+  // 0.0                 0.0
+  // 0.114 ~ 0.245       1.5~2.0, so frames(2) is 3.0
+  // 0.245 ~ 0.6         2.0~2.4, so frames(2) is 4.0
+  // 0.6   ~ 0.882       2.4~2.0, so frames(2) is 4.0
+  // 0.882 ~ 0.976       2.0~1.5, so frames(2) is 3.0
+  // 1.0                 1.0
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '300px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '400px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '300px');
+}, 'frames easing with input progress greater than 1.5');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'frames(2)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -0.5)
+  // in (0, 0.766312060).
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 750;
+  assert_equals(getComputedStyle(target).left, '-100px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'frames easing with input progress less than 0');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-syntax-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-syntax-expected.txt
new file mode 100644
index 0000000..6b236698
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-syntax-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS The number of frames must be a positive integer greater than 1, or we fallback to the previously-set easing 
+FAIL The serialization of frames is 'frames(n)', n is the number of frames assert_equals: expected "frames(2)" but got "ease"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-syntax.html b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-syntax.html
new file mode 100644
index 0000000..1616bcff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/frames-timing-functions-syntax.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="assert"
+content="This test checks the syntax output of frame timing functions" />
+<title>Frames timing function syntax tests</title>
+<link rel="help"
+href="https://drafts.csswg.org/css-timing/#frames-timing-functions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+"use strict";
+
+test(function(t) {
+  const div = createDiv(t);
+  div.style.animation = 'abc 1s ease-in';
+  div.style.animationTimingFunction = 'frames(1)';
+  assert_equals(getComputedStyle(div).animationTimingFunction, 'ease-in');
+}, 'The number of frames must be a positive integer greater than 1, or we ' +
+   'fallback to the previously-set easing');
+
+test(function(t) {
+  const div = createDiv(t);
+  div.style.animation = 'abc 1s frames(  2 )';
+  assert_equals(getComputedStyle(div).animationTimingFunction, 'frames(2)');
+}, 'The serialization of frames is \'frames(n)\', n is the number of frames');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/step-timing-functions-output-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/step-timing-functions-output-expected.txt
new file mode 100644
index 0000000..24f63f7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/step-timing-functions-output-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL step-start easing with input progress greater than 1 assert_equals: expected "200px" but got "100px"
+PASS step-end easing with input progress greater than 1 
+FAIL step-end easing with input progress greater than 2 assert_equals: expected "200px" but got "100px"
+PASS step-start easing with input progress less than 0 
+FAIL step-start easing with input progress less than -1 assert_equals: expected "-100px" but got "0px"
+FAIL step-end easing with input progress less than 0 assert_equals: expected "-100px" but got "0px"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/step-timing-functions-output.html b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/step-timing-functions-output.html
new file mode 100644
index 0000000..9a2aa507c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/step-timing-functions-output.html
@@ -0,0 +1,141 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="assert"
+content="This test checks the output of step timing functions" />
+<title>Tests for the output of step timing functions</title>
+<link rel="help"
+href="https://drafts.csswg.org/css-timing/#step-timing-functions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-start' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values greater than 1 (but always less than 2)
+  // in (0.23368794, 1)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-start easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values greater than 1 (but always less than 2)
+  // in (0.23368794, 1)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-end easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier function produces values greater than 2 (but always less than 3)
+  // in the range (~0.245, ~0.882)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-end easing with input progress greater than 2');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-start' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -1)
+  // in (0, 0.766312060)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 750;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-start easing with input progress less than 0');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-start' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -2, 1, -2)' });
+
+  // The bezier function produces values less than -1 (but always greater than
+  // -2) in the range (~0.118, ~0.755)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 100;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '-100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-start easing with input progress less than -1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -1)
+  // in (0, 0.766312060)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 750;
+  assert_equals(getComputedStyle(target).left, '-100px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-end easing with input progress less than 0');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/testcommon.js
new file mode 100644
index 0000000..9fd25b8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css-timing-1/testcommon.js
@@ -0,0 +1,65 @@
+'use strict';
+
+// Creates a <div> element, appends it to the document body and
+// removes the created element during test cleanup.
+function createDiv(test, doc) {
+  return createElement(test, 'div', doc);
+}
+
+// Creates an element with the given |tagName|, appends it to the document body
+// and removes the created element during test cleanup.
+// If |tagName| is null or undefined, creates a <div> element.
+function createElement(test, tagName, doc) {
+  if (!doc) {
+    doc = document;
+  }
+  var element = doc.createElement(tagName || 'div');
+  doc.body.appendChild(element);
+  test.add_cleanup(function() {
+    element.remove();
+  });
+  return element;
+}
+
+// Convert px unit value to a Number
+function pxToNum(str) {
+  return Number(String(str).match(/^(-?[\d.]+)px$/)[1]);
+}
+
+// Cubic bezier with control points (0, 0), (x1, y1), (x2, y2), and (1, 1).
+function cubicBezier(x1, y1, x2, y2) {
+  function xForT(t) {
+    var omt = 1-t;
+    return 3 * omt * omt * t * x1 + 3 * omt * t * t * x2 + t * t * t;
+  }
+
+  function yForT(t) {
+    var omt = 1-t;
+    return 3 * omt * omt * t * y1 + 3 * omt * t * t * y2 + t * t * t;
+  }
+
+  function tForX(x) {
+    // Binary subdivision.
+    var mint = 0, maxt = 1;
+    for (var i = 0; i < 30; ++i) {
+      var guesst = (mint + maxt) / 2;
+      var guessx = xForT(guesst);
+      if (x < guessx) {
+        maxt = guesst;
+      } else {
+        mint = guesst;
+      }
+    }
+    return (mint + maxt) / 2;
+  }
+
+  return function bezierClosure(x) {
+    if (x == 0) {
+      return 0;
+    }
+    if (x == 1) {
+      return 1;
+    }
+    return yForT(tForX(x));
+  }
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-align-3/distribution-values/space-evenly-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-align-3/distribution-values/space-evenly-001.html
new file mode 100644
index 0000000..74cf543
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-align-3/distribution-values/space-evenly-001.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html lang=en>
+  <meta charset=utf-8>
+  <title>CSS Box Alignment: space-evenly &amp; flexbox with single item</title>
+  <link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net">
+  <meta name=flags content="">
+  <meta name=assert content="justify-content: space-evenly with flexbox and a single item must center it">
+  <link rel="match" href="../../reference/ref-filled-green-100px-square.xht">
+  <link rel=help href="https://drafts.csswg.org/css-align/#distribution-values">
+  <link rel=help href="https://drafts.csswg.org/css-align/#fallback-alignment">
+  <link rel=help href="https://drafts.csswg.org/css-flexbox-1/#justify-content-property">
+<style>
+.red {
+	position: absolute;
+	z-index: -1;
+	width: 100px;
+	height: 100px;
+	background: red;
+}
+.container {
+	margin-left: -100px;
+	width: 300px;
+	display: flex;
+	justify-content: space-evenly;
+}
+.container div {
+	width: 100px;
+	height: 100px;
+	background: green;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div class=red></div>
+<div class=container><div></div></div>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-basic-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-basic-001.html
new file mode 100644
index 0000000..19727e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-basic-001.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step basic layout</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-rhythm-1/#line-height-step">
+<link rel="match" href="reference/line-height-step-basic-001.html">
+<meta name="assert" content="This test asserts the line-height-step property rounds up line box height.">
+<meta name="flags" content="ahem">
+<style>
+div {
+  font-family: Ahem;
+  font-size: 40px;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+  width: 5em;
+}
+.test {
+  line-height: 40px;
+  line-height-step: 60px;
+}
+.ref {
+  line-height: 60px;
+}
+</style>
+<p class="instructions">Test passes if left and right are the same.
+<div class="ref">
+  <div>XXXXX</div>
+  <div>XXXXX XXXXX XXXXX</div>
+  <div><br>X<br>X</div>
+</div>
+<div class="test">
+  <div>XXXXX</div>
+  <div>XXXXX XXXXX XXXXX</div>
+  <div><br>X<br>X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-boundary-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-boundary-001.html
new file mode 100644
index 0000000..50681bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-boundary-001.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step boundary test</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-rhythm-1/#line-height-step">
+<link rel="match" href="reference/line-height-step-boundary-001.html">
+<meta name="assert" content="This test asserts the line-height-step property rounds up line box height.">
+<meta name="flags" content="ahem">
+<style>
+div {
+  font-family: Ahem;
+  font-size: 30px;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+  width: 5em;
+}
+.test {
+  line-height-step: 40px;
+}
+</style>
+<p class="instructions">Test passes if left and right are the same.
+<div class="ref">
+  <div style="line-height: 40px">XXXXX</div>
+  <div style="line-height: 40px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 120px">XXXXX</div>
+</div>
+<div class="test">
+  <div style="line-height: 39px">XXXXX</div>
+  <div style="line-height: 40px">XXXXX</div>
+  <div style="line-height: 41px">XXXXX</div>
+  <div style="line-height: 79px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 81px">XXXXX</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-dynamic-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-dynamic-001.html
new file mode 100644
index 0000000..d6f7bd9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-dynamic-001.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step dynamic change</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-rhythm-1/#line-height-step">
+<meta name="assert" content="This test asserts changing the line-height-step property takes effects.">
+<meta name="flags" content="dom">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+div {
+  font-size: 20px;
+  line-height: 1;
+}
+</style>
+<div id="log"></div>
+<div id="target">X</div>
+<div id="next">X</div>
+<script>
+runTests();
+function runTests() {
+  var before = next.offsetTop;
+  target.style.lineHeightStep = "40px";
+  var after = next.offsetTop;
+  forceRelayout(document.documentElement);
+  var afterRelayout = next.offsetTop;
+
+  test(function () {
+    assert_not_equals(after, before);
+  }, "Height must change when line-height-step changes");
+  test(function () {
+    assert_equals(after, afterRelayout);
+  }, "Height must not change after relayout");
+}
+
+function forceRelayout(element) {
+  var saved = element.style.display;
+  element.style.display = "none";
+  element.offsetTop;
+  element.style.display = saved;
+  element.offsetTop;
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-parsing-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-parsing-001.html
new file mode 100644
index 0000000..3febf057
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-parsing-001.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: parsing line-height-step</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-rhythm-1/#line-height-step">
+<meta name="assert" content="This test asserts the parsing and getComputedStyle works correctly for the line-height-step property.">
+<meta name="flags" content="dom">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div title="initial value should be '0px'" data-expected="0px"></div>
+
+<div style="line-height-step: 20px" data-expected="20px">
+  <div title="line-height-step should inherit" data-expected="20px"></div>
+  <div style="line-height-step: initial" data-expected="0px"></div>
+
+  <div style="line-height-step: 40px" data-expected="40px"></div>
+
+  <div title="'0' should be a valid length" style="line-height-step: 0" data-expected="0px"></div>
+
+  <div title="Interger should be invalid" style="line-height-step: 1" data-expected="20px"></div>
+  <div title="Negative length should be invalid" style="line-height-step: -1px" data-expected="20px"></div>
+</div>
+
+<div id="pt" style="line-height-step: 40pt"></div>
+
+<script>
+Array.prototype.forEach.call(document.querySelectorAll("[data-expected]"), function (element) {
+  var expected = element.dataset.expected;
+  test(function () {
+    var actual = getComputedStyle(element).lineHeightStep;
+    assert_equals(actual, expected);
+  }, element.title || "'" + element.getAttribute("style") + "' should compute to '" + expected + "'");
+});
+
+test(function () {
+  assert_equals(getComputedStyle(document.getElementById("pt")).lineHeightStep.slice(-2), "px");
+}, "Computed value should be the absolute length");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-ruby-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-ruby-001.html
new file mode 100644
index 0000000..f79f13b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-ruby-001.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step and ruby</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-rhythm-1/#line-height-step">
+<link rel="match" href="reference/line-height-step-ruby-001.html">
+<meta name="assert" content="This test asserts the line-height-step property and ruby.">
+<meta name="flags" content="ahem">
+<style>
+div {
+  font-family: Ahem;
+  font-size: 40px;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+  width: 5em;
+}
+.test {
+  line-height: 40px;
+  line-height-step: 120px;
+}
+.ref {
+  line-height: 120px;
+}
+</style>
+<body>
+<p class="instructions">Test passes if left and right are the same.
+<div class="ref">
+  <div>X<ruby>XX<rt>XX</rt></ruby>X</div>
+</div>
+<div class="test">
+  <div>X<ruby>XX<rt>XX</rt></ruby>X</div>
+</div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-valign-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-valign-001.html
new file mode 100644
index 0000000..ffdc462
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-valign-001.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step vertical-align test</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-rhythm-1/#line-height-step">
+<link rel="match" href="reference/line-height-step-valign-001.html">
+<meta name="assert" content="This test asserts the vertical-align property with the line-height-step property.">
+<meta name="flags" content="ahem">
+<style>
+div {
+  font-family: Ahem;
+  font-size: 40px;
+}
+.test {
+  line-height-step: 80px;
+  line-height: 1;
+}
+.ref {
+  line-height: 1;
+}
+.adjuster {
+  line-height: 80px;
+  color: transparent;
+}
+.top {
+  vertical-align: top;
+}
+.text-top {
+  vertical-align: text-top;
+}
+.text-bottom {
+  vertical-align: text-bottom;
+}
+.bottom {
+  vertical-align: bottom;
+}
+</style>
+<p class="instructions">Test passes if two lines are the same.
+<div class="ref">
+  <div>XX<span class="top">X</span><span class="text-top">X</span><span class="text-bottom">X</span><span class="bottom">X</span><span class="adjuster">X</span></div>
+</div>
+<div class="test">
+  <div>XX<span class="top">X</span><span class="text-top">X</span><span class="text-bottom">X</span><span class="bottom">X</span></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-writing-mode-vrl-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-writing-mode-vrl-001.html
new file mode 100644
index 0000000..d74ceab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-writing-mode-vrl-001.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step in vertical-rl</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-rhythm-1/#line-height-step">
+<link rel="match" href="reference/line-height-step-writing-mode-vrl-001.html">
+<meta name="assert" content="This test asserts the line-height-step property in vertical-rl writing mode.">
+<meta name="flags" content="ahem">
+<style>
+.container {
+  font-family: Ahem;
+  font-size: 40px;
+  writing-mode: vertical-rl;
+  width: 5em;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+}
+.test {
+  line-height: 40px;
+  line-height-step: 120px;
+}
+.ref {
+  line-height: 120px;
+}
+</style>
+<body>
+<p class="instructions">Test passes if top and bottom are the same.
+<div class="container">
+  <div class="ref">
+    <div>XXXXX</div>
+  </div>
+  <div class="test">
+    <div>XXXXX</div>
+  </div>
+</div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-writing-mode-vrl-ruby-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-writing-mode-vrl-ruby-001.html
new file mode 100644
index 0000000..a071d0d4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/line-height-step-writing-mode-vrl-ruby-001.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step with ruby in vertical-rl</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-rhythm-1/#line-height-step">
+<link rel="match" href="reference/line-height-step-writing-mode-vrl-ruby-001.html">
+<meta name="assert" content="This test asserts the line-height-step property with ruby in vertical-rl writing mode.">
+<meta name="flags" content="ahem">
+<style>
+.container {
+  font-family: Ahem;
+  font-size: 40px;
+  writing-mode: vertical-rl;
+  width: 5em;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+}
+.test {
+  line-height: 40px;
+  line-height-step: 120px;
+}
+.ref {
+  line-height: 120px;
+}
+</style>
+<body>
+<p class="instructions">Test passes if top and bottom are the same.
+<div class="container">
+  <div class="ref">
+    <div>X<ruby>XX<rt>XX</rt></ruby>X</div>
+  </div>
+  <div class="test">
+    <div>X<ruby>XX<rt>XX</rt></ruby>X</div>
+  </div>
+</div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-basic-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-basic-001.html
new file mode 100644
index 0000000..e277021
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-basic-001.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step basic layout reference</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<style>
+div {
+  font-family: Ahem;
+  font-size: 40px;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+  width: 5em;
+}
+.ref {
+  line-height: 60px;
+}
+</style>
+<p class="instructions">Test passes if left and right are the same.
+<div class="ref">
+  <div>XXXXX</div>
+  <div>XXXXX XXXXX XXXXX</div>
+  <div><br>X<br>X</div>
+</div>
+<div class="ref">
+  <div>XXXXX</div>
+  <div>XXXXX XXXXX XXXXX</div>
+  <div><br>X<br>X</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-boundary-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-boundary-001.html
new file mode 100644
index 0000000..17e7515
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-boundary-001.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step boundary test</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<style>
+div {
+  font-family: Ahem;
+  font-size: 30px;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+  width: 5em;
+}
+</style>
+<p class="instructions">Test passes if left and right are the same.
+<div class="ref">
+  <div style="line-height: 40px">XXXXX</div>
+  <div style="line-height: 40px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 120px">XXXXX</div>
+</div>
+<div class="ref">
+  <div style="line-height: 40px">XXXXX</div>
+  <div style="line-height: 40px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 80px">XXXXX</div>
+  <div style="line-height: 120px">XXXXX</div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-ruby-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-ruby-001.html
new file mode 100644
index 0000000..a358c1d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-ruby-001.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step and ruby</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<style>
+div {
+  font-family: Ahem;
+  font-size: 40px;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+  width: 5em;
+}
+.ref {
+  line-height: 120px;
+}
+</style>
+<body>
+<p class="instructions">Test passes if left and right are the same.
+<div class="ref">
+  <div>X<ruby>XX<rt>XX</rt></ruby>X</div>
+</div>
+<div class="ref">
+  <div>X<ruby>XX<rt>XX</rt></ruby>X</div>
+</div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-valign-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-valign-001.html
new file mode 100644
index 0000000..4925fbc0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-valign-001.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step vertical-align test</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<style>
+div {
+  font-family: Ahem;
+  font-size: 40px;
+}
+.ref {
+  line-height: 1;
+}
+.adjuster {
+  line-height: 80px;
+  color: transparent;
+}
+.top {
+  vertical-align: top;
+}
+.text-top {
+  vertical-align: text-top;
+}
+.text-bottom {
+  vertical-align: text-bottom;
+}
+.bottom {
+  vertical-align: bottom;
+}
+</style>
+<p class="instructions">Test passes if two lines are the same.
+<div class="ref">
+  <div>XX<span class="top">X</span><span class="text-top">X</span><span class="text-bottom">X</span><span class="bottom">X</span><span class="adjuster">X</span></div>
+</div>
+<div class="ref">
+  <div>XX<span class="top">X</span><span class="text-top">X</span><span class="text-bottom">X</span><span class="bottom">X</span><span class="adjuster">X</span></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-001.html
new file mode 100644
index 0000000..11b7250
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-001.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step in vertical-rl</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<style>
+.container {
+  font-family: Ahem;
+  font-size: 40px;
+  writing-mode: vertical-rl;
+  width: 5em;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+}
+.ref {
+  line-height: 120px;
+}
+</style>
+<body>
+<p class="instructions">Test passes if top and bottom are the same.
+<div class="container">
+  <div class="ref">
+    <div>XXXXX</div>
+  </div>
+  <div class="ref">
+    <div>XXXXX</div>
+  </div>
+</div>
+</body>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-ruby-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-ruby-001.html
new file mode 100644
index 0000000..bcf4951
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-rhythm-1/reference/line-height-step-writing-mode-vrl-ruby-001.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>CSS Rhythmic Sizing: line-height-step with ruby in vertical-rl</title>
+<link rel="author" title="Koji Ishii" href="mailto:kojiishi@gmail.com">
+<style>
+.container {
+  font-family: Ahem;
+  font-size: 40px;
+  writing-mode: vertical-rl;
+  width: 5em;
+}
+.test, .ref {
+  display: inline-block;
+  vertical-align: top;
+}
+.ref {
+  line-height: 120px;
+}
+</style>
+<body>
+<p class="instructions">Test passes if top and bottom are the same.
+<div class="container">
+  <div class="ref">
+    <div>X<ruby>XX<rt>XX</rt></ruby>X</div>
+  </div>
+  <div class="ref">
+    <div>X<ruby>XX<rt>XX</rt></ruby>X</div>
+  </div>
+</div>
+</body>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-down-012.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-down-012.html
index 31354810..3ee17e0a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-down-012.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/nav-down-012.html
@@ -9,7 +9,7 @@
     <p>First, use directional navigation to navigate the focus to the "START" link below.</p>
     <!-- In Opera 12.16, directional navigation may be done using Shift+<arrow key>.
          In the SmartTV emulator, use the keypad in the GUI. -->
-    <p>Test passes if navigating up once moves the focus to the "FINISH" link.</p>
+    <p>Test passes if navigating down once moves the focus to the "FINISH" link.</p>
 
     <p><a href="" id="finish">ignore</a></p>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/support/nav-down-012-frame.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/support/nav-down-012-frame.html
index 80596ef..6065856 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/support/nav-down-012-frame.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui-3/support/nav-down-012-frame.html
@@ -4,7 +4,7 @@
 <link rel="author" title="Daniel Glazman" href="mailto:d.glazman@partner.samsung.com">
 <style>
     #start {
-        nav-down: #finish frame;
+        nav-down: #finish "frame";
     }
 </style>
 <body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/support/mplus-1p-regular.ttf b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/support/mplus-1p-regular.ttf
deleted file mode 100644
index d7adacb..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/support/mplus-1p-regular.ttf
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/text-orientation-mixed-vrl-002.xht b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/text-orientation-mixed-vrl-002.xht
index b489e74..c8f1021 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/text-orientation-mixed-vrl-002.xht
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes-3/text-orientation-mixed-vrl-002.xht
@@ -14,9 +14,6 @@
 					font-family: "mplus-1p-regular";
 					src: url("support/mplus-1p-regular.woff") format("woff");
 					/* filesize: 803300 bytes (784.5 KBytes) */
-					/*
-					mplus-1p-regular.ttf can be downloaded at, from [TBD later]
-					*/
 				}
 
 			div
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-1/medialist-interfaces-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-1/medialist-interfaces-002.html
index 8cce5948..d3dfff8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-1/medialist-interfaces-002.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-1/medialist-interfaces-002.html
@@ -4,7 +4,7 @@
   <title>CSS Test: CSSOM MediaList Interfaces</title>
   <link rel="author" title="Chapman Shoop" href="mailto:chapman.shoop@gmail.com">
   <link rel="reviewer" title="Ms2ger" href="mailto:ms2ger@gmail.com"> <!-- 2012-06-17 -->
-  <link rel="help" href="http://www.w3.org/TR/cssom-1/#the-medialist-interface">
+  <link rel="help" href="https://drafts.csswg.org/cssom/#the-medialist-interface">
   <meta name="flags" content="dom">
   <meta name="assert" content="MediaList object has deleteMedium method and it functions properly.">
   <script src="/resources/testharness.js" type="text/javascript"></script>
@@ -44,7 +44,7 @@
 
     test(function() {
       media_list = setup();
-      assert_throws(null, function() { media_list.deleteMedium(); });
+      assert_throws(new TypeError, function() { media_list.deleteMedium(); });
     }, "deleteMedium_called_without_argument",
     { assert: "MediaList.deleteMedium called without argument throws error." });
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view-1/window-screen-height-mutation-throws.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view-1/window-screen-height-mutation-throws.html
deleted file mode 100644
index b1097d2f..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view-1/window-screen-height-mutation-throws.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>CSSOM View - 4.2 - screen.height mutation throws exception</title>
-    <link rel="author" title="Neils Christoffersen" href="mailto:neils.christoffersen@gmail.com">
-    <link rel="help" href="http://www.w3.org/TR/cssom-view/#the-screen-interface">
-    <meta name="flags" content="dom">
-    <meta name="assert" content="screen.height mutation throws exception">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-</head>
-<body>
-    <div id="myDiv"></div>
-    <div id="log"></div>
-    <script>
-		test(function() {
-			assert_throws(null, function() {
-				window.screen.height = 0
-			}), "chaning window.screen.height should throw exception"
-		}, "mutation exception test");
-    </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view-1/window-screen-width-mutation-throws.html b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view-1/window-screen-width-mutation-throws.html
deleted file mode 100644
index 1b0b516b..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view-1/window-screen-width-mutation-throws.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <title>CSSOM View - 4.2 - screen.width mutation throws exception</title>
-    <link rel="author" title="Neils Christoffersen" href="mailto:neils.christoffersen@gmail.com">
-    <link rel="help" href="http://www.w3.org/TR/cssom-view/#the-screen-interface">
-    <meta name="flags" content="dom">
-    <meta name="assert" content="screen.width mutation throws exception">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-</head>
-<body>
-    <div id="myDiv"></div>
-    <div id="log"></div>
-    <script>
-		test(function() {
-			assert_throws(null, function() {
-				window.screen.width = 0
-			}), "chaning window.screen.width should throw exception"
-		}, "mutation exception test");
-    </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-001-ref.html
index 841a544..2913775 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-001-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-001-ref.html
@@ -9,6 +9,8 @@
   border: solid 15px green;
 }
 </style>
-<p>Test passes if, when the element below is focused, it is surrounded by a thick green border. There must be no red or blue once it is focused.</p>
+<p>Test passes if, when the element below is focused,
+it is surrounded by a thick green border.
+There must be no red or blue once it is focused.</p>
 <div>Focus this element</div>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-001.html
index d37e5767..b367aa68 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-001.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-001.html
@@ -26,7 +26,9 @@
 border-color: green;
 }
 </style>
-<p>Test passes if, when the element below is focused, it is surrounded by a thick green border. There must be no red or blue once it is focused.</p>
+<p>Test passes if, when the element below is focused,
+it is surrounded by a thick green border.
+There must be no red or blue once it is focused.</p>
 <div id="focusme" class="reftest-wait" onfocus="this.classList.toggle('reftest-wait');" tabindex="1">Focus this element</div>
 <script>
 /* This script is an optional convenience,
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-007-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-007-ref.html
new file mode 100644
index 0000000..6ecc215
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-007-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Selectors Level 4: focus-within Reference File</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<style>
+  html, body, div {
+      border: solid 5px green;
+  }
+</style>
+<p>Test passes if, when the element below is focused, it is surrounded by a green border, and HTML and BODY elements also have a green border. There must be no red or blue once it is focused.</p>
+<div>Focus this element</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-007.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-007.html
new file mode 100644
index 0000000..f23fe876
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-007.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Selectors Level 4: focus-within</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-within-pseudo">
+<link rel="match" href="focus-within-007-ref.html">
+<meta name="assert" content="Checks that ':focus-within' can be used as universal selector.">
+<style>
+  /* Suppress things that cannot be reproduced in the reference file */
+  :focus {
+    outline: none;
+  }
+  html, body, div {
+      border: solid 5px red;
+  }
+  /* Use blue to indicate that the user needs to pay attention.
+     This element needs to be focused for the test to make sense. */
+  div {
+      border-color: blue;
+  }
+  :focus-within {
+      border-color: green;
+  }
+</style>
+<p>Test passes if, when the element below is focused, it is surrounded by a green border, and HTML and BODY elements also have a green border. There must be no red or blue once it is focused.</p>
+<div id="focusme" tabindex="1">Focus this element</div>
+<script>
+  var focusme = document.getElementById('focusme');
+  focusme.focus();
+  document.documentElement.classList.remove('reftest-wait');
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-008.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-008.html
new file mode 100644
index 0000000..19deff2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-008.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Selectors Level 4: focus-within</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-within-pseudo">
+<link rel="match" href="focus-within-007-ref.html">
+<meta name="assert" content="Checks that ':focus-within' can be used as universal selector (using *).">
+<style>
+  /* Suppress things that cannot be reproduced in the reference file */
+  :focus {
+    outline: none;
+  }
+  html, body, div {
+      border: solid 5px red;
+  }
+  /* Use blue to indicate that the user needs to pay attention.
+     This element needs to be focused for the test to make sense. */
+  div {
+      border-color: blue;
+  }
+  *:focus-within {
+      border-color: green;
+  }
+</style>
+<p>Test passes if, when the element below is focused, it is surrounded by a green border, and HTML and BODY elements also have a green border. There must be no red or blue once it is focused.</p>
+<div id="focusme" tabindex="1">Focus this element</div>
+<script>
+  var focusme = document.getElementById('focusme');
+  focusme.focus();
+  document.documentElement.classList.remove('reftest-wait');
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-009.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-009.html
new file mode 100644
index 0000000..decd30ab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-009.html
@@ -0,0 +1,206 @@
+<!DOCTYPE html>
+<html id="html">
+<head>
+  <meta charset="utf-8">
+  <title>Selectors Level 4: focus-within</title>
+  <link rel="author" title="Benjamin Poulain" href="mailto:bpoulain@apple.com">
+  <link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+  <link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-within-pseudo">
+  <meta name="assert" content="Checks the basic features of the ':focus-within' pseudo class.">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <style>
+    * {
+      background-color: white;
+    }
+    :focus-within {
+      background-color: rgb(1, 2, 3);
+    }
+  </style>
+</head>
+<body id="body">
+  <div id="test">
+    <div id="container1">
+      <div id="sibling1"></div>
+      <div id="sibling2">
+        <input id="target1">
+      </div>
+      <div id="sibling3"></div>
+    </div>
+    <div id="container2">
+      <div id="sibling4"></div>
+      <div id="sibling5">
+        <textarea id="target2"></textarea>
+      </div>
+      <div id="sibling6"></div>
+    </div>
+  </div>
+  <div id=log></div>
+
+  <script>
+    "use strict";
+
+    function elementsStyledWithFocusWithinSelector() {
+        let elements = [];
+        for (let element of document.querySelectorAll("*")) {
+            if (getComputedStyle(element).backgroundColor === 'rgb(1, 2, 3)') {
+                elements.push(element.id);
+            }
+        }
+        return elements;
+    }
+
+    function elementsMatchingFocusWithinSelector() {
+        let elements = [];
+        for (let element of document.querySelectorAll(":focus-within")) {
+            elements.push(element.id);
+        }
+        return elements;
+    }
+
+    test(
+      function() {
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), []);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), []);
+      }, "Initial State");
+
+    var container1 = document.getElementById("container1");
+    var container2 = document.getElementById("container2");
+    var target1 = document.getElementById("target1");
+    var target2 = document.getElementById("target2");
+
+    test(
+      function() {
+        target1.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+      }, "Focus 'target1'");
+
+    test(
+      function() {
+        target2.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+      }, "Focus 'target2'");
+
+    test(
+      function() {
+        target2.style.display = "none";
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+        assert_true(target2.matches(":focus"));
+      }, "Set display none on 'target2'");
+
+    test(
+      function() {
+        target1.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+      }, "Focus 'target1' again");
+
+    test(
+      function() {
+        target2.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_true(target1.matches(":focus"));
+        assert_false(target2.matches(":focus"));
+      }, "Try to focus 'target2'");
+
+    test(
+      function() {
+        target2.style.display = "inline-block";
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+      }, "Set display back on 'target2'");
+
+    test(
+      function() {
+        target2.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+      }, "Focus 'target2' again");
+
+    test(
+      function() {
+        container2.style.display = "none";
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+        assert_true(target2.matches(":focus"));
+      }, "Set display none on 'container2'");
+
+    test(
+      function() {
+        target1.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+      }, "Focus 'target1' once again");
+
+    test(
+      function() {
+        target2.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_true(target1.matches(":focus"));
+        assert_false(target2.matches(":focus"));
+      }, "Try to focus 'target2' again");
+
+    test(
+      function() {
+        container2.style.display = "block";
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container1", "sibling2", "target1"]);
+      }, "Set display back on 'container2'");
+
+    test(
+      function() {
+        container1.parentElement.removeChild(container1);
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), []);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), []);
+        assert_equals(container1.querySelectorAll(":focus-within").length, 0);
+        assert_false(target1.matches(":focus"));
+        assert_false(target2.matches(":focus"));
+      }, "Detach 'container1' from the document");
+
+    test(
+      function() {
+        target1.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), []);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), []);
+        assert_equals(container1.querySelectorAll(":focus-within").length, 0);
+        assert_false(target1.matches(":focus"));
+        assert_false(target2.matches(":focus"));
+      }, "Try to focus 'target1'");
+
+    test(
+      function() {
+        target2.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+      }, "Focus 'target2' once again");
+
+    test(
+      function() {
+        container2.appendChild(container1);
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "sibling5", "target2"]);
+      }, "Attach 'container1' in 'container2'");
+
+    test(
+      function() {
+        target1.focus();
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), ["html", "body", "test", "container2", "container1", "sibling2", "target1"]);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), ["html", "body", "test", "container2", "container1", "sibling2", "target1"]);
+      }, "Focus 'target1' for the last time");
+
+    test(
+      function() {
+        container2.appendChild(target1);
+        assert_array_equals(elementsStyledWithFocusWithinSelector(), []);
+        assert_array_equals(elementsMatchingFocusWithinSelector(), []);
+        assert_false(target1.matches(":focus"));
+        assert_false(target2.matches(":focus"));
+      }, "Move 'target1' in 'container2'");
+  </script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-iteration-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-iteration-expected.txt
index 92b6b0a5..5fd080a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-iteration-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-iteration-expected.txt
@@ -1,4 +1,9 @@
 This is a testharness.js-based test.
-FAIL DOMTokenList iteration: keys, values, etc. assert_array_equals: lengths differ, expected 2 got 3
+FAIL classList assert_array_equals: lengths differ, expected 2 got 3
+FAIL classList.keys assert_array_equals: lengths differ, expected 2 got 3
+FAIL classList.values assert_array_equals: lengths differ, expected 2 got 3
+PASS classList.entries 
+PASS classList.forEach 
+PASS classList inheritance from Array.prototype 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-iteration.html b/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-iteration.html
index 921f97cb..f713ad4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-iteration.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/lists/DOMTokenList-iteration.html
@@ -5,46 +5,67 @@
 <script src=/resources/testharnessreport.js></script>
 <span class="   a  a b "></span>
 <script>
-  test(function() {
+  test(() => {
     var list = document.querySelector("span").classList;
     assert_array_equals([...list], ["a", "b"]);
+  }, "classList");
 
-    var keys = list.keys();
-    assert_false(keys instanceof Array);
+  test(() => {
+    var keys = document.querySelector("span").classList.keys();
+    assert_false(keys instanceof Array, "must not be Array");
     keys = [...keys];
     assert_array_equals(keys, [0, 1]);
+  }, "classList.keys");
 
-    var values = list.values();
-    assert_false(values instanceof Array);
+  test(() => {
+    var values = document.querySelector("span").classList.values();
+    assert_false(values instanceof Array, "must not be Array");
     values = [...values];
     assert_array_equals(values, ["a", "b"]);
+  }, "classList.values");
 
-    var entries = list.entries();
-    assert_false(entries instanceof Array);
+  test(() => {
+    var entries = document.querySelector("span").classList.entries();
+    assert_false(entries instanceof Array, "must not be Array");
     entries = [...entries];
-    assert_equals(entries.length, keys.length);
-    assert_equals(entries.length, values.length);
+    var keys = [...document.querySelector("span").classList.keys()];
+    var values = [...document.querySelector("span").classList.values()];
+    assert_equals(entries.length, keys.length, "entries.length == keys.length");
+    assert_equals(entries.length, values.length,
+                  "entries.length == values.length");
     for (var i = 0; i < entries.length; ++i) {
-      assert_array_equals(entries[i], [keys[i], values[i]]);
+      assert_array_equals(entries[i], [keys[i], values[i]],
+                          "entries[" + i + "]");
     }
+  }, "classList.entries");
+
+  test(() => {
+    var list = document.querySelector("span").classList;
+    var values = [...list.values()];
+    var keys = [...list.keys()];
+    var entries = [...list.entries()];
 
     var cur = 0;
     var thisObj = {};
     list.forEach(function(value, key, listObj) {
-      assert_equals(listObj, list);
-      assert_equals(this, thisObj);
-      assert_equals(value, values[cur]);
-      assert_equals(key, keys[cur]);
+      assert_equals(listObj, list, "Entry " + cur + " listObj");
+      assert_equals(this, thisObj, "Entry " + cur + " this");
+      assert_equals(value, values[cur], "Entry " + cur + " value");
+      assert_equals(key, keys[cur], "Entry " + cur + " key");
       cur++;
     }, thisObj);
-    assert_equals(cur, entries.length);
+    assert_equals(cur, entries.length, "length");
+  }, "classList.forEach");
 
-    assert_equals(list[Symbol.iterator], Array.prototype[Symbol.iterator]);
-    assert_equals(list.keys, Array.prototype.keys);
+  test(() => {
+    var list = document.querySelector("span").classList;
+    assert_equals(list[Symbol.iterator], Array.prototype[Symbol.iterator],
+                  "[Symbol.iterator]");
+    assert_equals(list.keys, Array.prototype.keys, ".keys");
     if (Array.prototype.values) {
-      assert_equals(list.values, Array.prototype.values);
+      assert_equals(list.values, Array.prototype.values, ".values");
     }
-    assert_equals(list.entries, Array.prototype.entries);
-    assert_equals(list.forEach, Array.prototype.forEach);
-  });
+    assert_equals(list.entries, Array.prototype.entries, ".entries");
+    assert_equals(list.forEach, Array.prototype.forEach, ".forEach");
+  }, "classList inheritance from Array.prototype");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/content-metadata.js b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/content-metadata.js
index 8ba5bcf..580cc2bd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/content-metadata.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/content-metadata.js
@@ -81,29 +81,6 @@
                                         initDataType:   'cenc',
                                         initData: 'AAAAjXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAG0IARIQ7nNWTsiokPB472hx+kvhixoIY2FzdGxhYnMiRGV5SmhjM05sZEVsa0lqb2laVzFsTFhSbGMzUXRNbk5sYzNOcGIyNGlMQ0oyWVhKcFlXNTBTV1FpT2lKclpYa3lJbjA9MgdkZWZhdWx0AAADwnBzc2gAAAAAmgTweZhAQoarkuZb4IhflQAAA6KiAwAAAQABAJgDPABXAFIATQBIAEUAQQBEAEUAUgAgAHgAbQBsAG4AcwA9ACIAaAB0AHQAcAA6AC8ALwBzAGMAaABlAG0AYQBzAC4AbQBpAGMAcgBvAHMAbwBmAHQALgBjAG8AbQAvAEQAUgBNAC8AMgAwADAANwAvADAAMwAvAFAAbABhAHkAUgBlAGEAZAB5AEgAZQBhAGQAZQByACIAIAB2AGUAcgBzAGkAbwBuAD0AIgA0AC4AMAAuADAALgAwACIAPgA8AEQAQQBUAEEAPgA8AFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBFAFkATABFAE4APgAxADYAPAAvAEsARQBZAEwARQBOAD4APABBAEwARwBJAEQAPgBBAEUAUwBDAFQAUgA8AC8AQQBMAEcASQBEAD4APAAvAFAAUgBPAFQARQBDAFQASQBOAEYATwA+ADwASwBJAEQAPgBUAGwAWgB6ADcAcQBqAEkAOABKAEIANAA3ADIAaAB4ACsAawB2AGgAaQB3AD0APQA8AC8ASwBJAEQAPgA8AEwAQQBfAFUAUgBMAD4AaAB0AHQAcABzADoALwAvAGwAaQBjAC4AcwB0AGEAZwBpAG4AZwAuAGQAcgBtAHQAbwBkAGEAeQAuAGMAbwBtAC8AbABpAGMAZQBuAHMAZQAtAHAAcgBvAHgAeQAtAGgAZQBhAGQAZQByAGEAdQB0AGgALwBkAHIAbQB0AG8AZABhAHkALwBSAGkAZwBoAHQAcwBNAGEAbgBhAGcAZQByAC4AYQBzAG0AeAA8AC8ATABBAF8AVQBSAEwAPgA8AEwAVQBJAF8AVQBSAEwAPgBoAHQAdABwAHMAOgAvAC8AbABpAGMALgBzAHQAYQBnAGkAbgBnAC4AZAByAG0AdABvAGQAYQB5AC4AYwBvAG0ALwBsAGkAYwBlAG4AcwBlAC0AcAByAG8AeAB5AC0AaABlAGEAZABlAHIAYQB1AHQAaAAvAGQAcgBtAHQAbwBkAGEAeQAvAFIAaQBnAGgAdABzAE0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAFUASQBfAFUAUgBMAD4APABDAEgARQBDAEsAUwBVAE0APgB4AEQASwBBAFkAMAB2AFoAaABVAFUAPQA8AC8AQwBIAEUAQwBLAFMAVQBNAD4APAAvAEQAQQBUAEEAPgA8AC8AVwBSAE0ASABFAEEARABFAFIAPgA=' } ] },
 
-    'mp4-basic-key1' :          {   assetId:    'mp4-multikey-sequential',
-                                    variantId:  'key1',
-                                    initDataType:   'cenc',
-                                    audio: {    type:   'audio/mp4;codecs="mp4a.40.2"',
-                                                path:   '/encrypted-media/content/audio_aac-lc_128k_dashinit.mp4' },
-                                    video: {    type:   'video/mp4;codecs="avc1.4d401e"',
-                                                path:   '/encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4' },
-                                    keys: [ {   kid:    [0x8a, 0x0d, 0x85, 0x45, 0x21, 0x05, 0xd4, 0x15, 0x35, 0x8f, 0xea, 0x8f, 0x68, 0xe6, 0xc1, 0x91],
-                                                key:    [0x76, 0x6f, 0xab, 0xc1, 0x68, 0x3f, 0xf8, 0xef, 0x4e, 0x76, 0x00, 0x24, 0xc5, 0x23, 0x8f, 0x10],
-                                                initDataType:   'cenc',
-                                                initData: 'AAAAlXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAHUIARIQig2FRSEF1BU1j+qPaObBkRoIY2FzdGxhYnMiTGV5SmhjM05sZEVsa0lqb2liWEEwTFcxMWJIUnBhMlY1TFhObGNYVmxiblJwWVd3aUxDSjJZWEpwWVc1MFNXUWlPaUpyWlhreEluMD0yB2RlZmF1bHQAAANYcHNzaAAAAACaBPB5mEBChquS5lvgiF+VAAADODgDAAABAAEALgM8AFcAUgBNAEgARQBBAEQARQBSACAAeABtAGwAbgBzAD0AIgBoAHQAdABwADoALwAvAHMAYwBoAGUAbQBhAHMALgBtAGkAYwByAG8AcwBvAGYAdAAuAGMAbwBtAC8ARABSAE0ALwAyADAAMAA3AC8AMAAzAC8AUABsAGEAeQBSAGUAYQBkAHkASABlAGEAZABlAHIAIgAgAHYAZQByAHMAaQBvAG4APQAiADQALgAwAC4AMAAuADAAIgA+ADwARABBAFQAQQA+ADwAUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEUAWQBMAEUATgA+ADEANgA8AC8ASwBFAFkATABFAE4APgA8AEEATABHAEkARAA+AEEARQBTAEMAVABSADwALwBBAEwARwBJAEQAPgA8AC8AUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEkARAA+AFIAWQBVAE4AaQBnAFUAaABGAGQAUQAxAGoAKwBxAFAAYQBPAGIAQgBrAFEAPQA9ADwALwBLAEkARAA+ADwATABBAF8AVQBSAEwAPgBoAHQAdABwAHMAOgAvAC8AbABpAGMALgBzAHQAYQBnAGkAbgBnAC4AZAByAG0AdABvAGQAYQB5AC4AYwBvAG0ALwBsAGkAYwBlAG4AcwBlAC0AcAByAG8AeAB5AC0AaABlAGEAZABlAHIAYQB1AHQAaAAvAGQAcgBtAHQAbwBkAGEAeQAvAFIAaQBnAGgAdABzAE0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAEEAXwBVAFIATAA+ADwATABVAEkAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAGwAYQB5AHIAZQBhAGQAeQAtAHUAaQAuAGUAeABhAG0AcABsAGUALgBjAG8AbQA8AC8ATABVAEkAXwBVAFIATAA+ADwAQwBIAEUAQwBLAFMAVQBNAD4AcQBOAEkAZQBiAFQAWABzAG8AcgBnAD0APAAvAEMASABFAEMASwBTAFUATQA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A' } ]
-                                },
-    'mp4-basic-key2' :          {   assetId:    'mp4-multikey-sequential',
-                                    variantId:  'key2',
-                                    initDataType:   'cenc',
-                                    audio: {    type:   'audio/mp4;codecs="mp4a.40.2"',
-                                                path:   '/encrypted-media/content/audio_aac-lc_128k_dashinit.mp4' },
-                                    video: {    type:   'video/mp4;codecs="avc1.4d401e"',
-                                                path:   '/encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4' },
-                                    keys: [ {   kid:    [0xfb, 0xb4, 0xb7, 0xf3, 0x4a, 0xbd, 0x31, 0x87, 0x34, 0x4b, 0xce, 0xc4, 0x5f, 0x96, 0x68, 0x88],
-                                                key:    [0x26, 0x52, 0xc3, 0x1d, 0xf7, 0x92, 0xd1, 0x7b, 0x08, 0xa6, 0xfa, 0xd3, 0x7c, 0xb6, 0x25, 0x60],
-                                                initDataType:   'cenc',
-                                                initData: 'AAAAlXBzc2gAAAAA7e+LqXnWSs6jyCfc1R0h7QAAAHUIARIQ+7S380q9MYc0S87EX5ZoiBoIY2FzdGxhYnMiTGV5SmhjM05sZEVsa0lqb2liWEEwTFcxMWJIUnBhMlY1TFhObGNYVmxiblJwWVd3aUxDSjJZWEpwWVc1MFNXUWlPaUpyWlhreUluMD0yB2RlZmF1bHQAAANYcHNzaAAAAACaBPB5mEBChquS5lvgiF+VAAADODgDAAABAAEALgM8AFcAUgBNAEgARQBBAEQARQBSACAAeABtAGwAbgBzAD0AIgBoAHQAdABwADoALwAvAHMAYwBoAGUAbQBhAHMALgBtAGkAYwByAG8AcwBvAGYAdAAuAGMAbwBtAC8ARABSAE0ALwAyADAAMAA3AC8AMAAzAC8AUABsAGEAeQBSAGUAYQBkAHkASABlAGEAZABlAHIAIgAgAHYAZQByAHMAaQBvAG4APQAiADQALgAwAC4AMAAuADAAIgA+ADwARABBAFQAQQA+ADwAUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEUAWQBMAEUATgA+ADEANgA8AC8ASwBFAFkATABFAE4APgA8AEEATABHAEkARAA+AEEARQBTAEMAVABSADwALwBBAEwARwBJAEQAPgA8AC8AUABSAE8AVABFAEMAVABJAE4ARgBPAD4APABLAEkARAA+ADgANwBlADAAKwA3ADEASwBoAHoARQAwAFMAOAA3AEUAWAA1AFoAbwBpAEEAPQA9ADwALwBLAEkARAA+ADwATABBAF8AVQBSAEwAPgBoAHQAdABwAHMAOgAvAC8AbABpAGMALgBzAHQAYQBnAGkAbgBnAC4AZAByAG0AdABvAGQAYQB5AC4AYwBvAG0ALwBsAGkAYwBlAG4AcwBlAC0AcAByAG8AeAB5AC0AaABlAGEAZABlAHIAYQB1AHQAaAAvAGQAcgBtAHQAbwBkAGEAeQAvAFIAaQBnAGgAdABzAE0AYQBuAGEAZwBlAHIALgBhAHMAbQB4ADwALwBMAEEAXwBVAFIATAA+ADwATABVAEkAXwBVAFIATAA+AGgAdAB0AHAAcwA6AC8ALwBwAGwAYQB5AHIAZQBhAGQAeQAtAHUAaQAuAGUAeABhAG0AcABsAGUALgBjAG8AbQA8AC8ATABVAEkAXwBVAFIATAA+ADwAQwBIAEUAQwBLAFMAVQBNAD4ARgB0AGkASQBoADYAUwBKAG0AcABZAD0APAAvAEMASABFAEMASwBTAFUATQA+ADwALwBEAEEAVABBAD4APAAvAFcAUgBNAEgARQBBAEQARQBSAD4A' } ] },
 
     'mp4-multikey-sequential' : {   assetId:    'mp4-multikey-sequential',
                                     initDataType:   'cenc',
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4 b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4
deleted file mode 100644
index e69de29..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/video_512x288_h264-360k_multikey_key1_dashinit.mp4
+++ /dev/null
diff --git a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4 b/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4
deleted file mode 100644
index 0b9b457a..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/encrypted-media/content/video_512x288_h264-360k_multikey_key2_dashinit.mp4
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/browser-state/navigator_online_event-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/browser-state/navigator_online_event-manual.html
new file mode 100644
index 0000000..b100f17
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/browser-state/navigator_online_event-manual.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+  <title>Offline Application Cache</title>
+  <link rel="stylesheet" href="../resources/css/result.css">
+ </head>
+ <body>
+  <h1>navigator_online_event</h1>
+
+  <ol>
+  <li>Change the 'work offline' mode.</li>
+  <li>If actual result and expected result are same, then test is <span class="manualpass">Pass</span>, otherwise <span class="manualfail">Fail</span>.</li>
+  </ol>
+
+  <hr>
+
+  <h2>Actual Result</h2>
+  <div id="actualResult">
+    <span id="actualMsg"></span>
+  </div>
+
+  <h2>Expected Result</h2>
+  <div id="expectedResult">
+    <span id="expectedMsg">apply 'work offline': offline event is raised.<p>release 'work offline': online event is raised.</span>
+  </div>
+  <script>
+
+  function showOnline() {
+    document.getElementById('actualMsg').innerHTML = 'online event is raised.';
+  }
+
+  function showOffline() {
+    document.getElementById('actualMsg').innerHTML = 'offline event is raised.';
+  }
+
+  window.addEventListener("online", showOnline, false);
+  window.addEventListener("offline", showOffline, false);
+  </script>
+ </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_main_empty-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_main_empty-manual.html
new file mode 100644
index 0000000..317aaa1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_main_empty-manual.html
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML>
+<html manifest="resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - manifest_main_empty</title>
+    <link rel="stylesheet" href="resources/css/result.css">
+  </head>
+  <body>
+    <ol>
+      <li>Disable the network connection.</li>
+      <li>Refresh the page.</li>
+      <li>If the page is normally displayed, then test is <span class="manualpass"><b>PASS</b></span>, otherwise <span class="manualfail"><b>FAIL</b></span>.</li>
+    </ol>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_notchanged_online-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_notchanged_online-manual.html
new file mode 100644
index 0000000..a464b426
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_notchanged_online-manual.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html manifest="resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - manifest_notchanged_online</title>
+    <script src="resources/js/clock.js"></script>
+    <link rel="stylesheet" href="resources/css/result.css">
+    <link rel="stylesheet" href="resources/css/clock.css">
+    <link rel="stylesheet" href="resources/css/online.css" type="text/css" media="screen">
+  </head>
+  <body>
+    <ol>
+      <li>Remove time element of this html document and not change manifest file.</li>
+      <li>Refresh the page.</li>
+      <li>If the page is normally displayed, then test is <span class="manualpass"><b>PASS</b></span>, otherwise <span class="manualfail"><b>FAIL</b></span>.</li>
+    </ol>
+
+    <p class="connectivity" width="600">The time is: <output id="clock"></output></p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_section_empty-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_section_empty-manual.html
new file mode 100644
index 0000000..eea2dbb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_section_empty-manual.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html manifest="resources/manifest/section_empty.manifest">
+  <head>
+    <title>Offline Application Cache - manifest_section_empty</title>
+    <script src="resources/js/clock.js"></script>
+    <link rel="stylesheet" href="resources/css/result.css">
+    <link rel="stylesheet" href="resources/css/clock.css">
+    <link rel="stylesheet" href="resources/css/online.css" type="text/css" media="screen">
+  </head>
+  <body>
+    <ol>
+      <li>Disable the network connection.</li>
+      <li>Refresh the page.</li>
+      <li>If the time element and colors of result elements are normally displayed, then test is <span class="manualpass"><b>PASS</b></span>, otherwise <span class="manualfail"><b>FAIL</b></span>.</li>
+    </ol>
+
+    <p class="connectivity" width="600">The time is: <output id="clock"></output></p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_section_many-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_section_many-manual.html
new file mode 100644
index 0000000..9378df1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/manifest_section_many-manual.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML>
+<html manifest="resources/manifest/section_many.manifest">
+  <head>
+    <title>Offline Application Cache - manifest_section_many</title>
+    <script src="resources/js/clock.js"></script>
+    <link rel="stylesheet" href="resources/css/result.css">
+    <link rel="stylesheet" href="resources/css/clock.css">
+    <link rel="stylesheet" href="resources/css/online.css" type="text/css" media="screen">
+  </head>
+  <body>
+    <ol type="1">
+      <li>Disable the network connection.</li>
+      <li>Refresh the page.</li>
+      <li>If the time element and colors of result elements are normally displayed, then test is <span class="manualpass"><b>PASS</b></span>, otherwise <span class="manualfail"><b>FAIL</b></span>.</li>
+    </ol>
+
+    <p class="connectivity" width="600">The time is: <output id="clock"></output></p>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/section_network_offline-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/section_network_offline-manual.html
new file mode 100644
index 0000000..c4121f5b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/section_network_offline-manual.html
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML>
+<html manifest="resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - Section_network_offline</title>
+    <link rel="stylesheet" href="resources/css/result.css">
+  </head>
+  <body>
+    <ol>
+      <li>Disable the network connection.</li>
+      <li>Refresh the page.</li>
+      <li>If only the frame element can't be loaded, then test is <span class="manualpass"><b>PASS</b></span>, otherwise <span class="manualfail"><b>FAIL</b></span>.</li>
+    </ol>
+
+    <IFRAME id="TestFrame" name="TestWindow" src="html/clock.html" width="600" height="50" scrolling="auto" frameborder="1">
+    </IFRAME>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/section_network_online-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/section_network_online-manual.html
new file mode 100644
index 0000000..a5d8e594
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/offline/section_network_online-manual.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html manifest="resources/manifest/clock.manifest">
+  <head>
+    <title>Offline Application Cache - Section_network_online</title>
+    <link rel="stylesheet" href="resources/css/result.css">
+  </head>
+  <body>
+    <ol>
+      <li>Refresh the page.</li>
+      <li>If the frame element is loaded, then test is <span class="manualpass"><b>PASS</b></span>, otherwise <span class="manualfail"><b>FAIL</b></span>.</li>
+    </ol>
+
+    <IFRAME id="TestFrame" name="TestWindow" src="html/clock.html" width="600" height="50" scrolling="auto" frameborder="1">
+    </IFRAME>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
index 7ffd474..79377861 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html
@@ -146,7 +146,13 @@
     test_throws(exception_t, new TypeError, function() { protoSetter.call(C, new Object()); }, "proto setter |call| on cross-origin Window");
     test_throws(exception_t, new TypeError, function() { protoSetter.call(C.location, new Object()); }, "proto setter |call| on cross-origin Location");
   });
-}, "[[SetPrototypeOf]] should throw");
+  if (Reflect.setPrototypeOf) {
+    assert_false(Reflect.setPrototypeOf(C, new Object()),
+                 "Reflect.setPrototypeOf on cross-origin Window");
+    assert_false(Reflect.setPrototypeOf(C.location, new Object()),
+                "Reflect.setPrototypeOf on cross-origin Location");
+  }
+}, "[[SetPrototypeOf]] should return false");
 
 /*
  * [[IsExtensible]]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001-expected.txt
new file mode 100644
index 0000000..5bdfd9e1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+FAIL tokenization should skip window features separators before `name` assert_equals: "noopener" should activate feature "noopener" expected null but got object "[object Window]"
+PASS feature `name` should be converted to ASCII lowercase 
+FAIL after `name`, tokenization should skip window features separators that are not "=" or "," assert_equals: "foo noopener=1" should activate feature "noopener" expected null but got object "[object Window]"
+PASS Tokenizing should ignore window feature separators except "," after initial "=" and before value 
+PASS Tokenizing should read characters until first window feature separator as `value` 
+PASS "noopener" should be based on name (key), not value 
+FAIL invalid feature names should not tokenize as "noopener" assert_not_equals: "\0noopener" should NOT activate feature "noopener" got disallowed value null
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001.html
new file mode 100644
index 0000000..3d3f53e1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-001.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML: window.open `features`: tokenization -- `noopener`</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#apis-for-creating-and-navigating-browsing-contexts-by-name">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+var windowURL = 'resources/close-self.html';
+
+// Tests for how windows features are tokenized into 'name', 'value'
+// window features separators are ASCII whitespace, '=' and  ','
+
+test (t => {
+  // Tokenizing `name`: initial window features separators are ignored
+  // Each of these variants should tokenize to ('noopener', '')
+  var featureVariants = [
+    ' noopener',
+    '=noopener',
+    ',,noopener',
+    ',=, noopener',
+    '\n=noopener=',
+    '\tnoopener',
+    '\r,,,=noopener',
+    '\u000Cnoopener'
+  ];
+  featureVariants.forEach(feature => {
+    var win = window.open(windowURL, '', feature);
+    assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
+  });
+}, 'tokenization should skip window features separators before `name`');
+
+test (t => {
+  // Tokenizing `name`: lowercase conversion
+  // Each of these variants should tokenize as feature ('noopener', '')
+  // except where indicated
+  // Note also that `value` is lowercased during tokenization
+  var featureVariants = [
+    'NOOPENER',
+    'noOpenER',
+    '  NOopener',
+    '=NOOPENER',
+    'noopener=NOOPENER', // => ('noopener', 'noopener')
+    'NOOPENER=noopener' // => ('noopener', 'noopener')
+  ];
+  featureVariants.forEach(feature => {
+    var win = window.open(windowURL, '', feature);
+    assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
+  });
+}, 'feature `name` should be converted to ASCII lowercase');
+
+test (t => {
+  // After `name` has been collected, ignore any window features separators until '='
+  // except ',' OR a non-window-features-separator — break in those cases
+  // i.e. ignore whitespace until '=' unless a ',' is encountered first
+  // Each of these variants should tokenize as feature ('noopener', '')
+  var featureVariants = [
+    'noopener',
+    ' noopener\r',
+    'noopener\n =',
+    'noopener,',
+    'noopener  =,',
+    ', noopener   =',
+    'noopener,=',
+    'noopener foo', // => ('noopener', ''), ('foo', '')
+    'foo noopener=1', // => ('foo', ''), ('noopener', '1')
+    'foo=\u000Cnoopener' // => ('foo', ''), ('noopener', '')
+  ];
+  featureVariants.forEach(feature => {
+    var win = window.open(windowURL, '', feature);
+    assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
+  });
+}, 'after `name`, tokenization should skip window features separators that are not "=" or ","');
+
+test (t => {
+  // After initial '=', tokenizing should ignore all separators except ','
+  // before collecting `value`
+  // Each of these variants should tokenize as feature ('noopener', '')
+  // Except where indicated
+  var featureVariants = [
+    'noopener=  yes', // => ('noopener', 'yes')
+    'noopener==,',
+    'noopener=\n ,',
+    'noopener = \t ,',
+    'noopener\n=\r noopener,', // => ('noopener', 'noopener')
+    'noopener=,yes', // => ('noopener'), ('yes')
+    'noopener= foo=,', // => ('noopener', 'foo')
+    'noopener = \u000Cyes' // => ('noopener', 'yes')
+  ];
+  featureVariants.forEach(feature => {
+    var win = window.open(windowURL, '', feature);
+    assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
+  });
+}, 'Tokenizing should ignore window feature separators except "," after initial "=" and before value');
+
+test (t => {
+  // Tokenizing `value` should collect any non-separator code points until first separator
+  var featureVariants = [
+    'noopener=noopener', // => ('noopener', 'noopener')
+    'noopener=yes', // => ('noopener', 'yes')
+    'noopener = yes ,', // => ('noopener', 'yes')
+    'noopener=\nyes  ,', // => ('noopener', 'yes')
+    'noopener=yes yes', // => ('noopener', 'yes'), ('yes', '')
+    'noopener=yes\ts', // => ('noopener', 'yes'), ('s', '')
+    'noopener==', // => ('noopener', '')
+    'noopener=0\n,', // => ('noopener', '0')
+    '==noopener===', // => ('noopener', '')
+    'noopener==\u000C' // => ('noopener', '')
+  ];
+  featureVariants.forEach(feature => {
+    var win = window.open(windowURL, '', feature);
+    assert_equals(win, null, `"${feature}" should set "noopener"`);
+  });
+}, 'Tokenizing should read characters until first window feature separator as `value`');
+
+test (t => {
+  // If tokenizedFeatures contains an entry with the key "noopener"...disown opener
+  // i.e. `value` should be irrelevant
+  var featureVariants = [
+    'noopener=false',
+    ',noopener=0, ',
+    'foo=bar,noopener=noopener,',
+    'noopener=true',
+    'noopener=foo\nbar\t'
+  ];
+  featureVariants.forEach(feature => {
+    var win = window.open(windowURL, '', feature);
+    assert_equals(win, null, `"${feature}" should activate feature "noopener"`);
+  });
+}, '"noopener" should be based on name (key), not value');
+
+test (t => {
+  var invalidFeatureVariants = [
+    '-noopener', //     => ('-noopener', '')
+    'NOOPENERRRR', //   => ('noopenerrr', '')
+    'noOpenErR', //     => ('noopenerr', '')
+    'no_opener', //     => ('no_opener', '')
+    ' no opener', //    => ('no', ''), ('opener', '')
+    'no\nopener', //    => ('no', ''), ('opener', '')
+    'no,opener', //     => ('no', ''), ('opener', '')
+    '\0noopener', //    => ('\0noopener', '')
+    'noopener\u0000=yes' // => ('noopener\0', 'yes')
+  ];
+  invalidFeatureVariants.forEach(feature => {
+    var win = window.open(windowURL, '', feature);
+    assert_not_equals(win, null, `"${feature}" should NOT activate feature "noopener"`);
+  });
+}, 'invalid feature names should not tokenize as "noopener"');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html
new file mode 100644
index 0000000..0c0cf9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/close-self.html
@@ -0,0 +1,3 @@
+<script>
+  window.close();
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-close-manual.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-close-manual.sub.html
new file mode 100644
index 0000000..8e2740c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-close-manual.sub.html
@@ -0,0 +1,3 @@
+<meta charset=utf-8>
+<p>Follow this link to open a new browsing context and then confirm it can be closed:
+<a rel=noreferrer target=reallydoesnotmatter href="//天気の良い日.{{location[host]}}/html/browsers/windows/resources/window-close-button.html">link</a>.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-manual.html
new file mode 100644
index 0000000..f5879ee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-manual.html
@@ -0,0 +1,10 @@
+<ol>
+ <li><p>After clicking these two links in order a single browsing context should be open showing
+ <code>example.org</code>:
+ <a target=doesnotmatter href="http://example.com/">one</a>,
+ <a target=doesnotmatter href="http://example.org/">two</a>.
+
+ <li><p>After clicking these two links two browsing contexts should have been opened:
+ <a rel=noreferrer target=reallydoesnotmatter href="http://example.com/">one</a>,
+ <a rel=noreferrer target=reallydoesnotmatter href="http://example.com/">two</a>.
+</ol>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-window-name-manual.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-window-name-manual.sub.html
new file mode 100644
index 0000000..c598ffb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/noreferrer-cross-origin-window-name-manual.sub.html
@@ -0,0 +1,3 @@
+<meta charset=utf-8>
+<p>Follow this link to open a new browsing context and then confirm it says "idonteven":
+<a rel=noreferrer target=idonteven href="//天気の良い日.{{location[host]}}/html/browsers/windows/resources/echo-window-name.html">link</a>.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/opener-cross-origin-manual.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/opener-cross-origin-manual.sub.html
new file mode 100644
index 0000000..0c01866
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/opener-cross-origin-manual.sub.html
@@ -0,0 +1,10 @@
+<ol>
+ <li><p>Clicking this link must navigate this page to a resource that contains "THE END":
+ <a href=//{{domains[www1]}}:{{location[port]}}/html/browsers/windows/resources/opener-cross-origin.html target=_blank>test</a>
+
+ <li><p>Clicking this link must open a new browsing context that is empty:
+ <a rel=noreferrer href=//{{domains[www1]}}:{{location[port]}}/html/browsers/windows/resources/opener-cross-origin.html target=_blank>test</a>
+
+ <li><p>Clicking this link must navigate this page to a resource that contains "THE END":
+ <a href=//{{domains[www1]}}:{{location[port]}}/html/browsers/windows/resources/opener-cross-origin-embed.sub.html target=_blank>test</a>
+</ol>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/targeting-multiple-cross-origin-manual.sub.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/targeting-multiple-cross-origin-manual.sub.html
new file mode 100644
index 0000000..c8f8cfb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/windows/targeting-multiple-cross-origin-manual.sub.html
@@ -0,0 +1,9 @@
+<meta charset=utf-8>
+<p>Follow this link to open a new browsing context in a separate origin. Follow the instructions
+in that new window, and then come back to this window.
+<a target=first href="{{location[scheme]}}://{{domains[天気の良い日]}}:{{location[port]}}/html/browsers/windows/resources/target-cross-origin.sub.html">link</a>.
+
+<p>Once you come back to this page, follow this link.
+<a target=second href="resources/echo-window-name.html">link</a>.
+
+<p>After clicking that link, you should have three additional windows open.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/activation/click-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/activation/click-manual.html
new file mode 100644
index 0000000..1359a43
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/activation/click-manual.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<title>Interaction of UI input and the click in progress flag</title>
+<p>When you mouse click the checkbox below it should not be checked:</p>
+<p><input type=checkbox onclick=this.click()></p>
+<p>Now keyboard "click" the checkbox and confirm it's still not checked.</p>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/003-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/003-manual.html
new file mode 100644
index 0000000..5e0adbd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/003-manual.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<html>
+	<head>
+		<title>allowTargetOrigin valid syntax</title>
+		<style type="text/css">
+div { float: left; height: 100px; width: 100px; margin-right: 10px; background: orange; }
+iframe { height: 100px; width: 100px; border: none; }
+.note { float: right; color: silver; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+function addNote(el,str) {
+	var par = document.createElement(el);
+	par.textContent = str;
+	document.body.appendChild(par);
+}
+function testFrame(text,frameorigin,framepath) {
+	var persist = arguments;
+	addNote('p',(done++)+'. '+text);
+	var div = document.createElement('div');
+	var frame = document.createElement('iframe');
+	frame.src = frameorigin+framepath;
+	div.draggable = true;
+	div.ondragstart = function (e) {
+		e.dataTransfer.effectAllowed = 'copy';
+		e.dataTransfer.setData('text','dummy text');
+		for( var i = 3; i < persist.length; i++ ) {
+			e.dataTransfer.allowTargetOrigin(persist[i]);
+		}
+	};
+	var par = document.createElement('p');
+	par.className = 'note';
+	par.appendChild(document.createTextNode('Target: '+frameorigin));
+	par.appendChild(document.createElement('br'));
+	par.appendChild(document.createTextNode('Allowing: '+([]).slice.call(persist,3).join(' and ')));
+	if( framepath.match(/\?domain\b/) ) {
+		par.appendChild(document.createElement('br'));
+		par.appendChild(document.createTextNode('document.domain set to parent domain'));
+	}
+	document.body.appendChild(par);
+	document.body.appendChild(div);
+	document.body.appendChild(frame);
+}
+var done = 1;
+window.onload = function () {
+	var allowText = 'Drag the orange box below over the blue box the right, and release it. Fail if nothing happens in the blue box.';
+	var blockText = 'Drag the orange box below over the pink box the right, and release it. Pass if nothing happens in the pink box.';
+	var allowHelper = location.pathname.replace(/[^\/]*$/,'HELPER-mustallow.html');
+	var blockHelper = location.pathname.replace(/[^\/]*$/,'HELPER-mustblock.html');
+	if( location.hostname != httpHostMain || location.host != httpHostMain ) {
+		addNote('p','This test must be loaded over http:\/\/'+httpHostMain+'\/');
+	} else {
+		/* 01 */ testFrame(allowText,'http://'+httpHostMain,allowHelper);
+		/* 02 */ testFrame(allowText,'http://'+httpHostAlias,allowHelper);
+		/* 03 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'*');
+		/* 04 */ testFrame(allowText,'http://'+httpHostAlias,allowHelper,'*');
+		/* 05 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'/');
+		/* 06 */ testFrame(blockText,'http://'+httpHostAlias,blockHelper,'/');
+		/* 07 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'http://'+httpHostMain);
+		/* 08 */ testFrame(blockText,'http://'+httpHostMain+':'+httpPortAlias,blockHelper,'http://'+httpHostMain);
+		/* 09 */ testFrame(blockText,'http://'+httpHostAlias,blockHelper,'http://'+httpHostMain);
+		/* 10 */ testFrame(blockText,'http://'+httpHostAlias,blockHelper,'http://'+httpHostMain);
+		/* 11 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'http://'+httpHostMain+':80');
+		/* 12 */ testFrame(blockText,'http://'+httpHostMain+':'+httpPortAlias,blockHelper,'http://'+httpHostMain+':80');
+		/* 13 */ testFrame(allowText,'http://'+httpHostMain+':'+httpPortAlias,allowHelper,'http://'+httpHostMain+':'+httpPortAlias);
+		/* 14 */ testFrame(blockText,'http://'+httpHostMain,blockHelper,'http://'+httpHostMain+':'+httpPortAlias);
+		/* 15 */ testFrame(blockText,'https://'+httpsHostAlias,blockHelper,'http://'+httpsHostAlias);
+		/* 16 */ testFrame(allowText,'https://'+httpsHostAlias,allowHelper,'https://'+httpsHostAlias);
+		/* 17 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'http://foo:bar@'+httpHostMain+'/baz');
+		/* 18 */ testFrame(allowText,'http://foo:bar@'+httpHostMain,allowHelper,'http://'+httpHostMain);
+		/* 19 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'http://'+httpHostAlias,'/');
+		/* 20 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'/','http://'+httpHostAlias);
+		/* 21 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'http://'+httpHostAlias,'*');
+		/* 22 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'http://'+httpHostAlias,'http://'+httpHostMain);
+		/* 23 */ testFrame(allowText,'http://'+httpHostAlias,allowHelper,'http://'+httpHostAlias,'http://'+httpHostMain);
+		/* 24 */ testFrame(blockText,'http://'+httpHostAlias,blockHelper,'http://dummy','http://'+httpHostMain);
+		/* 25 */ testFrame(blockText,'https://'+httpsHostAlias,blockHelper,'https://'+httpsHostAlias+':'+httpsPortAlias);
+		/* 26 */ testFrame(blockText,'https://'+httpsHostAlias+':'+httpsPortAlias,blockHelper,'https://'+httpsHostAlias);
+		/* 27 */ testFrame(allowText,'https://'+httpsHostAlias+':'+httpsPortAlias,allowHelper,'https://'+httpsHostAlias+':'+httpsPortAlias);
+		window.xhr = new XMLHttpRequest();
+		xhr.open('GET',allowHelper,false);
+		xhr.send(null);
+		/* 28 */ testFrame(allowText,'data:text/html,',escape(xhr.responseText),'http://'+httpHostMain);
+		/* 29 */ testFrame(allowText,'javascript:','parent.xhr.responseText','http://'+httpHostMain);
+		/* 30 */ testFrame(blockText,'http://'+httpHostAlias,blockHelper,'http://'+httpHostAlias.replace(/^[^.]+\./,''));
+		/* 31 */ testFrame(allowText,'http://'+httpHostAlias,allowHelper+'?domain','http://'+httpHostAlias);
+		/* 32 */ testFrame(blockText,'http://'+httpHostAlias,blockHelper+'?domain','http://'+httpHostAlias.replace(/^[^.]+\./,''));
+	}
+};
+		</script>
+	</head>
+	<body>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/004-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/004-manual.html
new file mode 100644
index 0000000..2a3d3bb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/004-manual.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Data URI does not match absolute HTTP URL</title>
+	</head>
+	<body>
+		<p>Load the following URL in a new tab (copy &amp; paste it into the address bar):</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+		<script type="text/javascript">
+document.write('data:text/html,'+escape(
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Data URI does not match absolute HTTP URL<\/title>\
+		<style type="text/css">\
+iframe { border: none; height: 150px; width: 150px; }\
+		<\/style>\
+		<script type="text/javascript">\
+window.onload = function () {\
+	document.body.ondragenter = document.body.ondragleave = document.body.ondragover = document.body.ondrop = function (e) {\
+		e.preventDefault();\
+		document.body.innerHTML = "FAIL";\
+	};\
+};\
+		<\/script>\
+	<\/head>\
+	<body>\
+		<p>Drag the orange square below over this text, and release it. Pass if this text does not change.<\/p>\
+		<p><iframe src="'+location.href.replace(/\.html$/,'-1.html')+'"><\/iframe><\/p>\
+	<\/body>\
+<\/html>'));
+
+		</script>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/005-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/005-manual.html
new file mode 100644
index 0000000..90a002c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/005-manual.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+	<head>
+		<title>JavaScript URI does not match absolute HTTP URL</title>
+	</head>
+	<body>
+		<p>Load the following URL in a new tab (copy &amp; paste it into the address bar):</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+		<script type="text/javascript">
+document.write('javascript:unescape("'+escape(
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>JavaScript does not match absolute HTTP URL<\/title>\
+		<style type=\'text/css\'>\
+iframe { border: none; height: 150px; width: 150px; }\
+		<\/style>\
+		<script type=\'text/javascript\'>\
+window.onload = function () {\
+	document.body.ondragenter = document.body.ondragleave = document.body.ondragover = document.body.ondrop = function (e) {\
+		e.preventDefault();\
+		document.body.innerHTML = \'FAIL\';\
+	};\
+};\
+		<\/script>\
+	<\/head>\
+	<body>\
+		<p>Drag the orange square below over this text, and release it. Pass if this text does not change.<\/p>\
+		<p><iframe src=\''+location.href.replace(/\.html$/,'-1.html')+'\'><\/iframe><\/p>\
+	<\/body>\
+<\/html>')+'")');
+
+		</script>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/006-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/006-manual.html
new file mode 100644
index 0000000..e167439
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/006-manual.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Data URI does not match /</title>
+	</head>
+	<body>
+		<!--
+/ sets an absolute URL pointing to the document's unique identifier - used as the script origin.
+The script origin will in fact be inherited from the parent page, which is actually the same data URI.
+That part works.
+However, when it comes to matching against it, it will not match, as the global identifier does not
+match because the origin does not match the scheme/host/port tuple required.
+		-->
+		<p>Load the following URL in a new tab (copy &amp; paste it into the address bar):</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+		<script type="text/javascript">
+document.write('data:text/html,'+escape(
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Data URI does not match /<\/title>\
+		<style type="text/css">\
+html, body { margin: 0; padding: 0; }\
+div { height: 100px; width: 100px; background: orange; }\
+iframe { border: none; height: 150px; width: 150px; }\
+		<\/style>\
+	<\/head>\
+	<body>\
+		<script type="text/javascript">\
+if( self == top ) {\
+	document.body.ondragenter = document.body.ondragleave = document.body.ondragover = document.body.ondrop = function (e) {\
+		e.preventDefault();\
+		document.body.innerHTML = "FAIL";\
+	};\
+	document.write("<p>Drag the orange square below over this text, and release it. Pass if this text does not change.<\\\/p>");\
+	document.write("<p><iframe src=\\""+location.href+"\\"><\\\/iframe><\\\/p>");\
+} else {\
+	document.write("<div draggable=\\"true\\"><\\\/div>");\
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {\
+		e.dataTransfer.effectAllowed = "copy";\
+		e.dataTransfer.setData("text","dummy text");\
+		e.dataTransfer.allowTargetOrigin("/");\
+	};\
+}\
+		<\/script>\
+	<\/body>\
+<\/html>'));
+
+		</script>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/007-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/007-manual.html
new file mode 100644
index 0000000..4f35ed17
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/007-manual.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Data URI does not match its own URL</title>
+	</head>
+	<body>
+		<!--
+Sets an absolute URL pointing to the data URI.
+The script origin will in fact be inherited from the parent page, which is actually the same data URI.
+That part works.
+However, when it comes to matching against it, it will not match, as the global identifier used as the
+script origin does not match because the origin does not match the scheme/host/port tuple required.
+		-->
+		<p>Load the following URL in a new tab (copy &amp; paste it into the address bar):</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+		<script type="text/javascript">
+document.write('data:text/html,'+escape(
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Data URI does not match its own URL<\/title>\
+		<style type="text/css">\
+html, body { margin: 0; padding: 0; }\
+div { height: 100px; width: 100px; background: orange; }\
+iframe { border: none; height: 150px; width: 150px; }\
+		<\/style>\
+	<\/head>\
+	<body>\
+		<script type="text/javascript">\
+if( self == top ) {\
+	document.body.ondragenter = document.body.ondragleave = document.body.ondragover = document.body.ondrop = function (e) {\
+		e.preventDefault();\
+		document.body.innerHTML = "FAIL";\
+	};\
+	document.write("<p>Drag the orange square below over this text, and release it. Pass if this text does not change.<\\\/p>");\
+	document.write("<p><iframe src=\\""+location.href+"\\"><\\\/iframe><\\\/p>");\
+} else {\
+	document.write("<div draggable=\\"true\\"><\\\/div>");\
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {\
+		e.dataTransfer.effectAllowed = "copy";\
+		e.dataTransfer.setData("text","dummy text");\
+		e.dataTransfer.allowTargetOrigin(location.href);\
+	};\
+}\
+		<\/script>\
+	<\/body>\
+<\/html>'));
+
+		</script>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/008-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/008-manual.html
new file mode 100644
index 0000000..71e915c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/008-manual.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Data URI does match *</title>
+	</head>
+	<body>
+		<!--
+* allows any URL at all, so it should work
+		-->
+		<p>Load the following URL in a new tab (copy &amp; paste it into the address bar):</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+		<script type="text/javascript">
+document.write('data:text/html,'+escape(
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Data URI does match *<\/title>\
+		<style type="text/css">\
+html, body { margin: 0; padding: 0; }\
+div { height: 100px; width: 100px; background: orange; }\
+iframe { border: none; height: 150px; width: 150px; }\
+		<\/style>\
+	<\/head>\
+	<body>\
+		<script type="text/javascript">\
+var seentypes = {};\
+if( self == top ) {\
+	document.body.ondragenter = document.body.ondragover = document.body.ondrop = function (e) {\
+		e.preventDefault();\
+		if( e.type == "drop" ) {\
+			document.body.innerHTML = ( seentypes.dragenter && seentypes.dragover ) ? "PASS" : "FAIL";\
+		} else {\
+			seentypes[e.type] = true;\
+		}\
+	};\
+	document.write("<p>Drag the orange square below over this text, and release it. Fail if this text does not change.<\\\/p>");\
+	document.write("<p><iframe src=\\""+location.href+"\\"><\\\/iframe><\\\/p>");\
+} else {\
+	document.write("<div draggable=\\"true\\"><\\\/div>");\
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {\
+		e.dataTransfer.effectAllowed = "copy";\
+		e.dataTransfer.setData("text","dummy text");\
+		e.dataTransfer.allowTargetOrigin("*");\
+	};\
+}\
+		<\/script>\
+	<\/body>\
+<\/html>'));
+
+		</script>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/009-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/009-manual.html
new file mode 100644
index 0000000..2fc7ef43
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/009-manual.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+	<head>
+		<title>* should not prevent dropping on external applications</title>
+		<style type="text/css">
+div { height: 100px; width: 100px; background: orange; }
+		</style>
+		<script type="text/javascript">
+window.onload = function () {
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {
+		e.dataTransfer.effectAllowed = "copy";
+		e.dataTransfer.setData("text","PASS");
+		e.dataTransfer.allowTargetOrigin("*");
+	};
+};
+		</script>
+	</head>
+	<body>
+		<p>This test is only relevant on platforms where it is possible to switch applications in mid-drag (eg. alt+tab, dragging over taskbar buttons, dragging between restored windows).</p>
+		<p>This testcase requires an external application that accepts dropping of text from other applications - eg. Wordpad (write.exe) on Windows. Ensure that the external application is open.</p>
+		<p>Drag the orange block to the other application and release it. Pass if the word &quot;PASS&quot; appears in the other application.</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+		<div draggable="true"></div>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/010-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/010-manual.html
new file mode 100644
index 0000000..74a20d7e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/010-manual.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<html>
+	<head>
+		<title>A URL should prevent dropping on external applications</title>
+		<style type="text/css">
+div { height: 100px; width: 100px; background: orange; }
+		</style>
+		<script type="text/javascript">
+window.onload = function () {
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {
+		e.dataTransfer.effectAllowed = "copy";
+		e.dataTransfer.setData("text","FAIL");
+		e.dataTransfer.allowTargetOrigin("http://foo");
+	};
+};
+		</script>
+	</head>
+	<body>
+		<p>This test is only relevant on platforms where it is possible to switch applications in mid-drag (eg. alt+tab, dragging over taskbar buttons, dragging between restored windows).</p>
+		<p>This testcase requires an external application that accepts dropping of text from other applications - eg. Wordpad (write.exe) on Windows. Ensure that the external application is open.</p>
+		<p>Drag the orange block to the other application and release it. Fail if the word &quot;FAIL&quot; appears in the other application.</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+		<div draggable="true"></div>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/011-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/011-manual.html
new file mode 100644
index 0000000..e030271
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/011-manual.html
@@ -0,0 +1,63 @@
+<!doctype html>
+<html>
+	<head>
+		<title>allowTargetOrigin should only block dragenter, dragover, dragleave and drop events</title>
+		<style type="text/css">
+div { height: 100px; width: 100px; background: orange; margin: 0; padding: 0; float: left; }
+div + div { background: blue; }
+		</style>
+		<script type="text/javascript">
+window.onload = function () {
+	var orange = document.getElementsByTagName('div')[0], evtdone = {}, fails = [];
+	orange.ondragstart = function (e) {
+		evtdone[e.type] = true;
+		e.dataTransfer.effectAllowed = 'copy';
+		e.dataTransfer.setData('text','dummy text');
+		try {
+			e.dataTransfer.allowTargetOrigin('http://example.com');
+		} catch(e) {
+			fails[fails.length] = 'allowTargetOrigin threw an error: '+e;
+		}
+	};
+	orange.ondragenter = orange.ondragover = orange.ondrop = function (e) {
+		e.preventDefault();
+		evtdone[e.type] = true;
+	};
+	orange.ondrag = orange.ondragleave = function (e) {
+		evtdone[e.type] = true;
+	};
+	orange.ondragend = function (e) {
+		evtdone[e.type] = true;
+		if( !evtdone.dragstart ) {
+			fails[fails.length] = 'dragstart did not fire - how did that happen?';
+		}
+		if( !evtdone.drag ) {
+			fails[fails.length] = 'drag did not fire';
+		}
+		if( !evtdone.dragend ) {
+			fails[fails.length] = 'dragend did not fire - OK, who broke the testcase?';
+		}
+		if( evtdone.dragenter ) {
+			fails[fails.length] = 'dragenter fired';
+		}
+		if( evtdone.dragover ) {
+			fails[fails.length] = 'dragover fired';
+		}
+		if( evtdone.dragleave ) {
+			fails[fails.length] = 'dragleave fired';
+		}
+		if( evtdone.drop ) {
+			fails[fails.length] = 'drop fired';
+		}
+		document.getElementsByTagName('p')[0].innerHTML = fails.length ? ( 'FAIL:<br>' + fails.join('<br>') ) : 'PASS';
+	};
+};
+		</script>
+	</head>
+	<body>
+		<p>Drag the orange square over the blue square then back to the orange square, then release it. Fail if this text does not change.</p>
+		<div draggable="true"></div>
+		<div></div>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/012-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/012-manual.html
new file mode 100644
index 0000000..164e613
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/012-manual.html
@@ -0,0 +1,62 @@
+<!doctype html>
+<html>
+	<head>
+		<title>allowTargetOrigin after leaving browser window</title>
+		<style type="text/css">
+div { float: left; height: 100px; width: 100px; margin-right: 10px; background: orange; }
+iframe { height: 100px; width: 100px; border: none; }
+.note { float: right; color: silver; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+function addNote(el,str) {
+	var par = document.createElement(el);
+	par.textContent = str;
+	document.body.appendChild(par);
+}
+function testFrame(text,frameorigin,framepath) {
+	var persist = arguments;
+	addNote('p',(done++)+'. '+text);
+	var div = document.createElement('div');
+	var frame = document.createElement('iframe');
+	frame.src = frameorigin+framepath;
+	div.draggable = true;
+	div.ondragstart = function (e) {
+		e.dataTransfer.effectAllowed = 'copy';
+		e.dataTransfer.setData('text','dummy text');
+		for( var i = 3; i < persist.length; i++ ) {
+			e.dataTransfer.allowTargetOrigin(persist[i]);
+		}
+	};
+	var par = document.createElement('p');
+	par.className = 'note';
+	par.appendChild(document.createTextNode('Target: '+frameorigin));
+	par.appendChild(document.createElement('br'));
+	par.appendChild(document.createTextNode('Allowing: '+([]).slice.call(persist,3).join(' and ')));
+	if( framepath.match(/\?domain\b/) ) {
+		par.appendChild(document.createElement('br'));
+		par.appendChild(document.createTextNode('document.domain set to parent domain'));
+	}
+	document.body.appendChild(par);
+	document.body.appendChild(div);
+	document.body.appendChild(frame);
+}
+var done = 1;
+window.onload = function () {
+	var allowText = 'Drag the orange box below outside the browser window (not onto the system taskbar) then back over the blue box the right, and release it. Fail if nothing happens in the blue box.';
+	var blockText = 'Drag the orange box below outside the browser window (not onto the system taskbar) then back over the pink box the right, and release it. Pass if nothing happens in the pink box.';
+	var allowHelper = location.pathname.replace(/[^\/]*$/,'HELPER-mustallow.html');
+	var blockHelper = location.pathname.replace(/[^\/]*$/,'HELPER-mustblock.html');
+	if( location.hostname != httpHostMain || location.host != httpHostMain ) {
+		addNote('p','This test must be loaded over http:\/\/'+httpHostMain+'\/');
+	} else {
+		/* 07 */ testFrame(allowText,'http://'+httpHostMain,allowHelper,'http://'+httpHostMain);
+		/* 09 */ testFrame(blockText,'http://'+httpHostAlias,blockHelper,'http://'+httpHostMain);
+	}
+};
+		</script>
+	</head>
+	<body>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/013-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/013-manual.html
new file mode 100644
index 0000000..39ee70cf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/013-manual.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html>
+	<head>
+		<title>A URL should prevent dropping on UI</title>
+		<style type="text/css">
+div { height: 100px; width: 100px; background: orange; }
+		</style>
+		<script type="text/javascript">
+window.onload = function () {
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {
+		e.dataTransfer.effectAllowed = "copy";
+		e.dataTransfer.setData("text","FAIL");
+		e.dataTransfer.allowTargetOrigin("http://foo");
+	};
+};
+		</script>
+	</head>
+	<body>
+		<p>This test is only relevant on platforms where it is possible to drop data onto the browser UI (eg. the address field).</p>
+		<p>Drag the orange block to the address field and release it. Fail if the word &quot;FAIL&quot; appears in the address field. Repeat for other UI fields.</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+		<div draggable="true"></div>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/102-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/102-manual.html
new file mode 100644
index 0000000..ebb3090
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/102-manual.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for http site to itself</title>
+		<style type="text/css">
+div { height: 100px; width: 100px; background: orange; }
+iframe { width: 500px; height: 120px; border: none; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	document.getElementsByTagName('div')[0].ondragstart = function (e) {
+		e.dataTransfer.effectAllowed = 'copy';
+		e.dataTransfer.setData('text','dummy text');
+	};
+	document.getElementsByTagName('span')[0].textContent = origin;
+	var iframe = document.createElement('iframe');
+	iframe.src = origin+location.pathname.replace(/[^\/]*$/,'HELPER-showorigin.html');
+	document.body.insertBefore(iframe,document.getElementsByTagName('div')[0]);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+		<p>Drag the orange square onto the blue square and release it. The blue square should be replaced with the text:<br>
+		<span></span></p>
+		<div draggable="true"></div>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/103-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/103-manual.html
new file mode 100644
index 0000000..7bedf09
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/103-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for http site with user/pass/port to itself</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'http://foo:bar@'+httpHostMain+':80'+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/104-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/104-manual.html
new file mode 100644
index 0000000..12624246
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/104-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for http site with non-default port to itself</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'http://'+httpHostMain+':'+httpPortAlias+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/105-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/105-manual.html
new file mode 100644
index 0000000..4695888a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/105-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for http site to site with non-default port</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'http://'+httpHostMain+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/106-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/106-manual.html
new file mode 100644
index 0000000..1801751
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/106-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for http site with non-default port to site</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'http://'+httpHostMain+':'+httpPortAlias+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/107-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/107-manual.html
new file mode 100644
index 0000000..ecd9e9b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/107-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for https site to itself</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'https://'+httpsHostAlias+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/108-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/108-manual.html
new file mode 100644
index 0000000..eb77db36
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/108-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for https site with non-default port to itself</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'https://'+httpsHostAlias+':'+httpsPortAlias+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/109-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/109-manual.html
new file mode 100644
index 0000000..7817a85
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/109-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for https site to site with non-default port</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'https://'+httpsHostAlias+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/110-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/110-manual.html
new file mode 100644
index 0000000..663e162
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/110-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for https site with non-default port to site</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'https://'+httpsHostAlias+':'+httpsPortAlias+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/111-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/111-manual.html
new file mode 100644
index 0000000..c81efa0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/111-manual.html
@@ -0,0 +1,52 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for file: to http:</title>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var datastr =
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Origin for file: to http:<\/title>\
+		<style type="text/css">\
+div { height: 100px; width: 100px; background: orange; }\
+iframe { width: 500px; height: 120px; border: none; }\
+		<\/style>\
+		<script type="text/javascript">\
+window.onload = function () {\
+	var origin = "null (string)";\
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {\
+		e.dataTransfer.effectAllowed = "copy";\
+		e.dataTransfer.setData("text","dummy text");\
+	};\
+	document.getElementsByTagName("span")[0].textContent = origin;\
+	var iframe = document.createElement("iframe");\
+	iframe.src = "'+location.href.replace(/[^\/]*$/,'HELPER-showorigin.html')+'";\
+	document.body.insertBefore(iframe,document.getElementsByTagName("div")[0]);\
+};\
+		<\/script>\
+	<\/head>\
+	<body>\
+		<p>Drag the orange square onto the blue square and release it. The blue square should be replaced with the text:<br>\
+		<span><\/span><\/p>\
+		<div draggable="true"></div>\
+	<\/body>\
+<\/html>';
+	document.getElementsByTagName('a')[0].href = 'data:text/html,'+escape(datastr);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+		<p><a href="">Download the linked file to your disk</a>, and open it locally. Follow further instructions in that file.</p>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/112-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/112-manual.html
new file mode 100644
index 0000000..858e51d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/112-manual.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for data: with inherited http origin to http:</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var datastr =
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Origin for data: with inherited http origin to http:<\/title>\
+		<style type="text/css">\
+div { height: 100px; width: 100px; background: orange; }\
+iframe { width: 500px; height: 120px; border: none; }\
+		<\/style>\
+		<script type="text/javascript">\
+window.onload = function () {\
+	var origin = "http://'+httpHostMain+'";\
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {\
+		e.dataTransfer.effectAllowed = "copy";\
+		e.dataTransfer.setData("text","dummy text");\
+	};\
+	document.getElementsByTagName("span")[0].textContent = origin;\
+	var iframe = document.createElement("iframe");\
+	iframe.src = "'+location.href.replace(/[^\/]*$/,'HELPER-showorigin.html')+'";\
+	document.body.insertBefore(iframe,document.getElementsByTagName("div")[0]);\
+};\
+		<\/script>\
+	<\/head>\
+	<body>\
+		<p>Drag the orange square onto the blue square and release it. The blue square should be replaced with the text:<br>\
+		<span><\/span><\/p>\
+		<div draggable="true"></div>\
+	<\/body>\
+<\/html>';
+	var iframe = document.createElement('iframe');
+	iframe.src = 'data:text/html,'+escape(datastr);
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/113-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/113-manual.html
new file mode 100644
index 0000000..d3f889a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/113-manual.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for data: with no inherited origin to http:</title>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+	</head>
+	<body>
+
+		<p>Load the following URL in a new tab (copy &amp; paste it into the address bar):</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+		<script type="text/javascript">
+var origin = 'http://'+httpHostMain;
+if( location.href.indexOf(origin+'/') ) {
+	document.write('This must be tested on '+origin+'/');
+} else {
+	document.write("data:text/html,"+escape(
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Origin for data: with no inherited origin to http:<\/title>\
+		<style type="text/css">\
+div { height: 100px; width: 100px; background: orange; }\
+iframe { width: 500px; height: 120px; border: none; }\
+		<\/style>\
+		<script type="text/javascript">\
+window.onload = function () {\
+	var origin = "null (string)";\
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {\
+		e.dataTransfer.effectAllowed = "copy";\
+		e.dataTransfer.setData("text","dummy text");\
+	};\
+	document.getElementsByTagName("span")[0].textContent = origin;\
+	var iframe = document.createElement("iframe");\
+	iframe.src = "'+location.href.replace(/[^\/]*$/,'HELPER-showorigin.html')+'";\
+	document.body.insertBefore(iframe,document.getElementsByTagName("div")[0]);\
+};\
+		<\/script>\
+	<\/head>\
+	<body>\
+		<p>Drag the orange square onto the blue square and release it. The blue square should be replaced with the text:<br>\
+		<span><\/span><\/p>\
+		<div draggable="true"></div>\
+	<\/body>\
+<\/html>'));
+}
+		</script>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/114-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/114-manual.html
new file mode 100644
index 0000000..b253217
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/114-manual.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for javascript: with inherited http origin to http:</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var datastr =
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Origin for javascript: with inherited http origin to http:<\/title>\
+		<style type="text/css">\
+div { height: 100px; width: 100px; background: orange; }\
+iframe { width: 500px; height: 120px; border: none; }\
+		<\/style>\
+		<script type="text/javascript">\
+window.onload = function () {\
+	var origin = "http://'+httpHostMain+'";\
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {\
+		e.dataTransfer.effectAllowed = "copy";\
+		e.dataTransfer.setData("text","dummy text");\
+	};\
+	document.getElementsByTagName("span")[0].textContent = origin;\
+	var iframe = document.createElement("iframe");\
+	iframe.src = "'+location.href.replace(/[^\/]*$/,'HELPER-showorigin.html')+'";\
+	document.body.insertBefore(iframe,document.getElementsByTagName("div")[0]);\
+};\
+		<\/script>\
+	<\/head>\
+	<body>\
+		<p>Drag the orange square onto the blue square and release it. The blue square should be replaced with the text:<br>\
+		<span><\/span><\/p>\
+		<div draggable="true"></div>\
+	<\/body>\
+<\/html>';
+	var iframe = document.createElement('iframe');
+	iframe.src = "javascript:'"+escape(datastr)+"'";
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/115-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/115-manual.html
new file mode 100644
index 0000000..751757e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/115-manual.html
@@ -0,0 +1,50 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for javascript: with no inherited origin to http:</title>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+	</head>
+	<body>
+
+		<p>Load the following URL in a new tab (copy &amp; paste it into the address bar):</p>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+		<script type="text/javascript">
+var origin = 'http://'+httpHostMain;
+if( location.href.indexOf(origin+'/') ) {
+	document.write('This must be tested on '+origin+'/');
+} else {
+	document.write("javascript:'"+escape(
+'<!doctype html>\
+<html>\
+	<head>\
+		<title>Origin for javascript: with no inherited origin to http:<\/title>\
+		<style type="text/css">\
+div { height: 100px; width: 100px; background: orange; }\
+iframe { width: 500px; height: 120px; border: none; }\
+		<\/style>\
+		<script type="text/javascript">\
+window.onload = function () {\
+	var origin = "null (string)";\
+	document.getElementsByTagName("div")[0].ondragstart = function (e) {\
+		e.dataTransfer.effectAllowed = "copy";\
+		e.dataTransfer.setData("text","dummy text");\
+	};\
+	document.getElementsByTagName("span")[0].textContent = origin;\
+	var iframe = document.createElement("iframe");\
+	iframe.src = "'+location.href.replace(/[^\/]*$/,'HELPER-showorigin.html')+'";\
+	document.body.insertBefore(iframe,document.getElementsByTagName("div")[0]);\
+};\
+		<\/script>\
+	<\/head>\
+	<body>\
+		<p>Drag the orange square onto the blue square and release it. The blue square should be replaced with the text:<br>\
+		<span><\/span><\/p>\
+		<div draggable="true"></div>\
+	<\/body>\
+<\/html>')+"'");
+}
+		</script>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/116-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/116-manual.html
new file mode 100644
index 0000000..fdeeeb37
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/116-manual.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for dropped files</title>
+		<style type="text/css">
+div { height: 100px; width: 100px; background: orange; }
+iframe { width: 500px; height: 120px; border: none; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	document.getElementsByTagName('span')[0].textContent = 'null (string)';
+	var iframe = document.createElement('iframe');
+	iframe.src = origin+location.pathname.replace(/[^\/]*$/,'HELPER-showorigin.html');
+	document.body.insertBefore(iframe,document.getElementsByTagName('div')[0]);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+		<p>Drag a small file from your computer onto the blue square and release it. If a prompt appears, accept it. The blue square should be replaced with the text:<br>
+		<span></span></p>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/117-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/117-manual.html
new file mode 100644
index 0000000..d126fda
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/117-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin for site with document.domain set to a parent domain</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'http://'+httpHostAlias+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/118-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/118-manual.html
new file mode 100644
index 0000000..6b93169
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/118-manual.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+	<head>
+		<title>Origin after leaving browser window</title>
+		<style type="text/css">
+html, body, iframe { display: block; width: 100%; height: 100%; border: none; margin: 0; padding: 0; }
+		</style>
+		<script type="text/javascript" src="../resources/crossorigin.sub.js"></script>
+		<script type="text/javascript">
+window.onload = function () {
+	var origin = 'http://'+httpHostMain;
+	if( location.href.indexOf(origin+'/') ) {
+		document.body.innerHTML = 'This must be tested on '+origin+'/';
+		return;
+	}
+	var iframe = document.createElement('iframe');
+	iframe.src = 'http://'+httpHostMain+':'+httpPortAlias+location.pathname.replace(/.html$/,'-1.html');
+	document.body.appendChild(iframe);
+};
+		</script>
+	</head>
+	<body>
+
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+
+	</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/201-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/201-manual.html
new file mode 100644
index 0000000..a687147
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/editing/dnd/target-origin/201-manual.html
@@ -0,0 +1,83 @@
+<!doctype html>
+<html>
+	<head>
+		<title>allowTargetOrigin with real dataTransfer should block dragenter, dragover, dragleave and drop synthetic events</title>
+		<style type="text/css">
+p + div { height: 100px; width: 100px; background: orange; }
+		</style>
+		<script type="text/javascript">
+window.onload = function () {
+	var orange = document.getElementsByTagName('div')[0], targ = document.getElementsByTagName('div')[1], evtdone = {}, fails = [];
+	orange.ondragstart = function (e) {
+		var evt;
+		e.dataTransfer.effectAllowed = 'copy';
+		e.dataTransfer.setData('text','dummy text');
+		try {
+			e.dataTransfer.allowTargetOrigin('http://example.com');
+		} catch(e) {
+			fails[fails.length] = 'allowTargetOrigin threw an error: '+e;
+		}
+		try {
+   evt = new DragEvent('dragstart', {dataTransfer:e.dataTransfer});
+			targ.dispatchEvent(evt);
+   evt = new DragEvent('drag', {dataTransfer:e.dataTransfer});
+			targ.dispatchEvent(evt);
+   evt = new DragEvent('dragenter', {dataTransfer:e.dataTransfer});
+			targ.dispatchEvent(evt);
+   evt = new DragEvent('dragover', {dataTransfer:e.dataTransfer});
+			targ.dispatchEvent(evt);
+   evt = new DragEvent('dragleave', {dataTransfer:e.dataTransfer});
+			targ.dispatchEvent(evt);
+   evt = new DragEvent('drop', {dataTransfer:e.dataTransfer});
+			targ.dispatchEvent(evt);
+   evt = new DragEvent('dragend', {dataTransfer:e.dataTransfer});
+			targ.dispatchEvent(evt);
+		} catch(e) {
+			fails[fails.length] = 'Synthetic event threw an error: '+e;
+		}
+		if( !evtdone.dragstart ) {
+			fails[fails.length] = 'dragstart did not fire';
+		}
+		if( !evtdone.drag ) {
+			fails[fails.length] = 'drag did not fire';
+		}
+		if( !evtdone.dragend ) {
+			fails[fails.length] = 'dragend did not fire';
+		}
+		if( evtdone.dragenter ) {
+			fails[fails.length] = 'dragenter fired';
+		}
+		if( evtdone.dragover ) {
+			fails[fails.length] = 'dragover fired';
+		}
+		if( evtdone.dragleave ) {
+			fails[fails.length] = 'dragleave fired';
+		}
+		if( evtdone.drop ) {
+			fails[fails.length] = 'drop fired';
+		}
+		document.getElementsByTagName('p')[0].innerHTML = fails.length ? ( 'FAIL:<br>' + fails.join('<br>') ) : 'PASS';
+	};
+	targ.ondragstart = function (e) {
+		evtdone[e.type] = true;
+	};
+	targ.ondragenter = targ.ondragover = targ.ondrop = function (e) {
+		e.preventDefault();
+		evtdone[e.type] = true;
+	};
+	targ.ondrag = targ.ondragleave = function (e) {
+		evtdone[e.type] = true;
+	};
+	targ.ondragend = function (e) {
+		evtdone[e.type] = true;
+	};
+};
+		</script>
+	</head>
+	<body>
+		<p>Drag the orange square to the right until the drag placeholder appears, then release it. Fail if this text does not change.</p>
+		<div draggable="true"></div>
+		<div></div>
+		<noscript><p>Enable JavaScript and reload</p></noscript>
+	</body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-down-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-down-manual.html
new file mode 100644
index 0000000..a9d4a7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-down-manual.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: marquee-direction-down</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/multipage/obsolete.html#the-marquee-element">
+<meta name="assert" content="Check if the marquee direction is from top to bottom">
+<p>Test passes if the text "Test Marquee" moves from top to bottom.</p>
+<marquee direction="down">Test Marquee</marquee>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-left-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-left-manual.html
new file mode 100644
index 0000000..cf08cca
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-left-manual.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: marquee-direction-left</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/multipage/obsolete.html#the-marquee-element">
+<meta name="assert" content="Check if the marquee direction is from right to left">
+<p>Test passes if the text "Test Marquee" moves from right to left.</p>
+<marquee direction="left">Test Marquee</marquee>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-right-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-right-manual.html
new file mode 100644
index 0000000..b42c9454
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-right-manual.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: marquee-direction-right</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/multipage/obsolete.html#the-marquee-element">
+<meta name="assert" content="Check if the marquee direction is from left to right">
+<p>Test passes if the text "Test Marquee" moves from left to right.</p>
+<marquee direction="right">Test Marquee</marquee>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-up-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-up-manual.html
new file mode 100644
index 0000000..040609f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-direction-up-manual.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: marquee-direction-up</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/multipage/obsolete.html#the-marquee-element">
+<meta name="assert" content="Check if the marquee direction is from bottom to top">
+<p>Test passes if the text "Test Marquee" moves from bottom to top.</p>
+<marquee direction="up">Test Marquee</marquee>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-scrollamount-effect-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-scrollamount-effect-manual.html
new file mode 100644
index 0000000..ad7ff0f3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-scrollamount-effect-manual.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: marquee-scrollamount-effect</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/multipage/obsolete.html#the-marquee-element">
+<meta name="assert" content="Check the effect of scrollamount attribute">
+<p>Test passes if the text "Test2" moves faster than the text "Test1".</p>
+<marquee id="test1">Test1</marquee>
+<marquee scrollamount="10" id="test2">Test2</marquee>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-start-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-start-manual.html
new file mode 100644
index 0000000..51b4289b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-start-manual.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: marquee-start</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/multipage/obsolete.html#the-marquee-element">
+<meta name="flags" content="interact">
+<meta name="assert" content="Check the start operation of HTMLMarqueeElement interface">
+<h2>Steps:</h2>
+<ol>
+  <li>Click the 'Start' button to start the marquee element.</li>
+</ol>
+<h2>Expected result:</h2>
+<ul>
+  <li>The text "Test Marquee" start to move when the 'Start' button is clicked.</li>
+</ul>
+<input type="button" id="start" value="Start" />
+<marquee id="test">Test Marquee</marquee>
+<script>
+  document.getElementById("test").stop();
+  document.getElementById("start").addEventListener("click", function(evt) {
+    document.getElementById("test").start();
+  }, false);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-stop-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-stop-manual.html
new file mode 100644
index 0000000..57a4e73e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/obsolete/requirements-for-implementations/the-marquee-element-0/marquee-stop-manual.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: marquee-stop</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/multipage/obsolete.html#the-marquee-element">
+<meta name="flags" content="interact">
+<meta name="assert" content="Check the stop operation of HTMLMarqueeElement interface">
+<h2>Steps:</h2>
+<ol>
+  <li>Click the 'Start' button to start the marquee element.</li>
+</ol>
+<h2>Expected result:</h2>
+<ul>
+  <li>The text "Test Marquee" stop moving when the 'Stop' button is clicked.</li>
+</ul>
+<input type="button" id="stop" value="Stop" />
+<marquee id="test">Test Marquee</marquee>
+<script>
+  document.getElementById("stop").addEventListener("click", function(evt) {
+    document.getElementById("test").stop();
+  }, false);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html
index 142024e..01df0c54 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/replaced-elements/embedded-content-rendering-rules/canvas-fallback.html
@@ -3,6 +3,10 @@
 <title>Canvas fallback content</title>
 <link rel=match href=canvas-fallback-ref.html>
 <style>
+canvas {
+  height: 2em; /* avoid causing scrollbar for 600x600 viewport */
+}
+
 #canvas2 {
   display: inline;
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_controls_present-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_controls_present-manual.html
new file mode 100644
index 0000000..38faa4d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_controls_present-manual.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Audio Test: audio_controls_present.html</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-controls" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the controls attribute is present in the audio element that expecting the user agent exposes a controller user interface" />
+  </head>
+  <body>
+    <p>Test passes if a controller user interface appears below and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <audio id="m" controls>The user agent doesn't support media element.</audio>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_muted_overriding_volume-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_muted_overriding_volume-manual.html
new file mode 100644
index 0000000..cc1892ce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_muted_overriding_volume-manual.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Audio Test: audio_muted_overriding_volume</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-muted" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the muted attribute is present in the audio element with volume is set to loudest that expecting the user hears no sound" />
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <p>Test passes if the audio is playing without sound output and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <audio id="m" controls muted>The user agent doesn't support media element.</audio>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        media.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+        media.volume = 1.0;
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_muted_present-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_muted_present-manual.html
new file mode 100644
index 0000000..16d6f07
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_muted_present-manual.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Audio Test: audio_muted_present</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-muted" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the muted attribute is present in the audio element that expecting the user hears no sound" />
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <p>Test passes if the audio is playing without sound output and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <audio id="m" controls muted>The user agent doesn't support media element.</audio>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        media.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_loudest-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_loudest-manual.html
new file mode 100644
index 0000000..a623e8f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_loudest-manual.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Audio Test: audio_volume_loudest</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-volume" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the volume attribute is set to 1.0 as loudest in the audio element that expecting the user hears sound loudly" />
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <p>Test passes if the audio is playing with sound heard and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <audio id="m" controls>The user agent doesn't support media element.</audio>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        media.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+        media.volume = 1.0;
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_silent-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_silent-manual.html
new file mode 100644
index 0000000..257bd46
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/audio_volume_silent-manual.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Audio Test: audio_volume_silent</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-volume" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the volume attribute is set to 0.0 as silent in the audio element that expecting the user hears no sound" />
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <p>Test passes if the audio is playing without sound heard and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <audio id="m" controls volume=0.0>The user agent doesn't support media element.</audio>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        media.src = getAudioURI("/media/sound_5") + "?" + new Date() + Math.random();
+        media.volume = 0.0;
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_controls_present-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_controls_present-manual.html
new file mode 100644
index 0000000..8e44951
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_controls_present-manual.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Video Test: video_controls_present.html</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-controls" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the controls attribute is present in the video element that expecting the user agent exposes a controller user interface" />
+  </head>
+  <body>
+    <p>Test passes if a controller user interface appears below and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <video id="m" controls>The user agent doesn't support media element.</video>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_muted_overriding_volume-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_muted_overriding_volume-manual.html
new file mode 100644
index 0000000..6d77066
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_muted_overriding_volume-manual.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Video Test: video_muted_overriding_volume</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-muted" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the muted attribute is present in the video element with volume is set to loudest that expecting the user hears no sound" />
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <p>Test passes if the video is playing without sound output and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <video id="m" controls muted>The user agent doesn't support media element.</video>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        media.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+        media.volume = 1.0;
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_muted_present-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_muted_present-manual.html
new file mode 100644
index 0000000..bc808277
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_muted_present-manual.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Video Test: video_muted_present</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-muted" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the muted attribute is present in the video element that expecting the user hears no sound" />
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <p>Test passes if the video is playing without sound output and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <video id="m" controls muted>The user agent doesn't support media element.</video>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        media.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_loudest-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_loudest-manual.html
new file mode 100644
index 0000000..7475781
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_loudest-manual.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Video Test: video_volume_loudest</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-volume" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the volume attribute is set to 1.0 as loudest in the video element that expecting the user hears sound loudly" />
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <p>Test passes if the video is playing with sound heard and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <video id="m" controls>The user agent doesn't support media element.</video>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        media.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+        media.volume = 1.0;
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_silent-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_silent-manual.html
new file mode 100644
index 0000000..1768dd4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/embedded-content/media-elements/video_volume_silent-manual.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Video Test: video_volume_silent</title>
+    <link rel="author" title="Intel" href="http://www.intel.com" />
+    <link rel="help" href="https://html.spec.whatwg.org/multipage/#dom-media-volume" />
+    <meta name="flags" content="" />
+    <meta name="assert" content="Check if the volume attribute is set to 0.0 as silent in the video element that expecting the user hears no sound" />
+    <script src="/common/media.js"></script>
+  </head>
+  <body>
+    <p>Test passes if the video is playing without sound heard and the text 'The user agent doesn't support media element.' does not appear anywhere on this page</p>
+    <video id="m" controls volume=0.0>The user agent doesn't support media element.</video>
+    <script type="text/javascript">
+        var media = document.getElementById("m");
+        media.src = getVideoURI("/media/movie_5") + "?" + new Date() + Math.random();
+        media.volume = 0.0;
+        media.play();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl-manual.html
new file mode 100644
index 0000000..cb00f69
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/attributes-common-to-form-controls/dirname-rtl-manual.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Submitting element directionality: the dirname attribute (rtl)</title>
+<link rel="author" title="Denis Ah-Kang" href="mailto:denis@w3.org">
+<link rel=help href="https://html.spec.whatwg.org/multipage/#submitting-element-directionality:-the-dirname-attribute">
+<form action="dirname-rtl-manual.html" method=get>
+  <p><label>Comment: <input type=text name="comment" dirname="comment.dir" required></label></p>
+  <p><button type=submit>Post Comment</button></p>
+</form>
+<p>Switch to a right-to-left writing direction, enter a text in the input and submit the form.</p>
+<p>Test passes if the word "PASS" appears below</p>
+<script>
+  function getParameterByName(name) {
+    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
+    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
+    results = regex.exec(location.search);
+    return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
+  }
+
+  var commentDir = getParameterByName("comment.dir");
+  if (commentDir) {
+    var p = document.createElement("p");
+    p.textContent = (commentDir == "rtl") ? "PASS" : "FAIL";
+    document.body.appendChild(p);
+  }
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end.html
new file mode 100644
index 0000000..0638380
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end.html
@@ -0,0 +1,148 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<script>
+  function createInputElement(value, append, suffix) {
+    var el = document.createElement("input");
+    el.type = "text";
+    el.value = value;
+    el.id = "input" + (append ? "-appended" : "-not-appended") + (suffix ? suffix : "");
+    if (append) {
+      document.body.appendChild(el);
+    }
+    return el;
+  };
+
+  function createTextareaElement(value, append, suffix) {
+    var el = document.createElement("textarea");
+    el.value = value;
+
+    el.id = "textarea" + (append ? "-appended" : "-not-appended") + (suffix ? suffix : "");
+    if (append) {
+      document.body.appendChild(el);
+    }
+    return el;
+  };
+
+  function createPrefocusedInputElement(value, append) {
+    var el = createInputElement(value, append, "-prefocused");
+    el.focus();
+    el.blur();
+    return el;
+  }
+
+  function createPrefocusedTextareaElement(value, append) {
+    var el = createTextareaElement(value, append, "-prefocused");
+    el.focus();
+    el.blur();
+    return el;
+  }
+
+  function createTestElements(value) {
+    return [ createInputElement(value, true),
+             createInputElement(value, false),
+             createPrefocusedInputElement(value, true),
+             createPrefocusedInputElement(value, false),
+             createTextareaElement(value, true),
+             createTextareaElement(value, false),
+             createPrefocusedTextareaElement(value, true),
+             createPrefocusedTextareaElement(value, false),
+           ];
+  }
+
+  var testValue = "abcdefghij";
+
+  test(function() {
+    assert_equals(testValue.length, 10);
+  }, "Sanity check for testValue length; if this fails, variou absolute offsets in the test below need to be adjusted to be less than testValue.length");
+
+  test(function() {
+    for (let el of createTestElements(testValue)) {
+      assert_equals(el.selectionStart, testValue.length,
+                    `Initial .value set on ${el.id} should set selectionStart to end of value`);
+      var t = async_test(`onselect should fire when selectionStart is changed on ${el.id}`);
+      el.onselect = t.step_func_done(function(e) {
+        assert_equals(e.type, "select");
+        el.remove();
+      });
+      el.selectionStart = 2;
+    }
+  }, "onselect should fire when selectionStart is changed");
+
+  test(function() {
+    for (let el of createTestElements(testValue)) {
+      assert_equals(el.selectionEnd, testValue.length,
+                    `Initial .value set on ${el.id} should set selectionEnd to end of value`);
+      var t = async_test(`onselect should fire when selectionEnd is changed on ${el.id}`);
+      el.onselect = t.step_func_done(function(e) {
+        assert_equals(e.type, "select");
+        el.remove();
+      });
+      el.selectionEnd = 2;
+    }
+  }, "onselect should fire when selectionEnd is changed");
+
+  test(function() {
+    for (let el of createTestElements(testValue)) {
+      assert_equals(el.selectionStart, testValue.length,
+                    `Initial .value set on ${el.id} should set selectionStart to end of value`);
+      el.selectionStart = 0;
+      el.selectionEnd = 5;
+      el.selectionStart = 8;
+      assert_equals(el.selectionStart, 8, `selectionStart on ${el.id}`);
+      assert_equals(el.selectionEnd, 8, `selectionEnd on ${el.id}`);
+      el.remove();
+    }
+  }, "Setting selectionStart to a value larger than selectionEnd should increase selectionEnd");
+
+  test(function() {
+    for (let el of createTestElements(testValue)) {
+      assert_equals(el.selectionStart, testValue.length,
+                    `Initial .value set on ${el.id} should set selectionStart to end of value`);
+      assert_equals(el.selectionEnd, testValue.length,
+                    `Initial .value set on ${el.id} should set selectionEnd to end of value`);
+      el.selectionStart = 8;
+      el.selectionEnd = 5;
+      assert_equals(el.selectionStart, 5, `selectionStart on ${el.id}`);
+      assert_equals(el.selectionEnd, 5, `selectionEnd on ${el.id}`);
+      el.remove();
+    }
+  }, "Setting selectionEnd to a value smaller than selectionStart should decrease selectionStart");
+
+  test(function() {
+    for (let el of createTestElements(testValue)) {
+      el.selectionStart = 0;
+      assert_equals(el.selectionStart, 0, `We just set it on ${el.id}`);
+      el.selectionStart = -1;
+      assert_equals(el.selectionStart, testValue.length,
+                    `selectionStart setter on ${el.id} should convert -1 to 2^32-1`);
+      el.selectionStart = Math.pow(2, 32);
+      assert_equals(el.selectionStart, 0,
+                    `selectionStart setter on ${el.id} should convert 2^32 to 0`);
+      el.selectionStart = Math.pow(2, 32) - 1;
+      assert_equals(el.selectionStart, testValue.length,
+                    `selectionStart setter on ${el.id} should leave 2^32-1 as-is`);
+      el.remove();
+    }
+  }, "selectionStart edge-case values");
+
+  test(function() {
+    for (let el of createTestElements(testValue)) {
+      el.selectionEnd = 0;
+      assert_equals(el.selectionEnd, 0, `We just set it on ${el.id}`);
+      el.selectionEnd = -1;
+      assert_equals(el.selectionEnd, testValue.length,
+                    `selectionEnd setter on ${el.id} should convert -1 to 2^32-1`);
+      el.selectionEnd = Math.pow(2, 32);
+      assert_equals(el.selectionEnd, 0,
+                    `selectionEnd setter on ${el.id} should convert 2^32 to 0`);
+      el.selectionEnd = Math.pow(2, 32) - 1;
+      assert_equals(el.selectionEnd, testValue.length,
+                    `selectionEnd setter on ${el.id} should leave 2^32-1 as-is`);
+      el.remove();
+    }
+  }, "selectionEnd edge-case values");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-value-interactions.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-value-interactions.html
new file mode 100644
index 0000000..5aba3d2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-value-interactions.html
@@ -0,0 +1,95 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<div id=target></div>
+<script>
+  var target = document.getElementById("target");
+  var sometext = "something";
+  var shorttext = "abc";
+  var elemData = [
+    {
+      desc: "textarea not in body",
+      factory: () => document.createElement("textarea"),
+    },
+    {
+      desc: "input not in body",
+      factory: () => document.createElement("input"),
+    },
+    {
+      desc: "textarea in body",
+      factory: () => document.body.appendChild(document.createElement("textarea")),
+    },
+    {
+      desc: "input in body",
+      factory: () => document.body.appendChild(document.createElement("input")),
+    },
+    {
+      desc: "textarea in body with parsed default value",
+      factory: () => {
+        target.innerHTML = "<textarea>abcdefghij</textarea>"
+        return target.querySelector("textarea");
+      },
+    },
+    {
+      desc: "input in body with parsed default value",
+      factory: () => {
+        target.innerHTML = "<input value='abcdefghij'>"
+        return target.querySelector("input");
+      },
+    },
+    {
+      desc: "focused textarea",
+      factory: () => {
+        var t = document.body.appendChild(document.createElement("textarea"));
+        t.focus();
+        return t;
+      },
+    },
+    {
+      desc: "focused input",
+      factory: () => {
+        var i = document.body.appendChild(document.createElement("input"));
+        i.focus();
+        return i;
+      },
+    },
+    {
+      desc: "focused then blurred textarea",
+      factory: () => {
+        var t = document.body.appendChild(document.createElement("textarea"));
+        t.focus();
+        t.blur();
+        return t;
+      },
+    },
+    {
+      desc: "focused then blurred input",
+      factory: () => {
+        var i = document.body.appendChild(document.createElement("input"));
+        i.focus();
+        i.blur()
+        return i;
+      },
+    },
+  ];
+
+for (var data of elemData) {
+  test(function() {
+    var el = data.factory();
+    this.add_cleanup(() => el.remove());
+    el.defaultValue = sometext;
+    assert_true(sometext.length > 8,
+                "sometext too short, test won't work right");
+    el.selectionStart = 4;
+    el.selectionEnd = 6;
+    el.setRangeText("xyz");
+    el.defaultValue = "set range text";
+    assert_equals(el.value, sometext.slice(0, 4) + "xyz" + sometext.slice(6),
+                  "Calling setRangeText should set the value dirty flag");
+  }, `value dirty flag behavior after setRangeText on ${data.desc}`);
+}
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection.html
index 709d26e8..b5cea05 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection.html
@@ -14,18 +14,24 @@
   var dirs = ['forward', 'backward', 'none'];
   var sampleText = "0123456789";
 
-  var createInputElement = function(value) {
+  var createInputElement = function(value, append = true) {
     var el = document.createElement("input");
     el.type = "text";
     el.value = value;
-    body.appendChild(el);
+    el.id = "input" + (append ? "-appended" : "-not-appended");
+    if (append) {
+      body.appendChild(el);
+    }
     return el;
   };
 
-  var createTextareaElement = function(value) {
+  var createTextareaElement = function(value, append = true) {
     var el = document.createElement("textarea");
     el.value = value;
-    body.appendChild(el);
+    el.id = "textarea" + (append ? "-appended" : "-not-appended");
+    if (append) {
+      body.appendChild(el);
+    }
     return el;
   };
 
@@ -82,49 +88,74 @@
   }, "test if non-ascii selection text is correct for textarea");
 
 
-  test(function() {
-    var el = createInputElement(sampleText);
-    // If there is no selection, then it must return the offset(in logical order)
-    // to the character that immediately follows the text entry cursor.
-    assert_equals(el.selectionStart, el.value.length, "SelectionStart offset without selection");
-    el.select();
-    assert_equals(el.selectionStart, 0, "SelectionStart offset");
-    el.parentNode.removeChild(el);
-  }, "test SelectionStart offset for input");
+  for (var append of [true, false]) {
+    test(function() {
+      var el = createInputElement(sampleText, append);
+      // If there is no selection, then it must return the offset(in logical order)
+      // to the character that immediately follows the text entry cursor.
+      assert_equals(el.selectionStart, el.value.length,
+                    "SelectionStart offset without selection in " + el.id);
+      if (!el.parentNode) {
+        return;
+      }
+      el.select();
+      assert_equals(el.selectionStart, 0, "SelectionStart offset");
+      el.parentNode.removeChild(el);
+    }, "test SelectionStart offset for input that is " +
+         (append ? "appended" : " not appended"));
+  }
+
+  for (var append of [true, false]) {
+    test(function() {
+      var el = createTextareaElement(sampleText, append);
+      // If there is no selection, then it must return the offset(in logical order)
+      // to the character that immediately follows the text entry cursor.
+      assert_equals(el.selectionStart, el.value.length,
+                    "SelectionStart offset without selection in " + el.id);
+      if (!el.parentNode) {
+        return;
+      }
+      el.select();
+      assert_equals(el.selectionStart, 0, "SelectionStart offset");
+      el.parentNode.removeChild(el);
+    }, "test SelectionStart offset for textarea that is " +
+         (append ? "appended" : " not appended"));
+  }
+
+  for (var append of [true, false]) {
+    test(function() {
+      var el = createInputElement(sampleText, append);
+      // If there is no selection, then it must return the offset(in logical order)
+      // to the character that immediately follows the text entry cursor.
+      assert_equals(el.selectionEnd, el.value.length,
+                    "SelectionEnd offset without selection in " + el.id);
+      if (!el.parentNode) {
+        return;
+      }
+      el.select();
+      assert_equals(el.selectionEnd, el.value.length, "SelectionEnd offset");
+      el.parentNode.removeChild(el);
+    }, "test SelectionEnd offset for input that is " +
+         (append ? "appended" : " not appended"));
+  }
 
 
-  test(function() {
-    var el = createTextareaElement(sampleText);
-    // If there is no selection, then it must return the offset(in logical order)
-    // to the character that immediately follows the text entry cursor.
-    assert_equals(el.selectionStart, el.value.length, "SelectionStart offset without selection");
-    el.select();
-    assert_equals(el.selectionStart, 0, "SelectionStart offset");
-    el.parentNode.removeChild(el);
-  }, "test SelectionStart offset for textarea");
-
-
-  test(function() {
-    var el = createInputElement(sampleText);
-    // If there is no selection, then it must return the offset(in logical order)
-    // to the character that immediately follows the text entry cursor.
-    assert_equals(el.selectionEnd, el.value.length, "SelectionEnd offset without selection");
-    el.select();
-    assert_equals(el.selectionEnd, el.value.length, "SelectionEnd offset");
-    el.parentNode.removeChild(el);
-  }, "test SelectionEnd offset for input");
-
-
-  test(function() {
-    var el = createTextareaElement(sampleText);
-    // If there is no selection, then it must return the offset(in logical order)
-    // to the character that immediately follows the text entry cursor.
-    assert_equals(el.selectionEnd, el.value.length, "SelectionEnd offset without selection");
-    el.select();
-    assert_equals(el.selectionEnd, el.value.length, "SelectionEnd offset");
-    el.parentNode.removeChild(el);
-  }, "test SelectionEnd offset for textarea");
-
+  for (var append of [true, false]) {
+    test(function() {
+      var el = createTextareaElement(sampleText, append);
+      // If there is no selection, then it must return the offset(in logical order)
+      // to the character that immediately follows the text entry cursor.
+      assert_equals(el.selectionEnd, el.value.length,
+                    "SelectionEnd offset without selection in " + el.id);
+      if (!el.parentNode) {
+        return;
+      }
+      el.select();
+      assert_equals(el.selectionEnd, el.value.length, "SelectionEnd offset");
+      el.parentNode.removeChild(el);
+    }, "test SelectionEnd offset for textarea that is " +
+         (append ? "appended" : " not appended"));
+  }
 
   test(function() {
     var el = createInputElement(sampleText);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html
index 636d282..a46b83f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html
@@ -104,5 +104,26 @@
         element.setRangeText();
       });
     }, element.id + " setRangeText without argument throws a type error");
+
+    async_test(function() {
+      // At this point there are already "select" events queued up on
+      // "element".  Give them time to fire; otherwise we can get spurious
+      // passes.
+      //
+      // This is unfortunately racy in that we might _still_ get spurious
+      // passes.  I'm not sure how best to handle that.
+      setTimeout(this.step_func(function() {
+        var q = false;
+        element.onselect = this.step_func_done(function(e) {
+          assert_true(q, "event should be queued");
+          assert_true(e.isTrusted, "event is trusted");
+          assert_true(e.bubbles, "event bubbles");
+          assert_false(e.cancelable, "event is not cancelable");
+        });
+        element.setRangeText("foobar2", 0, 6);
+        q = true;
+      }), 10);
+    }, element.id + " setRangeText fires a select event");
+
   })
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html
index 493cfdd..86508762 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html
@@ -138,6 +138,22 @@
     assert_equals(input.selectionStart, 0, "element.selectionStart should be 0");
     assert_equals(input.selectionEnd, 1, "element.selectionEnd should be 1");
   },'input setSelectionRange(undefined,1)');
+
+  test(function() {
+    input.setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1);
+    assert_equals(input.selectionStart, input.value.length,
+                 "element.selectionStart should be value.length");
+    assert_equals(input.selectionEnd, input.value.length,
+                  "element.selectionEnd should be value.length");
+  }, 'input setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1)');
+
+  test(function() {
+    input.setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1);
+    assert_equals(input.selectionStart, input.value.length,
+                 "element.selectionStart should be value.length");
+    assert_equals(input.selectionEnd, input.value.length,
+                  "element.selectionEnd should be value.length");
+  }, 'input setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1)');
 },"test of input.setSelectionRange");
 
 async_test(function() {
@@ -257,5 +273,21 @@
     assert_equals(textarea.selectionStart, 0, "element.selectionStart should be 0");
     assert_equals(textarea.selectionEnd, 1, "element.selectionStart should be 1");
   },'textarea setSelectionRange(undefined,1)');
+
+  test(function() {
+    textarea.setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1);
+    assert_equals(textarea.selectionStart, textarea.value.length,
+                 "element.selectionStart should be value.length");
+    assert_equals(textarea.selectionEnd, textarea.value.length,
+                  "element.selectionEnd should be value.length");
+  }, 'textarea setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1)');
+
+  test(function() {
+    textarea.setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1);
+    assert_equals(textarea.selectionStart, textarea.value.length,
+                 "element.selectionStart should be value.length");
+    assert_equals(textarea.selectionEnd, textarea.value.length,
+                  "element.selectionEnd should be value.length");
+  }, 'textarea setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1)');
 },"test of textarea.setSelectionRange");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-optgroup-element/optgroup-disabled-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-optgroup-element/optgroup-disabled-manual.html
new file mode 100644
index 0000000..ca8c6cd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-optgroup-element/optgroup-disabled-manual.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTMLOptGroupElement Test: disabled</title>
+<meta name="flags" content="interact">
+<link rel="author" title="Intel" href="http://www.intel.com/">
+
+<form>
+  <select>
+    <optgroup label="8.01" disabled>
+      <option value="8.01.1">Lecture 01: Powers of Ten</option>
+      <option value="8.01.2">Lecture 02: 1D Kinematics</option>
+      <option value="8.01.3">Lecture 03: Vectors</option>
+    </optgroup>
+    <optgroup label="8.02">
+      <option value="8.02.1">Lecture 01: What holds our world together?</option>
+      <option value="8.02.2">Lecture 02: Electric Field</option>
+      <option value="8.02.3">Lecture 03: Electric Flux</option>
+    </optgroup>
+  </select>
+</form>
+
+<h2>Description</h2>
+<p>
+  This test validates that an optgroup element is disabled if its disabled attribute is present.
+</p>
+
+<h2>Test steps:</h2>
+<ol>
+  <li>
+    Click the select flag to select section '8.01'
+  </li>
+</ol>
+
+<h2>Result:</h2>
+<p>Click the select flag and try to select section 8.01, test passes if the section 8.01 is disable to be selected</p>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-option-element/option-disabled-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-option-element/option-disabled-manual.html
new file mode 100644
index 0000000..25dfcc8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-option-element/option-disabled-manual.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTMLOptionElement Test: disabled</title>
+<meta name="flags" content="interact">
+<link rel="author" title="Intel" href="http://www.intel.com/">
+
+<div>
+  <select>
+    <option id="testOption1" text="Option1" >Option1</option>
+    <option id="testOption2" disabled >Option2</option>
+    <option id="testOption3" >Option3</option>
+  </select>
+</div>
+
+<h2>Description</h2>
+<p>
+  This test validates that an option element is disabled if its disabled attribute is present.
+</p>
+
+<h2>Test steps:</h2>
+<ol>
+  <li>
+    Click the select flag to select 'Option2'
+  </li>
+</ol>
+
+<h2>Result:</h2>
+<p>Test passes if not able to select 'Option2'</p>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/textarea-placeholder-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/textarea-placeholder-manual.html
new file mode 100644
index 0000000..d59a259
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/textarea-placeholder-manual.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: textarea - placeholder attribute</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#attr-textarea-placeholder">
+<meta name="flags" content="interact">
+<body>
+  <p>
+    Test passes if there is a "Placeholder Text" in the text area,
+    and if the "Placeholder Text" disappears after type in any character.
+  </p>
+  <textarea placeholder="Placeholder Text"></textarea>
+</body>
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/textarea-select-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/textarea-select-manual.html
new file mode 100644
index 0000000..4e98ba50
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/the-textarea-element/textarea-select-manual.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTMLTextAreaElement Test: select()</title>
+<link rel="author" title="Intel" href="http://www.intel.com/">
+<meta name="flags" content="interact">
+
+<p>Test passes if content of the input area is selected</p>
+
+<textarea id="test_obj">1234567</textarea>
+<script>
+var textarea = document.querySelector("#test_obj");
+textarea.select();
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html
index 3f282672..0f4195ff 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/scripting-1/the-script-element/module/execorder.html
@@ -2,6 +2,7 @@
 <html>
 <head>
     <title>html-script-module-execOrder</title>
+    <meta name=timeout content=long>
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
     <script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/selectors/pseudo-classes/checked-001-manual.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/selectors/pseudo-classes/checked-001-manual.html
new file mode 100644
index 0000000..76a963a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/selectors/pseudo-classes/checked-001-manual.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
+<html>
+ <head>
+  <title>CSS Selectors (:checked)</title>
+  <link rel="author" title="Ian Hickson" href="mailto:ian@hixie.ch"/>
+  <link rel="alternate" href="http://www.hixie.ch/tests/adhoc/css/selectors/checked/001.html"/>
+    <style type="text/css">
+   :checked, :checked + span { border: solid blue; color: blue; background: navy; }
+  </style>
+ </head>
+ <body>
+  <p>Anything that is checked below should be blue.</p>
+  <p><input checked type="checkbox"> <span>X</span></p>
+  <p><input checked type="radio" name="x"> <span>X</span> <input checked type="radio" name="x"> <span>X</span></p>
+  <p><select><option selected>X</option></select></p>
+  <p><select size="2"><option selected>X</option></select></p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-idle-periods.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-idle-periods.html
index ed8bd88..c066c605 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-idle-periods.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-idle-periods.html
@@ -6,38 +6,6 @@
 <script>
 
 async_test(function() {
-  // Check that two separate calls to requestIdleCallbacks can run in the same
-  // idle period.
-  var callback_1_deadline;
-  var callback_1_has_run = false;
-  var callback_1 = function(deadline) {
-    callback_1_has_run = true;
-    var remaining = deadline.timeRemaining();
-    if (remaining >= 5) {
-      // Should be enough time to run the next callback in the current idle
-      // period.
-      callback_1_deadline = performance.now() + remaining;
-    }
-  };
-  var callback_2 = this.step_func(function(deadline) {
-    assert_true(callback_1_has_run, "Should run callbacks in order of posting if they don't have a timeout.");
-    if (callback_1_deadline != undefined) {
-      assert_true(performance.now() < callback_1_deadline, "Should be able to run both callbacks in the same idle period.");
-      this.done();
-    } else {
-      // Might not have had enough idle time, so try again.
-      callback_1_has_run = false;
-      setTimeout(function() {
-        requestIdleCallback(callback_1);
-        requestIdleCallback(callback_2);
-      }, 0);
-    }
-  });
-  requestIdleCallback(callback_1);
-  requestIdleCallback(callback_2);
-}, 'requestIdleCallback can run multiple different requestIdleCallback callbacks in the same idle period.');
-
-async_test(function() {
   // Check that if an idle callback calls requestIdleCallback, the new callback
   // doesn't get the same deadline (i.e., runs in a new idle period).
   var previous_deadline = undefined;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-removed-frame.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-removed-frame.html
new file mode 100644
index 0000000..ca63f68f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/idle-callbacks/callback-removed-frame.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>requestIdleCallback on removed frame shouldn't call back</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+  async_test(function (t) {
+    assert_false(document.hidden, "document.hidden must exist and be false to run this test properly");
+
+    function start() {
+      var frame = document.createElement('iframe');
+      frame.addEventListener('load', _ => connect(frame), {once:true});
+      frame.src = "about:blank";
+      document.body.appendChild(frame);
+    }
+
+    function connect(frame) {
+      var contentWindow = frame.contentWindow;
+      contentWindow.requestIdleCallback(_ => callback0(frame, contentWindow));
+      t.step_timeout(function() { t.done(); }, 1000);
+    }
+
+    function callback0(f, w) {
+      document.body.removeChild(f);
+      w.requestIdleCallback(t.unreached_func("requestIdleCallback callback should not trigger the callback"));
+    }
+
+    addEventListener('load', start, {once:true});
+  }, "calling requestIdleCallback on a contentWindow from a removed iframe should not trigger the callback");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/negative-setinterval.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/negative-setinterval.html
new file mode 100644
index 0000000..430d13c5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/negative-setinterval.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>Negative timeout in setInterval</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+var i = 0;
+var interval;
+function next() {
+  i++;
+  if (i === 20) {
+    clearInterval(interval);
+    done();
+  }
+}
+setTimeout(assert_unreached, 1000);
+interval = setInterval(next, -100);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/negative-settimeout.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/negative-settimeout.html
new file mode 100644
index 0000000..57e88ee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/negative-settimeout.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>Negative timeout in setTimeout</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ setTimeout(done, -100);
+ setTimeout(assert_unreached, 10);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/type-long-setinterval.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/type-long-setinterval.html
new file mode 100644
index 0000000..af02995
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/type-long-setinterval.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>Type long timeout for setInterval</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+var interval;
+function next() {
+  clearInterval(interval);
+  done();
+}
+interval = setInterval(next, Math.pow(2, 32));
+setTimeout(assert_unreached, 100);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/type-long-settimeout.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/type-long-settimeout.html
new file mode 100644
index 0000000..31fa4f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/timers/type-long-settimeout.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>Type long timeout for setTimeout</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+setTimeout(done, Math.pow(2, 32));
+setTimeout(assert_unreached, 100);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/BlobEvent-constructor.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/BlobEvent-constructor.html
new file mode 100644
index 0000000..3bcf4296
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/BlobEvent-constructor.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>BlobEvent constructor</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-record/MediaRecorder.html#blob-event">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(function() {
+  assert_equals(BlobEvent.length, 2);
+  assert_throws(new TypeError, function() {
+    new BlobEvent("type");
+  });
+  assert_throws(new TypeError, function() {
+    new BlobEvent("type", null);
+  });
+  assert_throws(new TypeError, function() {
+    new BlobEvent("type", undefined);
+  });
+}, "The BlobEventInit dictionary is required");
+
+test(function() {
+  assert_throws(new TypeError, function() {
+    new BlobEvent("type", {});
+  });
+  assert_throws(new TypeError, function() {
+    new BlobEvent("type", { data: null });
+  });
+  assert_throws(new TypeError, function() {
+    new BlobEvent("type", { data: undefined });
+  });
+}, "The BlobEventInit dictionary's data member is required.");
+
+test(function() {
+  var blob = new Blob();
+  var event = new BlobEvent("type", { data: blob });
+  assert_equals(event.type, "type");
+  assert_equals(event.data, blob);
+}, "The BlobEvent instance's data attribute is set.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness-expected.txt
new file mode 100644
index 0000000..4563c99
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness-expected.txt
@@ -0,0 +1,60 @@
+This is a testharness.js-based test.
+Found 56 tests; 48 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS MediaRecorder interface: existence and properties of interface object 
+PASS MediaRecorder interface object length 
+PASS MediaRecorder interface object name 
+FAIL MediaRecorder interface: existence and properties of interface prototype object assert_equals: class string of MediaRecorder.prototype expected "[object MediaRecorderPrototype]" but got "[object MediaRecorder]"
+PASS MediaRecorder interface: existence and properties of interface prototype object's "constructor" property 
+PASS MediaRecorder interface: attribute stream 
+PASS MediaRecorder interface: attribute mimeType 
+PASS MediaRecorder interface: attribute state 
+PASS MediaRecorder interface: attribute onstart 
+PASS MediaRecorder interface: attribute onstop 
+PASS MediaRecorder interface: attribute ondataavailable 
+PASS MediaRecorder interface: attribute onpause 
+PASS MediaRecorder interface: attribute onresume 
+PASS MediaRecorder interface: attribute onerror 
+PASS MediaRecorder interface: attribute videoBitsPerSecond 
+PASS MediaRecorder interface: attribute audioBitsPerSecond 
+PASS MediaRecorder interface: operation start(long) 
+PASS MediaRecorder interface: operation stop() 
+PASS MediaRecorder interface: operation pause() 
+PASS MediaRecorder interface: operation resume() 
+PASS MediaRecorder interface: operation requestData() 
+PASS MediaRecorder interface: operation isTypeSupported(DOMString) 
+PASS MediaRecorder must be primary interface of [object MediaRecorder] 
+PASS Stringification of [object MediaRecorder] 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "stream" with the proper type (0) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "mimeType" with the proper type (1) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "state" with the proper type (2) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "onstart" with the proper type (3) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "onstop" with the proper type (4) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "ondataavailable" with the proper type (5) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "onpause" with the proper type (6) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "onresume" with the proper type (7) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "onerror" with the proper type (8) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "videoBitsPerSecond" with the proper type (9) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "audioBitsPerSecond" with the proper type (10) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "start" with the proper type (11) 
+PASS MediaRecorder interface: calling start(long) on [object MediaRecorder] with too few arguments must throw TypeError 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "stop" with the proper type (12) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "pause" with the proper type (13) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "resume" with the proper type (14) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "requestData" with the proper type (15) 
+PASS MediaRecorder interface: [object MediaRecorder] must inherit property "isTypeSupported" with the proper type (16) 
+PASS MediaRecorder interface: calling isTypeSupported(DOMString) on [object MediaRecorder] with too few arguments must throw TypeError 
+PASS BlobEvent interface: existence and properties of interface object 
+PASS BlobEvent interface object length 
+PASS BlobEvent interface object name 
+FAIL BlobEvent interface: existence and properties of interface prototype object assert_equals: class string of BlobEvent.prototype expected "[object BlobEventPrototype]" but got "[object BlobEvent]"
+PASS BlobEvent interface: existence and properties of interface prototype object's "constructor" property 
+PASS BlobEvent interface: attribute data 
+PASS BlobEvent interface: attribute timecode 
+FAIL MediaRecorderErrorEvent interface: existence and properties of interface object assert_own_property: self does not have own property "MediaRecorderErrorEvent" expected property "MediaRecorderErrorEvent" missing
+FAIL MediaRecorderErrorEvent interface object length assert_own_property: self does not have own property "MediaRecorderErrorEvent" expected property "MediaRecorderErrorEvent" missing
+FAIL MediaRecorderErrorEvent interface object name assert_own_property: self does not have own property "MediaRecorderErrorEvent" expected property "MediaRecorderErrorEvent" missing
+FAIL MediaRecorderErrorEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "MediaRecorderErrorEvent" expected property "MediaRecorderErrorEvent" missing
+FAIL MediaRecorderErrorEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "MediaRecorderErrorEvent" expected property "MediaRecorderErrorEvent" missing
+FAIL MediaRecorderErrorEvent interface: attribute error assert_own_property: self does not have own property "MediaRecorderErrorEvent" expected property "MediaRecorderErrorEvent" missing
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness.html
new file mode 100644
index 0000000..95f60d737
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-record/idlharness.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset=utf-8>
+  <title>Media Recorder IDL test</title>
+  <link rel="help" href="https://w3c.github.io/mediacapture-record/MediaRecorder.html">
+  <link rel="idl" href="https://w3c.github.io/mediacapture-record/MediaRecorder.html#idl-index">
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/resources/WebIDLParser.js"></script>
+  <script src="/resources/idlharness.js"></script>
+</head>
+<body>
+  <canvas id='canvas' width=10 height=10/>
+
+  <pre id="untested_idl" style="display: none">
+    interface Event {};
+    interface EventHandler {};
+    interface EventTarget {};
+    interface MediaStream {};
+  </pre>
+  <pre id="idl" style="display: none">
+    // https://w3c.github.io/mediacapture-record/MediaRecorder.html
+
+    [Constructor(MediaStream stream, optional MediaRecorderOptions options)]
+    interface MediaRecorder : EventTarget {
+      readonly attribute MediaStream stream;
+      readonly attribute DOMString mimeType;
+      readonly attribute RecordingState state;
+      attribute EventHandler onstart;
+      attribute EventHandler onstop;
+      attribute EventHandler ondataavailable;
+      attribute EventHandler onpause;
+      attribute EventHandler onresume;
+      attribute EventHandler onerror;
+      readonly attribute unsigned long videoBitsPerSecond;
+      readonly attribute unsigned long audioBitsPerSecond;
+
+      void start(optional long timeslice);
+      void stop();
+      void pause();
+      void resume();
+      void requestData();
+
+      static boolean isTypeSupported(DOMString type);
+    };
+
+    dictionary MediaRecorderOptions {
+      DOMString mimeType;
+      unsigned long audioBitsPerSecond;
+      unsigned long videoBitsPerSecond;
+      unsigned long bitsPerSecond;
+    };
+
+    enum RecordingState {
+      "inactive",
+      "recording",
+      "paused"
+    };
+
+    [Constructor(DOMString type, BlobEventInit eventInitDict)]
+    interface BlobEvent : Event {
+      [SameObject] readonly attribute Blob data;
+      readonly attribute DOMHighResTimeStamp timecode;
+    };
+
+    dictionary BlobEventInit {
+      required Blob data;
+      DOMHighResTimeStamp timecode;
+    };
+
+    dictionary MediaRecorderErrorEventInit : EventInit {
+      required DOMException error;
+    };
+
+    [Exposed=Window, Constructor(DOMString type, MediaRecorderErrorEventInit eventInitDict)]
+    interface MediaRecorderErrorEvent : Event {
+      [SameObject] readonly attribute DOMException error;
+    };
+
+  </pre>
+  <script>
+    var canvas = document.getElementById('canvas');
+    var context = canvas.getContext("2d");
+    context.fillStyle = "red";
+    context.fillRect(0, 0, 10, 10);
+    var stream = canvas.captureStream();
+
+    var idl_array = new IdlArray();
+    idl_array.add_untested_idls(document.getElementById("untested_idl").textContent);
+    idl_array.add_idls(document.getElementById("idl").textContent);
+    idl_array.add_objects({
+        MediaRecorder: [new MediaRecorder(stream)],
+      });
+    idl_array.test();
+  </script>
+  <div id="log"></div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js
deleted file mode 100644
index f6838ff..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/resources/error-worker.js
+++ /dev/null
@@ -1,12 +0,0 @@
-var source;
-
-self.addEventListener('message', function(e) {
-  source = e.source;
-  throw 'testError';
-});
-
-self.addEventListener('error', function(e) {
-  source.postMessage({
-    error: e.error, filename: e.filename, message: e.message, lineno: e.lineno,
-    colno: e.colno});
-});
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html
deleted file mode 100644
index 4ccb7572..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/ServiceWorkerGlobalScope/service-worker-error-event.https.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<title>ServiceWorkerGlobalScope: Error event error message</title>
-<script src='/resources/testharness.js'></script>
-<script src='/resources/testharnessreport.js'></script>
-<script src='../resources/test-helpers.sub.js'></script>
-<script>
-promise_test(t => {
-    var script = 'resources/error-worker.js';
-    var scope = 'resources/scope/service-worker-error-event';
-    var error_name = 'testError'
-    return service_worker_unregister_and_register(t, script, scope)
-      .then(registration => {
-          var worker = registration.installing;
-          add_completion_callback(() => { registration.unregister(); });
-          return new Promise(function(resolve) {
-              navigator.serviceWorker.onmessage = resolve;
-              worker.postMessage('');
-            });
-        })
-      .then(e => {
-          assert_equals(e.data.error, error_name, 'error type');
-          assert_greater_than(
-            e.data.message.indexOf(error_name), -1, 'error message');
-          assert_greater_than(
-            e.data.filename.indexOf(script), -1, 'filename');
-          assert_equals(e.data.lineno, 5, 'error line number');
-          assert_equals(e.data.colno, 3, 'error column number');
-        });
-  }, 'Error handlers inside serviceworker should see the attributes of ' + 
-     'ErrorEvent');
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-event-throws-after-respond-with.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-event-throws-after-respond-with.https.html
new file mode 100644
index 0000000..969a3c9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/fetch-event-throws-after-respond-with.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+promise_test(function(t) {
+    var scope = 'resources/fetch-event-throws-after-respond-with-iframe.html';
+    var workerscript = 'resources/respond-then-throw-worker.js';
+    var iframe;
+    return service_worker_unregister_and_register(t, workerscript, scope)
+      .then(function(reg) {
+          return wait_for_state(t, reg.installing, 'activated')
+            .then(() => reg.active);
+        })
+      .then(function(worker) {
+          var channel = new MessageChannel();
+          channel.port1.onmessage = function(e) {
+              assert_equals(e.data, 'SYNC', ' Should receive sync message.');
+              channel.port1.postMessage('ACK');
+            }
+          worker.postMessage({port: channel.port2}, [channel.port2]);
+          // The iframe will only be loaded after the sync is completed.
+          return with_iframe(scope);
+        })
+      .then(function(frame) {
+        assert_true(frame.contentDocument.body.innerHTML.includes("intercepted"));
+        service_worker_unregister_and_done(t, scope);
+      })
+  }, 'Fetch event handler throws after a successful respondWith()');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/postmessage-from-waiting-serviceworker.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/postmessage-from-waiting-serviceworker.https.html
new file mode 100644
index 0000000..6d0a5d3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/postmessage-from-waiting-serviceworker.https.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>Service Worker: postMessage from waiting serviceworker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+
+function echo(worker, data) {
+  return new Promise(resolve => {
+    navigator.serviceWorker.addEventListener('message', function onMsg(evt) {
+      navigator.serviceWorker.removeEventListener('message', onMsg);
+      resolve(evt);
+    });
+    worker.postMessage(data);
+  });
+}
+
+async_test(t => {
+  let script = 'resources/echo-message-to-source-worker.js';
+  let scope = 'resources/client-postmessage-from-wait-serviceworker';
+  let registration;
+  let frame;
+  service_worker_unregister_and_register(t, script, scope)
+    .then(swr => {
+      registration = swr;
+      return wait_for_state(t, registration.installing, 'activated');
+    }).then(_ => {
+      return with_iframe(scope);
+    }).then(f => {
+      frame = f;
+      return navigator.serviceWorker.register(script + '?update', { scope: scope })
+    }).then(swr => {
+      assert_equals(swr, registration, 'should be same registration');
+      return wait_for_state(t, registration.installing, 'installed');
+    }).then(_ => {
+      return echo(registration.waiting, 'waiting');
+    }).then(evt => {
+      assert_equals(evt.source, registration.waiting,
+                    'message event source should be correct');
+      return echo(registration.active, 'active');
+    }).then(evt => {
+      assert_equals(evt.source, registration.active,
+                    'message event source should be correct');
+      frame.remove();
+    }).then(_ => service_worker_unregister_and_done(t, scope) )
+    .catch(unreached_rejection(t));
+}, 'Client.postMessage() from waiting serviceworker.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/request-end-to-end.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/request-end-to-end.https.html
index e952332..32b4299 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/request-end-to-end.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/request-end-to-end.https.html
@@ -8,7 +8,6 @@
 t.step(function() {
     var url = 'resources/request-end-to-end-worker.js';
     var scope = 'resources/blank.html';
-    var frames = [];
 
     service_worker_unregister_and_register(t, url, scope)
       .then(onRegister)
@@ -46,7 +45,11 @@
     }
 
     function onPortReady() {
-        with_iframe(scope).then(function(f) { frames.push(f); });
+        // The only purpose of the iframe created here is to generate an HTTP
+        // request, so the element may be removed as soon as the frame has
+        // completed loading.
+        with_iframe(scope).then(function(f) { f.remove(); })
+          .catch(unreached_rejection(t));
     }
 
     function onResult(event) {
@@ -66,7 +69,6 @@
         assert_equals(event.data.errorNameWhileAppendingHeader, 'TypeError',
                       'Appending a new header to the request must throw a ' +
                       'TypeError.')
-        frames.forEach(function(f) { f.remove(); });
         service_worker_unregister_and_done(t, scope);
     }
 });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/echo-message-to-source-worker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/echo-message-to-source-worker.js
new file mode 100644
index 0000000..bbbd35fb4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/echo-message-to-source-worker.js
@@ -0,0 +1,3 @@
+addEventListener('message', evt => {
+  evt.source.postMessage(evt.data);
+});
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/respond-then-throw-worker.js b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/respond-then-throw-worker.js
new file mode 100644
index 0000000..adb48de
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/respond-then-throw-worker.js
@@ -0,0 +1,40 @@
+var syncport = null;
+
+self.addEventListener('message', function(e) {
+  if ('port' in e.data) {
+    if (syncport) {
+      syncport(e.data.port);
+    } else {
+      syncport = e.data.port;
+    }
+  }
+});
+
+function sync() {
+  return new Promise(function(resolve) {
+      if (syncport) {
+        resolve(syncport);
+      } else {
+        syncport = resolve;
+      }
+    }).then(function(port) {
+      port.postMessage('SYNC');
+      return new Promise(function(resolve) {
+          port.onmessage = function(e) {
+            if (e.data === 'ACK') {
+              resolve();
+            }
+          }
+        });
+    });
+}
+
+
+self.addEventListener('fetch', function(event) {
+    // In Firefox the result would depend on a race between fetch handling
+    // and exception handling code. On the assumption that this might be a common
+    // design error, we explicitly allow the exception to be handled first.
+    event.respondWith(sync().then(() => new Response('intercepted')));
+
+    throw("error");
+  });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/storage/estimate-indexeddb-worker.https.html b/third_party/WebKit/LayoutTests/external/wpt/storage/estimate-indexeddb-worker.https.html
new file mode 100644
index 0000000..2366760
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/storage/estimate-indexeddb-worker.https.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>StorageManager: estimate() for indexeddb from worker</title>
+    <meta name="help" href="https://storage.spec.whatwg.org/#dom-storagemanager-estimate">
+    <meta name="author" title="Mozilla" href="https://www.mozilla.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <script>
+      fetch_tests_from_worker(new Worker("storage-estimate-indexeddb.js"));
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/storage/estimate-indexeddb.https.html b/third_party/WebKit/LayoutTests/external/wpt/storage/estimate-indexeddb.https.html
new file mode 100644
index 0000000..3f5e158
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/storage/estimate-indexeddb.https.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>StorageManager: estimate() for indexeddb</title>
+    <meta name="help" href="https://storage.spec.whatwg.org/#dom-storagemanager-estimate">
+    <meta name="author" title="Mozilla" href="https://www.mozilla.org">
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <script src="storage-estimate-indexeddb.js"></script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/storage/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/storage/interfaces-expected.txt
deleted file mode 100644
index 3e6ba26..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/storage/interfaces-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-PASS Storage API IDL test 
-FAIL Navigator interface: attribute storage assert_true: The prototype object must have a property "storage" expected true got false
-PASS WorkerNavigator interface: existence and properties of interface object 
-PASS StorageManager interface: existence and properties of interface object 
-PASS StorageManager interface object length 
-PASS StorageManager interface object name 
-FAIL StorageManager interface: existence and properties of interface prototype object assert_equals: class string of StorageManager.prototype expected "[object StorageManagerPrototype]" but got "[object StorageManager]"
-PASS StorageManager interface: existence and properties of interface prototype object's "constructor" property 
-PASS StorageManager interface: operation persisted() 
-PASS StorageManager interface: operation persist() 
-PASS StorageManager interface: operation estimate() 
-FAIL StorageManager must be primary interface of navigator.storage assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL Stringification of navigator.storage assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL StorageManager interface: navigator.storage must inherit property "persisted" with the proper type (0) assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL StorageManager interface: navigator.storage must inherit property "persist" with the proper type (1) assert_equals: wrong typeof object expected "object" but got "undefined"
-FAIL StorageManager interface: navigator.storage must inherit property "estimate" with the proper type (2) assert_equals: wrong typeof object expected "object" but got "undefined"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/storage/interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/storage/interfaces.https-expected.txt
new file mode 100644
index 0000000..3eedecd4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/storage/interfaces.https-expected.txt
@@ -0,0 +1,19 @@
+This is a testharness.js-based test.
+PASS Storage API IDL test 
+PASS Navigator interface: attribute storage 
+PASS WorkerNavigator interface: existence and properties of interface object 
+PASS StorageManager interface: existence and properties of interface object 
+PASS StorageManager interface object length 
+PASS StorageManager interface object name 
+FAIL StorageManager interface: existence and properties of interface prototype object assert_equals: class string of StorageManager.prototype expected "[object StorageManagerPrototype]" but got "[object StorageManager]"
+PASS StorageManager interface: existence and properties of interface prototype object's "constructor" property 
+PASS StorageManager interface: operation persisted() 
+PASS StorageManager interface: operation persist() 
+PASS StorageManager interface: operation estimate() 
+PASS StorageManager must be primary interface of navigator.storage 
+PASS Stringification of navigator.storage 
+PASS StorageManager interface: navigator.storage must inherit property "persisted" with the proper type (0) 
+PASS StorageManager interface: navigator.storage must inherit property "persist" with the proper type (1) 
+PASS StorageManager interface: navigator.storage must inherit property "estimate" with the proper type (2) 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/storage/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/storage/interfaces.https.html
similarity index 100%
rename from third_party/WebKit/LayoutTests/external/wpt/storage/interfaces.html
rename to third_party/WebKit/LayoutTests/external/wpt/storage/interfaces.https.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/storage/storage-estimate-indexeddb.js b/third_party/WebKit/LayoutTests/external/wpt/storage/storage-estimate-indexeddb.js
new file mode 100644
index 0000000..5f789535
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/storage/storage-estimate-indexeddb.js
@@ -0,0 +1,94 @@
+if (this.document === undefined) {
+  importScripts("/resources/testharness.js");
+}
+
+test(function(t) {
+  assert_true('estimate' in navigator.storage);
+  assert_equals(typeof navigator.storage.estimate, 'function');
+  assert_true(navigator.storage.estimate() instanceof Promise);
+}, 'estimate() method exists and returns a Promise');
+
+promise_test(function(t) {
+  return navigator.storage.estimate().then(function(result) {
+    assert_true(typeof result === 'object');
+    assert_true('usage' in result);
+    assert_equals(typeof result.usage, 'number');
+    assert_true('quota' in result);
+    assert_equals(typeof result.quota, 'number');
+  });
+}, 'estimate() resolves to dictionary with members');
+
+promise_test(function(t) {
+  const arraySize = 1e6;
+  const objectStoreName = "storageManager";
+  const dbname = this.window ? window.location.pathname :
+  	   "estimate-worker.https.html";
+
+  let db;
+  let usageBeforeCreate, usageAfterCreate, usageAfterPut;
+
+  function deleteDB(name) {
+    return new Promise(function(resolve, reject) {
+      let deleteRequest = indexedDB.deleteDatabase(name);
+      deleteRequest.onerror = function() { reject(deleteRequest.error); };
+      deleteRequest.onsuccess = function() { resolve(); };
+    });
+  }
+
+  return deleteDB(dbname)
+  .then(() => {
+     return navigator.storage.estimate();
+  })
+  .then(estimate => {
+    usageBeforeCreate = estimate.usage;
+    return new Promise(function(resolve, reject) {
+      let openRequest = indexedDB.open(dbname);
+      openRequest.onerror = function() { reject(openRequest.error); };
+      openRequest.onupgradeneeded = function(event) {
+        openRequest.result.createObjectStore(objectStoreName);
+      };
+      openRequest.onsuccess = function() { resolve(openRequest.result); };
+    });
+  })
+  .then(connection => {
+    db = connection;
+    return navigator.storage.estimate();
+  })
+  .then(estimate => {
+    usageAfterCreate = estimate.usage;
+    assert_greater_than(usageAfterCreate, usageBeforeCreate,
+  	                'estimated usage should increase after object store is created');
+
+    let txn = db.transaction(objectStoreName, 'readwrite');
+    let buffer = new ArrayBuffer(arraySize);
+    let view = new Uint8Array(buffer);
+
+    for (let i = 0; i < arraySize; i++) {
+      view[i] = parseInt(Math.random() * 255);
+    }
+
+    let testBlob = new Blob([buffer], {type: "binary/random"});
+    txn.objectStore(objectStoreName).add(testBlob, 1);
+
+    return new Promise(function(resolve, reject) {
+      txn.onabort = function() { reject(txn.error); };
+      txn.oncomplete = function() { resolve(); };
+    });
+  })
+  .then(() => {
+    return navigator.storage.estimate();
+  })
+  .then(estimate => {
+    usageAfterPut = estimate.usage;
+    assert_greater_than(usageAfterPut, usageAfterCreate,
+  	                'estimated usage should increase after large value is stored');
+
+    db.close();
+    return deleteDB(dbname)
+  })
+  .then(() => {
+    t.done();
+  })
+}, 'estimate() shows usage increase after large value is stored');
+
+done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward-expected.txt
new file mode 100644
index 0000000..f0d60e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward-expected.txt
@@ -0,0 +1,30 @@
+This is a testharness.js-based test.
+PASS Closing must be propagated forward: starts closed; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = undefined (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = null (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = false (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = 0 (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = -0 (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = NaN (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose =  (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = true (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = a (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = 1 (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = Symbol() (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = [object Object] (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = true, preventAbort = true 
+PASS Closing must be propagated forward: starts closed; preventClose = true, preventAbort = true, preventCancel = true 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose = true 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose = true 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose = true 
+PASS Closing must be propagated forward: shutdown must not occur until the final write completes 
+FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true assert_equals: the pipe must not be complete expected false but got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.dedicatedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.dedicatedworker-expected.txt
new file mode 100644
index 0000000..f0d60e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.dedicatedworker-expected.txt
@@ -0,0 +1,30 @@
+This is a testharness.js-based test.
+PASS Closing must be propagated forward: starts closed; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = undefined (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = null (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = false (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = 0 (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = -0 (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = NaN (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose =  (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = true (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = a (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = 1 (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = Symbol() (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = [object Object] (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = true, preventAbort = true 
+PASS Closing must be propagated forward: starts closed; preventClose = true, preventAbort = true, preventCancel = true 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose = true 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose = true 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose = true 
+PASS Closing must be propagated forward: shutdown must not occur until the final write completes 
+FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true assert_equals: the pipe must not be complete expected false but got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.js b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.js
index 3f39c6a..35eac87 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.js
@@ -424,4 +424,38 @@
 
 }, 'Closing must be propagated forward: shutdown must not occur until the final write completes');
 
+promise_test(() => {
+
+  const rs = recordingReadableStream();
+
+  let resolveWritePromise;
+  const ws = recordingWritableStream({
+    write() {
+      return new Promise(resolve => {
+        resolveWritePromise = resolve;
+      });
+    }
+  });
+
+  let pipeComplete = false;
+  const pipePromise = rs.pipeTo(ws, { preventClose: true }).then(() => {
+    pipeComplete = true;
+  });
+
+  rs.controller.enqueue('a');
+  rs.controller.close();
+
+  // Flush async events and verify that no shutdown occurs.
+  return flushAsyncEvents().then(() => {
+    assert_array_equals(ws.events, ['write', 'a'],
+      'the chunk must have been written, but close must not have happened yet');
+    assert_equals(pipeComplete, false, 'the pipe must not be complete');
+
+    resolveWritePromise();
+
+    return pipePromise;
+  });
+
+}, 'Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true');
+
 done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.serviceworker.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.serviceworker.https-expected.txt
new file mode 100644
index 0000000..93a7dc9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.serviceworker.https-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+PASS Service worker test setup 
+PASS Closing must be propagated forward: starts closed; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = undefined (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = null (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = false (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = 0 (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = -0 (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = NaN (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose =  (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = true (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = a (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = 1 (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = Symbol() (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = [object Object] (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = true, preventAbort = true 
+PASS Closing must be propagated forward: starts closed; preventClose = true, preventAbort = true, preventCancel = true 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose = true 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose = true 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose = true 
+PASS Closing must be propagated forward: shutdown must not occur until the final write completes 
+FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true assert_equals: the pipe must not be complete expected false but got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.sharedworker-expected.txt
new file mode 100644
index 0000000..f0d60e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/close-propagation-forward.sharedworker-expected.txt
@@ -0,0 +1,30 @@
+This is a testharness.js-based test.
+PASS Closing must be propagated forward: starts closed; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = undefined (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = null (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = false (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = 0 (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = -0 (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = NaN (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose =  (falsy); fulfilled close promise 
+PASS Closing must be propagated forward: starts closed; preventClose = true (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = a (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = 1 (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = Symbol() (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = [object Object] (truthy) 
+PASS Closing must be propagated forward: starts closed; preventClose = true, preventAbort = true 
+PASS Closing must be propagated forward: starts closed; preventClose = true, preventAbort = true, preventCancel = true 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; preventClose = true 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed asynchronously; dest never desires chunks; preventClose = true 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose omitted; fulfilled close promise 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose omitted; rejected close promise 
+PASS Closing must be propagated forward: becomes closed after one chunk; preventClose = true 
+PASS Closing must be propagated forward: shutdown must not occur until the final write completes 
+FAIL Closing must be propagated forward: shutdown must not occur until the final write completes; preventClose = true assert_equals: the pipe must not be complete expected false but got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation-expected.txt
deleted file mode 100644
index 32b3cd1..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Piping from an errored readable stream to an errored writable stream 
-PASS Piping from an errored readable stream to an errored writable stream; preventAbort = true 
-FAIL Piping from an errored readable stream to a closed writable stream assert_array_equals: lengths differ, expected 1 got 2
-PASS Piping from a closed readable stream to an errored writable stream 
-PASS Piping from a closed readable stream to a closed writable stream 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.dedicatedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.dedicatedworker-expected.txt
deleted file mode 100644
index 32b3cd1..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.dedicatedworker-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Piping from an errored readable stream to an errored writable stream 
-PASS Piping from an errored readable stream to an errored writable stream; preventAbort = true 
-FAIL Piping from an errored readable stream to a closed writable stream assert_array_equals: lengths differ, expected 1 got 2
-PASS Piping from a closed readable stream to an errored writable stream 
-PASS Piping from a closed readable stream to a closed writable stream 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.js b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.js
index 79ec399..447433f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.js
@@ -71,19 +71,48 @@
   });
   const ws = recordingWritableStream();
   const writer = ws.getWriter();
-  writer.close();
+  const closePromise = writer.close();
   writer.releaseLock();
 
   return promise_rejects(t, error1, rs.pipeTo(ws), 'pipeTo must reject with the readable stream\'s error').then(() => {
     assert_array_equals(rs.events, []);
-    assert_array_equals(ws.events, ['close']);
+    assert_array_equals(ws.events, ['abort', error1]);
 
     return Promise.all([
       promise_rejects(t, error1, rs.getReader().closed, 'the readable stream must be errored with error1'),
-      ws.getWriter().closed
+      promise_rejects(t, new TypeError(), ws.getWriter().closed,
+        'closed must reject with a TypeError indicating the writable stream was aborted'),
+      promise_rejects(t, new TypeError(), closePromise,
+        'close() must reject with a TypeError indicating the writable stream was aborted'),
     ]);
   });
 
+}, 'Piping from an errored readable stream to a closing writable stream');
+
+promise_test(t => {
+  const rs = recordingReadableStream({
+    start(c) {
+      c.error(error1);
+    }
+  });
+  const ws = recordingWritableStream();
+  const writer = ws.getWriter();
+  const closePromise = writer.close();
+  writer.releaseLock();
+
+  return flushAsyncEvents().then(() => {
+    return promise_rejects(t, error1, rs.pipeTo(ws), 'pipeTo must reject with the readable stream\'s error').then(() => {
+      assert_array_equals(rs.events, []);
+      assert_array_equals(ws.events, ['close']);
+
+      return Promise.all([
+        promise_rejects(t, error1, rs.getReader().closed, 'the readable stream must be errored with error1'),
+        ws.getWriter().closed,
+        closePromise
+      ]);
+    });
+  });
+
 }, 'Piping from an errored readable stream to a closed writable stream');
 
 promise_test(t => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.serviceworker.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.serviceworker.https-expected.txt
deleted file mode 100644
index 7c3b316..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.serviceworker.https-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = The stream has been aborted
-PASS Service worker test setup 
-PASS Piping from an errored readable stream to an errored writable stream 
-PASS Piping from an errored readable stream to an errored writable stream; preventAbort = true 
-FAIL Piping from an errored readable stream to a closed writable stream assert_array_equals: lengths differ, expected 1 got 2
-PASS Piping from a closed readable stream to an errored writable stream 
-PASS Piping from a closed readable stream to a closed writable stream 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.sharedworker-expected.txt
deleted file mode 100644
index 32b3cd1..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/multiple-propagation.sharedworker-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS Piping from an errored readable stream to an errored writable stream 
-PASS Piping from an errored readable stream to an errored writable stream; preventAbort = true 
-FAIL Piping from an errored readable stream to a closed writable stream assert_array_equals: lengths differ, expected 1 got 2
-PASS Piping from a closed readable stream to an errored writable stream 
-PASS Piping from a closed readable stream to a closed writable stream 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through-expected.txt
index 423e104..cb261c6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through-expected.txt
@@ -5,5 +5,6 @@
 PASS pipeThrough generically calls pipeTo with the appropriate args 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise object 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise thenable object 
+PASS pipeThrough should mark a real promise from a fake readable as handled 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.dedicatedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.dedicatedworker-expected.txt
index 423e104..cb261c6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.dedicatedworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.dedicatedworker-expected.txt
@@ -5,5 +5,6 @@
 PASS pipeThrough generically calls pipeTo with the appropriate args 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise object 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise thenable object 
+PASS pipeThrough should mark a real promise from a fake readable as handled 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.js b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.js
index 57277cf..9299fce 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.js
@@ -104,4 +104,18 @@
 
 }, 'pipeThrough can handle calling a pipeTo that returns a non-promise thenable object');
 
+promise_test(() => {
+  const dummy = {
+    pipeTo() {
+      return Promise.reject(new Error('this rejection should not be reported as unhandled'));
+    }
+  };
+
+  ReadableStream.prototype.pipeThrough.call(dummy, { });
+
+  // The test harness should complain about unhandled rejections by then.
+  return flushAsyncEvents();
+
+}, 'pipeThrough should mark a real promise from a fake readable as handled');
+
 done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.serviceworker.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.serviceworker.https-expected.txt
index 1ef1fed5..cbfe250 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.serviceworker.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.serviceworker.https-expected.txt
@@ -6,5 +6,6 @@
 PASS pipeThrough generically calls pipeTo with the appropriate args 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise object 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise thenable object 
+PASS pipeThrough should mark a real promise from a fake readable as handled 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.sharedworker-expected.txt
index 423e104..cb261c6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.sharedworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.sharedworker-expected.txt
@@ -5,5 +5,6 @@
 PASS pipeThrough generically calls pipeTo with the appropriate args 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise object 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise thenable object 
+PASS pipeThrough should mark a real promise from a fake readable as handled 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/svg/interfaces.html
index 5a946c76..98346c4a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/interfaces.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/interfaces.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <title>SVG interface tests</title>
+<meta name=timeout content=long>
 <div id=log></div>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/uievents/keyboard/key-101en-us-manual.html b/third_party/WebKit/LayoutTests/external/wpt/uievents/keyboard/key-101en-us-manual.html
new file mode 100644
index 0000000..8b9cb46
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/uievents/keyboard/key-101en-us-manual.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<title>Keyboard Event Manual Test</title>
+<meta http-equiv="content-type" content="text/html;charset=utf-8" />
+<script type="text/javascript" src="key-manual.js" ></script>
+<link rel="stylesheet" type="text/css" href="key-manual.css" />
+
+</head>
+
+<body>
+
+<script language="javascript">
+var KeyTable101 = [
+    // Code         Row  Type  Width      KeyCap   Key    Shift
+    ["Backquote",    0,    0,    0,        "`",    "`",    "~"],
+    ["Digit1",       0,    0,    0,        "1",    "1",    "!"],
+    ["Digit2",       0,    0,    0,        "2",    "2",    "@"],
+    ["Digit3",       0,    0,    0,        "3",    "3",    "#"],
+    ["Digit4",       0,    0,    0,        "4",    "4",    "$"],
+    ["Digit5",       0,    0,    0,        "5",    "5",    "%"],
+    ["Digit6",       0,    0,    0,        "6",    "6",    "^"],
+    ["Digit7",       0,    0,    0,        "7",    "7",    "&"],
+    ["Digit8",       0,    0,    0,        "8",    "8",    "*"],
+    ["Digit9",       0,    0,    0,        "9",    "9",    "("],
+    ["Digit0",       0,    0,    0,        "0",    "0",    ")"],
+    ["Minus",        0,    0,    0,        "-",    "-",    "_"],
+    ["Equal",        0,    0,    0,        "=",    "=",    "+"],
+    ["Backspace",    0,    0,    2,        "Backspace",  "Backspace",  "Backspace"],
+
+    ["Tab",          1,    0,    1,        "Tab",  "Tab",  "Tab"],
+    ["KeyQ",         1,    0,    0,        "Q",    "q",    "Q"],
+    ["KeyW",         1,    0,    0,        "W",    "w",    "W"],
+    ["KeyE",         1,    0,    0,        "E",    "e",    "E"],
+    ["KeyR",         1,    0,    0,        "R",    "r",    "R"],
+    ["KeyT",         1,    0,    0,        "T",    "t",    "T"],
+    ["KeyY",         1,    0,    0,        "Y",    "y",    "Y"],
+    ["KeyU",         1,    0,    0,        "U",    "u",    "U"],
+    ["KeyI",         1,    0,    0,        "I",    "i",    "I"],
+    ["KeyO",         1,    0,    0,        "O",    "o",    "O"],
+    ["KeyP",         1,    0,    0,        "P",    "p",    "P"],
+    ["BracketLeft",  1,    0,    0,        "[",    "[",    "{"],
+    ["BracketRight", 1,    0,    0,        "]",    "]",    "}"],
+    ["Backslash",    1,    0,    1,        "\\",   "\\",   "|"],
+
+    ["CapsLock",     2,    1,    2,        "CapsLock",  "CapsLock",  "CapsLock"],
+    ["KeyA",         2,    0,    0,        "A",    "a",    "A"],
+    ["KeyS",         2,    0,    0,        "S",    "s",    "S"],
+    ["KeyD",         2,    0,    0,        "D",    "d",    "D"],
+    ["KeyF",         2,    0,    0,        "F",    "f",    "F"],
+    ["KeyG",         2,    0,    0,        "G",    "g",    "G"],
+    ["KeyH",         2,    0,    0,        "H",    "h",    "H"],
+    ["KeyJ",         2,    0,    0,        "J",    "j",    "J"],
+    ["KeyK",         2,    0,    0,        "K",    "k",    "K"],
+    ["KeyL",         2,    0,    0,        "L",    "l",    "L"],
+    ["Semicolon",    2,    0,    0,        ";",    ";",    ":"],
+    ["Quote",        2,    0,    0,        "'",    "'",    "\""],
+    ["Enter",        2,    0,    3,        "Enter",  "Enter",  "Enter"],
+
+    ["ShiftLeft",    3,    3,    3,        "Shift",  "Shift",  "Shift"],
+    ["KeyZ",         3,    0,    0,        "Z",    "z",    "Z"],
+    ["KeyX",         3,    0,    0,        "X",    "x",    "X"],
+    ["KeyC",         3,    0,    0,        "C",    "c",    "C"],
+    ["KeyV",         3,    0,    0,        "V",    "v",    "V"],
+    ["KeyB",         3,    0,    0,        "B",    "b",    "B"],
+    ["KeyN",         3,    0,    0,        "N",    "n",    "N"],
+    ["KeyM",         3,    0,    0,        "M",    "m",    "M"],
+    ["Comma",        3,    0,    0,        ",",    ",",    "<"],
+    ["Period",       3,    0,    0,        ".",    ".",    ">"],
+    ["Slash",        3,    0,    0,        "/",    "/",    "?"],
+    ["ShiftRight",   3,    3,    4,        "Shift",  "Shift",  "Shift"],
+
+    ["ControlLeft",  4,    3,    1,        "Control",  "Control",  "Control"],
+    ["MetaLeft",     4,    3,    1,        "Meta",     "Meta",     "Meta"],
+    ["AltLeft",      4,    3,    1,        "Alt",      "Alt",      "Alt"],
+    ["Space",        4,    0,    5,        "Space",    " ",        " "],
+    ["AltRight",     4,    3,    1,        "Alt",      "Alt",      "Alt"],
+    ["MetaRight",    4,    3,    1,        "Meta",     "Meta",     "Meta"],
+    ["ContextMenu",  4,    0,    1,        "Menu",     "",         ""],
+    ["ControlRight", 4,    3,    1,        "Control",  "Control",  "Control"],
+
+    ["END",          0,    2,    0,        "",     "",     ""],
+];
+
+init("101en-us", KeyTable101);
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/uievents/keyboard/key-102fr-fr-manual.html b/third_party/WebKit/LayoutTests/external/wpt/uievents/keyboard/key-102fr-fr-manual.html
new file mode 100644
index 0000000..6521681
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/uievents/keyboard/key-102fr-fr-manual.html
@@ -0,0 +1,93 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<title>Keyboard Event Manual Test</title>
+<meta http-equiv="content-type" content="text/html;charset=utf-8" />
+<script type="text/javascript" src="key-manual.js" ></script>
+<link rel="stylesheet" type="text/css" href="key-manual.css" />
+
+</head>
+
+<body>
+
+<script language="javascript">
+var KeyTable102 = [
+    // Code         Row  Type  Width      KeyCap   Key    Shift
+    ["Backquote",    0,    0,    0,        "²",    "²",    ""],
+    ["Digit1",       0,    0,    0,        "&",    "&",    "1"],
+    ["Digit2",       0,    0,    0,        "é",    "é",    "2"],
+    ["Digit3",       0,    0,    0,        "\"",   "\"",   "3"],
+    ["Digit4",       0,    0,    0,        "'",    "'",    "4"],
+    ["Digit5",       0,    0,    0,        "(",    "(",    "5"],
+    ["Digit6",       0,    0,    0,        "-",    "-",    "6"],
+    ["Digit7",       0,    0,    0,        "è",    "è",    "7"],
+    ["Digit8",       0,    0,    0,        "_",    "_",    "8"],
+    ["Digit9",       0,    0,    0,        "ç",    "ç",    "9"],
+    ["Digit0",       0,    0,    0,        "à",    "à",    "0"],
+    ["Minus",        0,    0,    0,        ")",    ")",    "°"],
+    ["Equal",        0,    0,    0,        "=",    "=",    "+"],
+    ["Backspace",    0,    0,    2,        "Backspace",  "Backspace", "Backspace"],
+
+    ["Tab",          1,    0,    1,        "Tab",  "Tab",  "Tab"],
+    ["KeyQ",         1,    0,    0,        "A",    "a",    "A"],
+    ["KeyW",         1,    0,    0,        "Z",    "z",    "Z"],
+    ["KeyE",         1,    0,    0,        "E",    "e",    "E"],
+    ["KeyR",         1,    0,    0,        "R",    "r",    "R"],
+    ["KeyT",         1,    0,    0,        "T",    "t",    "T"],
+    ["KeyY",         1,    0,    0,        "Y",    "y",    "Y"],
+    ["KeyU",         1,    0,    0,        "U",    "u",    "U"],
+    ["KeyI",         1,    0,    0,        "I",    "i",    "I"],
+    ["KeyO",         1,    0,    0,        "O",    "o",    "O"],
+    ["KeyP",         1,    0,    0,        "P",    "p",    "P"],
+    ["BracketLeft",  1,    0,    0,        "^",    "^",    "¨"],
+    ["BracketRight", 1,    0,    0,        "$",    "$",    "£"],
+    ["Enter",        1,    0,    1,        "Enter",  "Enter",  "Enter"],
+
+    ["CapsLock",     2,    1,    2,        "CapsLock",  "CapsLock",  "CapsLock"],
+    ["KeyA",         2,    0,    0,        "Q",    "q",    "Q"],
+    ["KeyS",         2,    0,    0,        "S",    "s",    "S"],
+    ["KeyD",         2,    0,    0,        "D",    "d",    "D"],
+    ["KeyF",         2,    0,    0,        "F",    "f",    "F"],
+    ["KeyG",         2,    0,    0,        "G",    "g",    "G"],
+    ["KeyH",         2,    0,    0,        "H",    "h",    "H"],
+    ["KeyJ",         2,    0,    0,        "J",    "j",    "J"],
+    ["KeyK",         2,    0,    0,        "K",    "k",    "K"],
+    ["KeyL",         2,    0,    0,        "L",    "l",    "L"],
+    ["Semicolon",    2,    0,    0,        "M",    "m",    "M"],
+    ["Quote",        2,    0,    0,        "ù",    "ù",    "%"],
+    ["IntlHash",     2,    0,    0,        "*",    "*",    "µ"],
+    ["Enter",        2,    1,    0,        "Enter",  "Enter",  "Enter"],
+
+    ["ShiftLeft",    3,    3,    1,        "Shift",  "Shift",  "Shift"],
+    ["IntlBackslash",3,    0,    0,        "<",    "<",    ">"],
+    ["KeyZ",         3,    0,    0,        "W",    "w",    "W"],
+    ["KeyX",         3,    0,    0,        "X",    "x",    "X"],
+    ["KeyC",         3,    0,    0,        "C",    "c",    "C"],
+    ["KeyV",         3,    0,    0,        "V",    "v",    "V"],
+    ["KeyB",         3,    0,    0,        "B",    "b",    "B"],
+    ["KeyN",         3,    0,    0,        "N",    "n",    "N"],
+    ["KeyM",         3,    0,    0,        ",",    ",",    "?"],
+    ["Comma",        3,    0,    0,        ";",    ";",    "."],
+    ["Period",       3,    0,    0,        ":",    ":",    "/"],
+    ["Slash",        3,    0,    0,        "!",    "!",    "§"],
+    ["ShiftRight",   3,    3,    4,        "Shift",  "Shift",  "Shift"],
+
+    ["ControlLeft",  4,    3,    1,        "Control",  "Control",  "Control"],
+    ["MetaLeft",     4,    3,    1,        "Meta",     "Meta",     "Meta"],
+    ["AltLeft",      4,    3,    1,        "Alt",      "Alt",      "Alt"],
+    ["Space",        4,    0,    5,        "Space",    " ",        " "],
+    ["AltRight",     4,    3,    1,        "Alt",      "Alt",      "Alt"],
+    ["MetaRight",    4,    3,    1,        "Meta",     "Meta",     "Meta"],
+    ["ContextMenu",  4,    0,    1,        "Menu",     "",         ""],
+    ["ControlRight", 4,    3,    1,        "Control",  "Control",  "Control"],
+
+    ["END",          0,    2,    0,        "",     "",     ""],
+];
+
+init("102fr-fr", KeyTable102);
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html
index 2766745..87efd42 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance.html
@@ -8,7 +8,6 @@
 <script src="../../resources/easing-tests.js"></script>
 <body>
 <div id="log"></div>
-<div id="target"></div>
 <script>
 'use strict';
 
@@ -80,338 +79,5 @@
      `with a ${params.desc} does not alter the result`);
 });
 
-// Test that different easing functions correctly handle inputs outside the
-// range [0, 1]. This only occurs when we have an easing specified on the
-// effect that produces a value outside [0, 1] which we then pass to an easing
-// on a keyframe.
-
-function assert_style_left_at(animation, time, easingFunction) {
-  animation.currentTime = time;
-  var portion = time / animation.effect.timing.duration;
-  assert_approx_equals(pxToNum(getComputedStyle(animation.effect.target).left),
-                       easingFunction(portion) * 100,
-                       0.01,
-                       'The left of the animation should be approximately ' +
-                       easingFunction(portion) * 100 + ' at ' + time + 'ms');
-}
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-start' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
-
-  // The bezier function produces values greater than 1 (but always less than 2)
-  // in (0.23368794, 1)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 230;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 250;
-  assert_equals(getComputedStyle(target).left, '200px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-start easing with input progress greater than 1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-end' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
-
-  // The bezier function produces values greater than 1 (but always less than 2)
-  // in (0.23368794, 1)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 230;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 250;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-end easing with input progress greater than 1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-end' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 3, 1, 3)' });
-
-  // The bezier function produces values greater than 2 (but always less than 3)
-  // in the range (~0.245, ~0.882)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 500;
-  assert_equals(getComputedStyle(target).left, '200px');
-  anim.currentTime = 900;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-end easing with input progress greater than 2');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-start' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
-
-  // The bezier function produces negative values (but always greater than -1)
-  // in (0, 0.766312060)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 750;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 800;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-start easing with input progress less than 0');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-start' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, -2, 1, -2)' });
-
-  // The bezier function produces values less than -1 (but always greater than
-  // -2) in the range (~0.118, ~0.755)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 100;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 500;
-  assert_equals(getComputedStyle(target).left, '-100px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-start easing with input progress less than -1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-end' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
-
-  // The bezier function produces negative values (but always greater than -1)
-  // in (0, 0.766312060)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 750;
-  assert_equals(getComputedStyle(target).left, '-100px');
-  anim.currentTime = 800;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-end easing with input progress less than 0');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate(
-    // http://cubic-bezier.com/#.5,1,.5,0
-    [ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' },
-      { left: '100px' } ],
-      { duration: 1000,
-        fill: 'forwards',
-        easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
-  var keyframeEasing = function(x) {
-    assert_greater_than_equal(x, 0.0,
-      'This function should be called in [0, 1.0] range');
-    assert_less_than_equal(x, 1.0,
-      'This function should be called in [0, 1.0] range');
-    return cubicBezier(0.5, 1, 0.5, 0)(x);
-  }
-  var keyframeEasingExtrapolated = function(x) {
-    assert_greater_than(x, 1.0,
-      'This function should be called in (1.0, infinity) range');
-    // p3x + (p2y - p3y) / (p2x - p3x) * (x - p3x)
-    return 1.0 + (0 - 1) / (0.5 - 1) * (x - 1.0);
-  }
-  var effectEasing = function(x) {
-    return cubicBezier(0, 1.5, 1, 1.5)(x);
-  }
-
-  // The effect-easing produces values greater than 1 in (0.23368794, 1)
-  assert_style_left_at(anim, 0, function(x) {
-    return keyframeEasing(effectEasing(x));
-  });
-  assert_style_left_at(anim, 230, function(x) {
-    return keyframeEasing(effectEasing(x));
-  });
-  assert_style_left_at(anim, 240, function(x) {
-    return keyframeEasingExtrapolated(effectEasing(x));
-  });
-  // Near the extreme point of the effect-easing function
-  assert_style_left_at(anim, 700, function(x) {
-    return keyframeEasingExtrapolated(effectEasing(x));
-  });
-  assert_style_left_at(anim, 990, function(x) {
-    return keyframeEasingExtrapolated(effectEasing(x));
-  });
-  assert_style_left_at(anim, 1000, function(x) {
-    return keyframeEasing(effectEasing(x));
-  });
-}, 'cubic-bezier easing with input progress greater than 1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate(
-    // http://cubic-bezier.com/#0,1.5,1,1.5
-    [ { left: '0px', easing: 'cubic-bezier(0, 1.5, 1, 1.5)' },
-      { left: '100px' } ],
-      { duration: 1000,
-        fill: 'forwards',
-        easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
-  var easing = function(x) {
-    assert_greater_than_equal(x, 0.0,
-      'This function should be called in [0, 1.0] range');
-    assert_less_than_equal(x, 1.0,
-      'This function should be called in [0, 1.0] range');
-    return cubicBezier(0, 1.5, 1, 1.5)(x);
-  }
-  var easingExtrapolated = function(x) {
-    assert_greater_than(x, 1.0,
-      'This function should be called in negative range');
-    // For cubic-bezier(0, 1.5, 1, 1.5), the tangent at the
-    // endpoint (x = 1.0) is infinity so we should just return 1.0.
-    return 1.0;
-  }
-
-  // The effect-easing produces values greater than 1 in (0.23368794, 1)
-  assert_style_left_at(anim, 0, function(x) {
-    return easing(easing(x))
-  });
-  assert_style_left_at(anim, 230, function(x) {
-    return easing(easing(x))
-  });
-  assert_style_left_at(anim, 240, function(x) {
-    return easingExtrapolated(easing(x));
-  });
-  // Near the extreme point of the effect-easing function
-  assert_style_left_at(anim, 700, function(x) {
-    return easingExtrapolated(easing(x));
-  });
-  assert_style_left_at(anim, 990, function(x) {
-    return easingExtrapolated(easing(x));
-  });
-  assert_style_left_at(anim, 1000, function(x) {
-    return easing(easing(x))
-  });
-}, 'cubic-bezier easing with input progress greater than 1 and where the ' +
-   'tangent on the upper boundary is infinity');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate(
-    // http://cubic-bezier.com/#.5,1,.5,0
-    [ { left: '0px', easing: 'cubic-bezier(0.5, 1, 0.5, 0)' },
-      { left: '100px' } ],
-      { duration: 1000,
-        fill: 'forwards',
-        easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
-  var keyframeEasing = function(x) {
-    assert_greater_than_equal(x, 0.0,
-      'This function should be called in [0, 1.0] range');
-    assert_less_than_equal(x, 1.0,
-      'This function should be called in [0, 1.0] range');
-    return cubicBezier(0.5, 1, 0.5, 0)(x);
-  }
-  var keyframeEasingExtrapolated = function(x) {
-    assert_less_than(x, 0.0,
-      'This function should be called in negative range');
-    // p0x + (p1y - p0y) / (p1x - p0x) * (x - p0x)
-    return (1 / 0.5) * x;
-  }
-  var effectEasing = function(x) {
-    return cubicBezier(0, -0.5, 1, -0.5)(x);
-  }
-
-  // The effect-easing produces negative values in (0, 0.766312060)
-  assert_style_left_at(anim, 0, function(x) {
-    return keyframeEasing(effectEasing(x));
-  });
-  assert_style_left_at(anim, 10, function(x) {
-    return keyframeEasingExtrapolated(effectEasing(x));
-  });
-  // Near the extreme point of the effect-easing function
-  assert_style_left_at(anim, 300, function(x) {
-    return keyframeEasingExtrapolated(effectEasing(x));
-  });
-  assert_style_left_at(anim, 750, function(x) {
-    return keyframeEasingExtrapolated(effectEasing(x));
-  });
-  assert_style_left_at(anim, 770, function(x) {
-    return keyframeEasing(effectEasing(x));
-  });
-  assert_style_left_at(anim, 1000, function(x) {
-    return keyframeEasing(effectEasing(x));
-  });
-}, 'cubic-bezier easing with input progress less than 0');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate(
-    // http://cubic-bezier.com/#0,-0.5,1,-0.5
-    [ { left: '0px', easing: 'cubic-bezier(0, -0.5, 1, -0.5)' },
-      { left: '100px' } ],
-      { duration: 1000,
-        fill: 'forwards',
-        easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
-  var easing = function(x) {
-    assert_greater_than_equal(x, 0.0,
-      'This function should be called in [0, 1.0] range');
-    assert_less_than_equal(x, 1.0,
-      'This function should be called in [0, 1.0] range');
-    return cubicBezier(0, -0.5, 1, -0.5)(x);
-  }
-  var easingExtrapolated = function(x) {
-    assert_less_than(x, 0.0,
-      'This function should be called in negative range');
-    // For cubic-bezier(0, -0.5, 1, -0.5), the tangent at the
-    // endpoint (x = 0.0) is infinity so we should just return 0.0.
-    return 0.0;
-  }
-
-  // The effect-easing produces negative values in (0, 0.766312060)
-  assert_style_left_at(anim, 0, function(x) {
-    return easing(easing(x))
-  });
-  assert_style_left_at(anim, 10, function(x) {
-    return easingExtrapolated(easing(x));
-  });
-  // Near the extreme point of the effect-easing function
-  assert_style_left_at(anim, 300, function(x) {
-    return easingExtrapolated(easing(x));
-  });
-  assert_style_left_at(anim, 750, function(x) {
-    return easingExtrapolated(easing(x));
-  });
-  assert_style_left_at(anim, 770, function(x) {
-    return easing(easing(x))
-  });
-  assert_style_left_at(anim, 1000, function(x) {
-    return easing(easing(x))
-  });
-}, 'cubic-bezier easing with input progress less than 0 and where the ' +
-   'tangent on the lower boundary is infinity');
-
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animatable/animate-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animatable/animate-expected.txt
index d99f559..7943c84 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animatable/animate-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animatable/animate-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 82 tests; 38 PASS, 44 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 90 tests; 46 PASS, 44 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Element.animate() creates an Animation object 
 FAIL Element.animate() creates an Animation object in the relevant realm of the target element Cannot read property 'prototype' of undefined
 PASS Element.animate() creates an Animation object with a KeyframeEffect 
@@ -74,6 +74,14 @@
 PASS Element.animate() does not accept invalid easing: 'function (a){return a}' 
 PASS Element.animate() does not accept invalid easing: 'function (x){return x}' 
 PASS Element.animate() does not accept invalid easing: 'function(x, y){return 0.3}' 
+PASS Element.animate() does not accept invalid easing: 'frames(1)' 
+PASS Element.animate() does not accept invalid easing: 'frames' 
+PASS Element.animate() does not accept invalid easing: 'frames()' 
+PASS Element.animate() does not accept invalid easing: 'frames(,)' 
+PASS Element.animate() does not accept invalid easing: 'frames(a)' 
+PASS Element.animate() does not accept invalid easing: 'frames(2.0)' 
+PASS Element.animate() does not accept invalid easing: 'frames(2.5)' 
+PASS Element.animate() does not accept invalid easing: 'frames(2 3)' 
 PASS Element.animate() accepts a double as an options argument 
 PASS Element.animate() accepts a KeyframeAnimationOptions argument 
 PASS Element.animate() accepts an absent options argument 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt
index 40d75ee6..ef6e612 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/AnimationEffectTiming/easing-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Found 52 tests; 50 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test default value 
 PASS step-start function 
 PASS steps(1, start) function 
@@ -7,6 +8,7 @@
 PASS steps(1) function 
 PASS steps(1, end) function 
 PASS steps(2, end) function 
+FAIL frames function Failed to set the 'easing' property on 'AnimationEffectTiming': 'frames(5)' is not a valid value for easing
 PASS linear function 
 PASS ease function 
 PASS ease-in function 
@@ -32,6 +34,14 @@
 PASS Invalid effect easing value test: 'function (a){return a}' 
 PASS Invalid effect easing value test: 'function (x){return x}' 
 PASS Invalid effect easing value test: 'function(x, y){return 0.3}' 
+PASS Invalid effect easing value test: 'frames(1)' 
+PASS Invalid effect easing value test: 'frames' 
+PASS Invalid effect easing value test: 'frames()' 
+PASS Invalid effect easing value test: 'frames(,)' 
+PASS Invalid effect easing value test: 'frames(a)' 
+PASS Invalid effect easing value test: 'frames(2.0)' 
+PASS Invalid effect easing value test: 'frames(2.5)' 
+PASS Invalid effect easing value test: 'frames(2 3)' 
 PASS Canonical easing 'ease' is returned as set 
 PASS Canonical easing 'linear' is returned as set 
 PASS Canonical easing 'ease-in' is returned as set 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/resources/easing-tests.js b/third_party/WebKit/LayoutTests/external/wpt/web-animations/resources/easing-tests.js
index 7efaa9b..03cfbc1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/resources/easing-tests.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/resources/easing-tests.js
@@ -39,6 +39,11 @@
     serialization: 'steps(2)'
   },
   {
+    desc: 'frames function',
+    easing: 'frames(5)',
+    easingFunction: framesTiming(5)
+  },
+  {
     desc: 'linear function',
     easing: 'linear', // cubic-bezier(0, 0, 1.0, 1.0)
     easingFunction: cubicBezier(0, 0, 1.0, 1.0)
@@ -94,6 +99,14 @@
   'function (a){return a}',
   'function (x){return x}',
   'function(x, y){return 0.3}',
+  'frames(1)',
+  'frames',
+  'frames()',
+  'frames(,)',
+  'frames(a)',
+  'frames(2.0)',
+  'frames(2.5)',
+  'frames(2 3)',
 ];
 
 // Easings that should serialize to the same string
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/testcommon.js b/third_party/WebKit/LayoutTests/external/wpt/web-animations/testcommon.js
index 348af6e..302fb8ba1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/testcommon.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/testcommon.js
@@ -90,11 +90,6 @@
   return anim.effect.target;
 }
 
-// Convert px unit value to a Number
-function pxToNum(str) {
-  return Number(String(str).match(/^(-?[\d.]+)px$/)[1]);
-}
-
 // Cubic bezier with control points (0, 0), (x1, y1), (x2, y2), and (1, 1).
 function cubicBezier(x1, y1, x2, y2) {
   function xForT(t) {
@@ -146,6 +141,13 @@
   }
 }
 
+function framesTiming(nframes) {
+  return function framesClosure(x) {
+    var result = Math.floor(x * nframes) / (nframes - 1);
+    return (result > 1.0 && x <= 1.0) ? 1.0 : result;
+  }
+}
+
 function waitForAnimationFrames(frameCount) {
   return new Promise(function(resolve, reject) {
     function handleFrame() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt
index ee5620bc..6a9484af 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress-expected.txt
@@ -6,6 +6,7 @@
 PASS Transformed progress for steps(1) function 
 PASS Transformed progress for steps(1, end) function 
 PASS Transformed progress for steps(2, end) function 
+FAIL Transformed progress for frames function Failed to execute 'animate' on 'Element': 'frames(5)' is not a valid value for easing
 PASS Transformed progress for linear function 
 FAIL Transformed progress for ease function assert_approx_equals: The progress should be approximately 0.40851059137130497 at 250ms expected 0.40851059137130497 +/- 0.01 but got 0.41869212962962965
 PASS Transformed progress for ease-in function 
@@ -24,5 +25,7 @@
 PASS Test bounds point of step-end easing 
 FAIL Test bounds point of step-end easing with iterationStart and delay assert_equals: Progress at 0ms expected 0 but got 0.5
 PASS Test bounds point of step-end easing with iterationStart not at a transition point 
+FAIL Test bounds point of frames easing Failed to execute 'animate' on 'Element': 'frames(2)' is not a valid value for easing
+FAIL Test bounds point of frames easing with iterationStart and delay Failed to execute 'animate' on 'Element': 'frames(2)' is not a valid value for easing
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress.html
index 3d97e4c1..6ca27cf 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/time-transformations/transformed-progress.html
@@ -32,9 +32,10 @@
   }, 'Transformed progress for ' + params.desc);
 });
 
-// Additional tests for various boundary conditions of step timing functions
+// Additional tests for various boundary conditions of step timing functions and
+// frames timing functions.
 
-var gStepTimingFunctionTests = [
+var gStepAndFramesTimingFunctionTests = [
   {
     description: 'Test bounds point of step-start easing',
     effect:     {
@@ -252,10 +253,45 @@
                   { currentTime: 2000, progress: 0.5 },
                   { currentTime: 2500, progress: 0.5 },
                 ]
+  },
+  {
+    description: 'Test bounds point of frames easing',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  easing: 'frames(2)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 0 },
+                  { currentTime: 1000, progress: 0 },
+                  { currentTime: 1499, progress: 0 },
+                  { currentTime: 1500, progress: 1 },
+                  { currentTime: 2000, progress: 1 }
+                ]
+  },
+  {
+    description: 'Test bounds point of frames easing ' +
+                 'with iterationStart and delay',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  iterationStart: 0.5,
+                  easing: 'frames(2)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 1 },
+                  { currentTime: 1000, progress: 1 },
+                  { currentTime: 1499, progress: 1 },
+                  { currentTime: 1500, progress: 0 },
+                  { currentTime: 1999, progress: 0 },
+                  { currentTime: 2000, progress: 1 }
+                ]
   }
 ];
 
-gStepTimingFunctionTests.forEach(function(options) {
+gStepAndFramesTimingFunctionTests.forEach(function(options) {
   test(function(t) {
     var target = createDiv(t);
     var animation = target.animate(null, options.effect);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webmessaging/README.md b/third_party/WebKit/LayoutTests/external/wpt/webmessaging/README.md
index 06b3a11..0b81aa0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webmessaging/README.md
+++ b/third_party/WebKit/LayoutTests/external/wpt/webmessaging/README.md
@@ -1,10 +1,2 @@
-This directory contains the HTML5 Web Messaging test suite.
-
-The following document contains a list of each test file in the test suite and the results of running the test file on several browsers <http://www.w3.org/wiki/Webapps/Interop/WebMessaging>.
-
-To run this test suite within a browser, go to: <http://w3c-test.org/web-platform-tests/master/webmessaging/>.
-
-The latest Editor's Draft of HTML5 Web Messaging is: <http://dev.w3.org/html5/postmsg/>.
-
-The latest W3C Technical Report of HTML5 Web Messaging is <http://www.w3.org/TR/webmessaging/>.
-
+These are the cross-document messaging (`postMessage()`) tests for the
+[cross-document messaging chapter of the HTML Standard](https://html.spec.whatwg.org/multipage/comms.html#web-messaging).
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/rtcpeerconnection/canTrickleIceCandidates-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/rtcpeerconnection/canTrickleIceCandidates-expected.txt
new file mode 100644
index 0000000..569a15f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/rtcpeerconnection/canTrickleIceCandidates-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+FAIL canTrickleIceCandidates property is null prior to setRemoteDescription assert_equals: canTrickleIceCandidates property is null expected (object) null but got (undefined) undefined
+FAIL canTrickleIceCandidates property is true after setRemoteDescription with a=ice-options:trickle promise_test: Unhandled rejection with value: object "OperationError: TEST_ERROR"
+FAIL canTrickleIceCandidates property is false after setRemoteDescription without a=ice-options:trickle promise_test: Unhandled rejection with value: object "OperationError: TEST_ERROR"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/rtcpeerconnection/canTrickleIceCandidates.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/rtcpeerconnection/canTrickleIceCandidates.html
new file mode 100644
index 0000000..63dac8f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/rtcpeerconnection/canTrickleIceCandidates.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<html>
+<head>
+  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  <title>RTCPeerConnection canTrickleIceCandidates tests</title>
+</head>
+<body>
+  <!-- These files are in place when executing on W3C. -->
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script type="text/javascript">
+  // tests support for RTCPeerConnection.canTrickleIceCandidates:
+  // http://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-cantrickleicecandidates
+  const sdp = 'v=0\r\n' +
+      'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
+      's=-\r\n' +
+      't=0 0\r\n' +
+      'a=ice-options:trickle\r\n' +
+      'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
+      'c=IN IP4 0.0.0.0\r\n' +
+      'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
+      'a=ice-ufrag:someufrag\r\n' +
+      'a=ice-pwd:somelongpwdwithenoughrandomness\r\n' +
+      'a=fingerprint:sha-256 8C:71:B3:8D:A5:38:FD:8F:A4:2E:A2:65:6C:86:52:BC:E0:6E:94:F2:9F:7C:4D:B5:DF:AF:AA:6F:44:90:8D:F4\r\n' +
+      'a=setup:actpass\r\n' +
+      'a=rtcp-mux\r\n' +
+      'a=mid:mid1\r\n' +
+      'a=sendonly\r\n' +
+      'a=msid:stream1 track1\r\n' +
+      'a=ssrc:1001 cname:some\r\n' +
+      'a=rtpmap:111 opus/48000/2\r\n';
+
+  test(function() {
+    var pc = new RTCPeerConnection();
+    assert_equals(pc.canTrickleIceCandidates, null, 'canTrickleIceCandidates property is null');
+  }, 'canTrickleIceCandidates property is null prior to setRemoteDescription');
+
+  promise_test(function() {
+    var pc = new RTCPeerConnection();
+
+    return pc.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp}))
+    .then(function() {
+      assert_true(pc.canTrickleIceCandidates, 'canTrickleIceCandidates property is true after setRemoteDescription');
+    })
+  }, 'canTrickleIceCandidates property is true after setRemoteDescription with a=ice-options:trickle');
+
+  promise_test(function() {
+    var pc = new RTCPeerConnection();
+
+    return pc.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp.replace('a=ice-options:trickle\r\n', '')}))
+    .then(function() {
+      assert_false(pc.canTrickleIceCandidates, 'canTrickleIceCandidates property is false after setRemoteDescription');
+    })
+  }, 'canTrickleIceCandidates property is false after setRemoteDescription without a=ice-options:trickle');
+</script>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webstorage/README.md b/third_party/WebKit/LayoutTests/external/wpt/webstorage/README.md
index 298028c..6b70aa5 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webstorage/README.md
+++ b/third_party/WebKit/LayoutTests/external/wpt/webstorage/README.md
@@ -1,10 +1,2 @@
-This directory contains the Web Storage test suite.
-
-The spec's Implementation Report contains a list of each test file in the test suite and the results of running the test file on several browsers <http://www.w3.org/wiki/Webapps/Interop/WebStorage>.
-
-To run this test suite within a browser, go to: <http://w3c-test.org/webstorage/>.
-
-A W3C Recommendation of Web Storage was published on 30 July 2013 <http://www.w3.org/TR/2013/REC-webstorage-20130730/>.
-
-Latest Editor's Draft of Web Storage is: <http://dev.w3.org/html5/webstorage/>.
-
+These are the storage (`localStorage`, `sessionStorage`) tests for the
+[Web storage chapter of the HTML Standard](https://html.spec.whatwg.org/multipage/webstorage.html).
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webstorage/storage_local-manual.html b/third_party/WebKit/LayoutTests/external/wpt/webstorage/storage_local-manual.html
new file mode 100644
index 0000000..d039773
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webstorage/storage_local-manual.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebStorage Test: local storage</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<meta name="flags" content="interact">
+
+<h2>Description</h2>
+<p>
+  This test validates that store data using Local Storage which means that close the page, and re-open it, the data saved before should be loaded again.
+</p>
+
+<h2>Preconditions</h2>
+<ol class="instructions">
+  <li>
+    Click the "Clear" button, refresh the page once and then check if the page shows "You have viewed this page 1 time(s)"
+  </li>
+  <li>
+    Close the page, re-open it and then check if the page still shows "You have viewed this page 2 time(s)"
+  </li>
+  <li>
+    If the above two steps are all true the test case pass, otherwise it fail
+  </li>
+</ol>
+
+<p>
+  <h2>You have viewed this page
+  <span id="count">an untold number of</span>
+  time(s).</h2>
+  <button type="button" onclick="javascript:localStorage.pageLoadCount = 0;"><h3>Clear</h3></button>
+</p>
+
+<script>
+
+    if (!localStorage.pageLoadCount) {
+        localStorage.pageLoadCount = 0;
+    }
+    localStorage.pageLoadCount = parseInt(localStorage.pageLoadCount) + 1;
+    document.getElementById('count').textContent = localStorage.pageLoadCount;
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webstorage/storage_session-manual.html b/third_party/WebKit/LayoutTests/external/wpt/webstorage/storage_session-manual.html
new file mode 100644
index 0000000..c2676af
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/webstorage/storage_session-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>WebStorage Test: session storage</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<meta name="flags" content="interact">
+
+<h2>Description</h2>
+<p>
+  This test validates that store the data using Session Storage which means that even if you close the page, and re-open it, the data saved before should be lost.
+</p>
+
+<ol class="instructions">
+  <li>
+    Click the "Clear" button, refresh the page once and then check if the page shows "You have viewed this page 1 time(s)"
+  </li>
+  <li>
+    Close the page, re-open it and then check if the page still shows "You have viewed this page 1 time(s)"
+  </li>
+  <li>
+    If the above two steps are all true the test case pass, otherwise it fail.<br>
+  </li>
+</ol>
+
+<p>
+  <h2>You have viewed this page
+  <span id="count">an untold number of</span>
+  time(s).</h2>
+  <button type="button" onclick="javascript:sessionStorage.pageLoadCount = 0;"><h3>Clear</h3></button>
+</p>
+
+<script>
+
+    if (!sessionStorage.pageLoadCount) {
+        sessionStorage.pageLoadCount = 0;
+    }
+    sessionStorage.pageLoadCount = parseInt(sessionStorage.pageLoadCount) + 1;
+    document.getElementById('count').textContent = sessionStorage.pageLoadCount;
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webvtt/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webvtt/interfaces-expected.txt
deleted file mode 100644
index a980177..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/webvtt/interfaces-expected.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-This is a testharness.js-based test.
-Found 50 tests; 40 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
-FAIL VTTCue interface: existence and properties of interface object Cannot read property 'has_extended_attribute' of undefined
-PASS VTTCue interface object length 
-PASS VTTCue interface object name 
-FAIL VTTCue interface: existence and properties of interface prototype object Cannot read property 'has_extended_attribute' of undefined
-PASS VTTCue interface: existence and properties of interface prototype object's "constructor" property 
-PASS VTTCue interface: attribute region 
-PASS VTTCue interface: attribute vertical 
-PASS VTTCue interface: attribute snapToLines 
-PASS VTTCue interface: attribute line 
-FAIL VTTCue interface: attribute lineAlign assert_true: The prototype object must have a property "lineAlign" expected true got false
-PASS VTTCue interface: attribute position 
-FAIL VTTCue interface: attribute positionAlign assert_true: The prototype object must have a property "positionAlign" expected true got false
-PASS VTTCue interface: attribute size 
-PASS VTTCue interface: attribute align 
-PASS VTTCue interface: attribute text 
-PASS VTTCue interface: operation getCueAsHTML() 
-PASS VTTCue must be primary interface of new VTTCue(0, 1, "foo") 
-FAIL Stringification of new VTTCue(0, 1, "foo") Cannot read property 'has_stringifier' of undefined
-PASS VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "region" with the proper type (0) 
-PASS VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "vertical" with the proper type (1) 
-PASS VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "snapToLines" with the proper type (2) 
-FAIL VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "line" with the proper type (3) Unrecognized type [object Object],[object Object]
-FAIL VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "lineAlign" with the proper type (4) assert_inherits: property "lineAlign" not found in prototype chain
-FAIL VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "position" with the proper type (5) Unrecognized type [object Object],[object Object]
-FAIL VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "positionAlign" with the proper type (6) assert_inherits: property "positionAlign" not found in prototype chain
-PASS VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "size" with the proper type (7) 
-PASS VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "align" with the proper type (8) 
-PASS VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "text" with the proper type (9) 
-PASS VTTCue interface: new VTTCue(0, 1, "foo") must inherit property "getCueAsHTML" with the proper type (10) 
-PASS VTTRegion interface: existence and properties of interface object 
-PASS VTTRegion interface object length 
-PASS VTTRegion interface object name 
-FAIL VTTRegion interface: existence and properties of interface prototype object assert_equals: class string of VTTRegion.prototype expected "[object VTTRegionPrototype]" but got "[object VTTRegion]"
-PASS VTTRegion interface: existence and properties of interface prototype object's "constructor" property 
-PASS VTTRegion interface: attribute width 
-PASS VTTRegion interface: attribute lines 
-PASS VTTRegion interface: attribute regionAnchorX 
-PASS VTTRegion interface: attribute regionAnchorY 
-PASS VTTRegion interface: attribute viewportAnchorX 
-PASS VTTRegion interface: attribute viewportAnchorY 
-PASS VTTRegion interface: attribute scroll 
-PASS VTTRegion must be primary interface of new VTTRegion() 
-PASS Stringification of new VTTRegion() 
-PASS VTTRegion interface: new VTTRegion() must inherit property "width" with the proper type (0) 
-PASS VTTRegion interface: new VTTRegion() must inherit property "lines" with the proper type (1) 
-PASS VTTRegion interface: new VTTRegion() must inherit property "regionAnchorX" with the proper type (2) 
-PASS VTTRegion interface: new VTTRegion() must inherit property "regionAnchorY" with the proper type (3) 
-PASS VTTRegion interface: new VTTRegion() must inherit property "viewportAnchorX" with the proper type (4) 
-PASS VTTRegion interface: new VTTRegion() must inherit property "viewportAnchorY" with the proper type (5) 
-PASS VTTRegion interface: new VTTRegion() must inherit property "scroll" with the proper type (6) 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webvtt/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/webvtt/interfaces.html
deleted file mode 100644
index 8cc4bb94..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/webvtt/interfaces.html
+++ /dev/null
@@ -1,64 +0,0 @@
-<!doctype html>
-<title>WebVTT IDL tests</title>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/resources/WebIDLParser.js></script>
-<script src=/resources/idlharness.js></script>
-
-<h1>WebVTT IDL tests</h1>
-<div id=log></div>
-
-<script type=text/plain>
-enum AutoKeyword { "auto" };
-enum DirectionSetting { "" /* horizontal */, "rl", "lr" };
-enum AlignSetting { "start", "middle", "end", "left", "right" };
-[Constructor(double startTime, double endTime, DOMString text)]
-interface VTTCue : TextTrackCue {
-           attribute VTTRegion? region;
-           attribute DirectionSetting vertical;
-           attribute boolean snapToLines;
-           attribute (double or AutoKeyword) line;
-           attribute AlignSetting lineAlign;
-           attribute (double or AutoKeyword) position;
-           attribute AlignSetting positionAlign;
-           attribute double size;
-           attribute AlignSetting align;
-           attribute DOMString text;
-  DocumentFragment getCueAsHTML();
-};
-
-enum ScrollSetting { "" /* none */, "up" };
-[Constructor]
-interface VTTRegion {
-           attribute double width;
-           attribute long lines;
-           attribute double regionAnchorX;
-           attribute double regionAnchorY;
-           attribute double viewportAnchorX;
-           attribute double viewportAnchorY;
-           attribute ScrollSetting scroll;
-};
-</script>
-<script>
-"use strict";
-var idlArray;
-setup(function() {
-	idlArray = new IdlArray();
-	[].forEach.call(document.querySelectorAll("script[type=text\\/plain]"), function(node) {
-		if (node.className == "untested") {
-			idlArray.add_untested_idls(node.textContent);
-		} else {
-			idlArray.add_idls(node.textContent);
-		}
-	});
-}, {explicit_done:true});
-window.onload = function() {
-	idlArray.add_objects({
-		// WebVTT
-		VTTCue: ['new VTTCue(0, 1, "foo")'],
-		VTTRegion: ['new VTTRegion()']
-	});
-	idlArray.test();
-	done();
-};
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/workers/README.md b/third_party/WebKit/LayoutTests/external/wpt/workers/README.md
index 3a1c58f..78cc74371 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/workers/README.md
+++ b/third_party/WebKit/LayoutTests/external/wpt/workers/README.md
@@ -1,8 +1,2 @@
-This directory contains the Web Workers test suite.
-
-To run this test suite within a browser, go to: <http://w3c-test.org/web-platform-tests/master/workers/>.
-
-The latest Editor's Draft of Web Workers is: <http://dev.w3.org/html5/workers/>.
-
-The latest W3C Technical Report of Web Workers is <http://www.w3.org/TR/workers/>.
-
+These are the workers (`Worker`, `SharedWorker`) tests for the
+[Web workers chapter of the HTML Standard](https://html.spec.whatwg.org/multipage/workers.html).
diff --git a/third_party/WebKit/LayoutTests/fast/css/crash-in-attachFirstLetterTextLayoutObjects.html b/third_party/WebKit/LayoutTests/fast/css/crash-in-attachFirstLetterTextLayoutObjects.html
new file mode 100644
index 0000000..dcd8ddaf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/crash-in-attachFirstLetterTextLayoutObjects.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<style>
+.c3 { -webkit-appearance: button; }
+.c3:nth-last-child(even) { display: table-row; }
+.c14 { float: left; }
+.c14::first-letter { float: inherit; }
+</style>
+<div id="div" class="c14">
+	<div class="c3">
+		Test passes if it doesn't crash.
+	</div>
+</div>
+<script>
+test(function() {
+	setTimeout('div.appendChild(document.createElement("div"));', 0);
+	assert_true(true, "Should not crash");
+}, "Check that we clear pseudoElement from ElementRareData when FirstLetterPseudoElement doesn't have a LayoutObject");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/bindings/dynamic-bindings-frame-attach-detach-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/bindings/dynamic-bindings-frame-attach-detach-expected.txt
index b7df14c6..0541f07 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/bindings/dynamic-bindings-frame-attach-detach-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/bindings/dynamic-bindings-frame-attach-detach-expected.txt
@@ -31,10 +31,11 @@
 [+] _test_attachFrame.js
 
 Running: detachFrame
-Removed: 2 uiSourceCodes
+Removed: 3 uiSourceCodes
+[-] dynamic-script.js
 [-] dynamic-style.css
 [-] http://127.0.0.1:8000/inspector/bindings/resources/dynamic-frame.html
-Workspace: 14 uiSourceCodes.
+Workspace: 13 uiSourceCodes.
     debugger:///VM[XXX] bindings-test.js
     debugger:///VM[XXX] dynamic-bindings-frame-attach-detach.html
     debugger:///VM[XXX] dynamic-bindings-frame-attach-detach.html
@@ -43,7 +44,6 @@
     debugger:///VM[XXX] inspector-test.js
     debugger:///VM[XXX] _test_attachFrame.js
 [+] debugger:///VM[XXX] _test_detachFrame.js
-    dynamic-script.js
     http://127.0.0.1:8000/inspector/bindings/bindings-test.js
     http://127.0.0.1:8000/inspector/bindings/dynamic-bindings-frame-attach-detach.html
     http://127.0.0.1:8000/inspector/inspector-test.js
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 f611d11..a874845 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
@@ -36,7 +36,7 @@
             {
                 InspectorTest.addResult("compiled.js UISourceCode arrived");
                 originalUISourceCode = uiSourceCode;
-                for (var s of Object.values(debuggerModel.scripts)) {
+                for (var s of debuggerModel.scripts()) {
                     if (s.sourceURL.endsWith("compiled.js")) {
                         InspectorTest.addResult("compiled.js script found");
                         script = s;
@@ -107,7 +107,7 @@
             function compiledUISourceCodeAdded(uiSourceCode)
             {
                 InspectorTest.addResult("compiled.js UISourceCode arrived");
-                for (var s of Object.values(debuggerModel.scripts)) {
+                for (var s of debuggerModel.scripts()) {
                     if (s.sourceMapURL && s.sourceMapURL.startsWith("data:application")) {
                         InspectorTest.addResult("compiled.js script found");
                         script = s;
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
index d36a55e..e3f5b2e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
@@ -574,13 +574,8 @@
 
 InspectorTest.queryScripts = function(filter)
 {
-    var scripts = [];
-    for (var scriptId in InspectorTest.debuggerModel._scripts) {
-        var script = InspectorTest.debuggerModel._scripts[scriptId];
-        if (!filter || filter(script))
-            scripts.push(script);
-    }
-    return scripts;
+    var scripts = InspectorTest.debuggerModel.scripts();
+    return filter ? scripts.filter(filter) : scripts;
 };
 
 InspectorTest.createScriptMock = function(url, startLine, startColumn, isContentScript, source, target, preRegisterCallback)
diff --git a/third_party/WebKit/LayoutTests/inspector-enabled/sources/debugger/linkifier.html b/third_party/WebKit/LayoutTests/inspector-enabled/sources/debugger/linkifier.html
index 26900aa6..2803476 100644
--- a/third_party/WebKit/LayoutTests/inspector-enabled/sources/debugger/linkifier.html
+++ b/third_party/WebKit/LayoutTests/inspector-enabled/sources/debugger/linkifier.html
@@ -43,9 +43,7 @@
 
     function debuggerTest()
     {
-        var scripts = InspectorTest.debuggerModel.scripts;
-        for (var scriptId in scripts) {
-            var scriptCandidate = scripts[scriptId];
+        for (var scriptCandidate of InspectorTest.debuggerModel.scripts()) {
             if (scriptCandidate.sourceURL === InspectorTest.mainTarget.inspectedURL() && scriptCandidate.lineOffset === 4) {
                 script = scriptCandidate;
                 break;
diff --git a/third_party/WebKit/LayoutTests/inspector/components/linkifier.html b/third_party/WebKit/LayoutTests/inspector/components/linkifier.html
index 46e73ed..8158ca4 100644
--- a/third_party/WebKit/LayoutTests/inspector/components/linkifier.html
+++ b/third_party/WebKit/LayoutTests/inspector/components/linkifier.html
@@ -18,9 +18,7 @@
     {
         var target = SDK.targetManager.mainTarget();
         var url = target.inspectedURL();
-        var scripts = InspectorTest.debuggerModel.scripts;
-        for (var scriptId in scripts) {
-            var scriptCandidate = scripts[scriptId];
+        for (var scriptCandidate of InspectorTest.debuggerModel.scripts()) {
             if (scriptCandidate.sourceURL === url) {
                 script = scriptCandidate;
                 break;
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment.html
index 259533d..75e32f3 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/source-url-comment.html
@@ -54,10 +54,9 @@
 {
     function forEachScriptMatchingURL(url, handler)
     {
-        var scripts = InspectorTest.debuggerModel._scripts;
-        for (var id in scripts) {
-            if (scripts[id].sourceURL.indexOf(url) !== -1)
-                handler(scripts[id]);
+        for (var script of InspectorTest.debuggerModel.scripts()) {
+            if (script.sourceURL.indexOf(url) !== -1)
+                handler(script);
         }
     }
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
index baf644b..6182a61e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
@@ -6,6 +6,7 @@
 PASS A steps(1) function on a keyframe affects the resulting style 
 PASS A steps(1, end) function on a keyframe affects the resulting style 
 PASS A steps(2, end) function on a keyframe affects the resulting style 
+FAIL A frames function on a keyframe affects the resulting style Failed to execute 'animate' on 'Element': 'frames(5)' is not a valid value for easing
 PASS A linear function on a keyframe affects the resulting style 
 FAIL A ease function on a keyframe affects the resulting style assert_approx_equals: The width should be approximately 109.47963055884654 at 1100ms expected 109.47963055884654 +/- 0.01 but got 109.312
 PASS A ease-in function on a keyframe affects the resulting style 
@@ -20,6 +21,7 @@
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(1) function does not alter the result 
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(1, end) function does not alter the result 
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(2, end) function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 500ms expected "50.3438px" but got "50px"
+FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a frames function does not alter the result Failed to execute 'animate' on 'Element': 'frames(5)' is not a valid value for easing
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a linear function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "25.0938px" but got "25px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "41.875px" but got "41.8594px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease-in function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "8.95312px" but got "9.32812px"
@@ -27,15 +29,5 @@
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease-out function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "38.0469px" but got "37.9688px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a easing function which produces values greater than 1 does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "100px" but got "102.406px"
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a easing function which produces values less than 1 does not alter the result 
-FAIL step-start easing with input progress greater than 1 assert_equals: expected "200px" but got "100px"
-PASS step-end easing with input progress greater than 1 
-FAIL step-end easing with input progress greater than 2 assert_equals: expected "200px" but got "100px"
-PASS step-start easing with input progress less than 0 
-FAIL step-start easing with input progress less than -1 assert_equals: expected "-100px" but got "0px"
-FAIL step-end easing with input progress less than 0 assert_equals: expected "-100px" but got "0px"
-FAIL cubic-bezier easing with input progress greater than 1 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress greater than 1 and where the tangent on the upper boundary is infinity Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress less than 0 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress less than 0 and where the tangent on the lower boundary is infinity Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-filter-expected.png
deleted file mode 100644
index 7c96b563..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/images/color-profile-filter-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
index f7983ce6..17c669dd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
deleted file mode 100644
index 37a31d5..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
index 090e845e..fb3518b41 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-filter-expected.png
deleted file mode 100644
index 532bf5a..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-filter-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
new file mode 100644
index 0000000..ac896d7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
index cd608a0..50363d7 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
new file mode 100644
index 0000000..d8ddf81
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-filter-expected.png
deleted file mode 100644
index bb4a79d..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-filter-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
index baf644b..6182a61e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
@@ -6,6 +6,7 @@
 PASS A steps(1) function on a keyframe affects the resulting style 
 PASS A steps(1, end) function on a keyframe affects the resulting style 
 PASS A steps(2, end) function on a keyframe affects the resulting style 
+FAIL A frames function on a keyframe affects the resulting style Failed to execute 'animate' on 'Element': 'frames(5)' is not a valid value for easing
 PASS A linear function on a keyframe affects the resulting style 
 FAIL A ease function on a keyframe affects the resulting style assert_approx_equals: The width should be approximately 109.47963055884654 at 1100ms expected 109.47963055884654 +/- 0.01 but got 109.312
 PASS A ease-in function on a keyframe affects the resulting style 
@@ -20,6 +21,7 @@
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(1) function does not alter the result 
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(1, end) function does not alter the result 
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(2, end) function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 500ms expected "50.3438px" but got "50px"
+FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a frames function does not alter the result Failed to execute 'animate' on 'Element': 'frames(5)' is not a valid value for easing
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a linear function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "25.0938px" but got "25px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "41.875px" but got "41.8594px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease-in function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "8.95312px" but got "9.32812px"
@@ -27,15 +29,5 @@
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease-out function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "38.0469px" but got "37.9688px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a easing function which produces values greater than 1 does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "100px" but got "102.406px"
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a easing function which produces values less than 1 does not alter the result 
-FAIL step-start easing with input progress greater than 1 assert_equals: expected "200px" but got "100px"
-PASS step-end easing with input progress greater than 1 
-FAIL step-end easing with input progress greater than 2 assert_equals: expected "200px" but got "100px"
-PASS step-start easing with input progress less than 0 
-FAIL step-start easing with input progress less than -1 assert_equals: expected "-100px" but got "0px"
-FAIL step-end easing with input progress less than 0 assert_equals: expected "-100px" but got "0px"
-FAIL cubic-bezier easing with input progress greater than 1 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress greater than 1 and where the tangent on the upper boundary is infinity Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress less than 0 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress less than 0 and where the tangent on the lower boundary is infinity Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
index acb572ba..9dd5995 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-filter-expected.png
index 6d30485..f5e737e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange-expected.txt
index 13e0686..82c26a0 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange-expected.txt
@@ -23,6 +23,8 @@
 PASS input setSelectionRange(NaN,1) 
 PASS input setSelectionRange(null,1) 
 PASS input setSelectionRange(undefined,1) 
+PASS input setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1) 
+PASS input setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1) 
 PASS input setSelectionRange fires a select event 
 PASS test of textarea.setSelectionRange 
 PASS textarea typeof(input.setSelectionRange)' 
@@ -44,5 +46,7 @@
 PASS textarea setSelectionRange(NaN,1) 
 PASS textarea setSelectionRange(null,1) 
 PASS textarea setSelectionRange(undefined,1) 
+PASS textarea setSelectionRange(Math.pow(2,32) - 2, Math.pow(2,32) - 1) 
+PASS textarea setSelectionRange(Math.pow(2,31), Math.pow(2,32) - 1) 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
index f967c05..9cd7b3c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/external/wpt/web-animations/animation-model/keyframe-effects/effect-value-transformed-distance-expected.txt
@@ -6,6 +6,7 @@
 PASS A steps(1) function on a keyframe affects the resulting style 
 PASS A steps(1, end) function on a keyframe affects the resulting style 
 PASS A steps(2, end) function on a keyframe affects the resulting style 
+FAIL A frames function on a keyframe affects the resulting style Failed to execute 'animate' on 'Element': 'frames(5)' is not a valid value for easing
 PASS A linear function on a keyframe affects the resulting style 
 FAIL A ease function on a keyframe affects the resulting style assert_approx_equals: The width should be approximately 109.47963055884654 at 1100ms expected 109.47963055884654 +/- 0.01 but got 109.313
 PASS A ease-in function on a keyframe affects the resulting style 
@@ -20,6 +21,7 @@
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(1) function does not alter the result 
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(1, end) function does not alter the result 
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a steps(2, end) function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 500ms expected "50.3438px" but got "50px"
+FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a frames function does not alter the result Failed to execute 'animate' on 'Element': 'frames(5)' is not a valid value for easing
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a linear function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "25.0938px" but got "25px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "41.875px" but got "41.8594px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease-in function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "8.95313px" but got "9.32813px"
@@ -27,15 +29,5 @@
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a ease-out function does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "38.0469px" but got "37.9688px"
 FAIL Linear-equivalent cubic-bezier keyframe easing applied to an effect with a easing function which produces values greater than 1 does not alter the result assert_equals: The 'width' of the animated elements should be equal at 250ms expected "100px" but got "102.406px"
 PASS Linear-equivalent cubic-bezier keyframe easing applied to an effect with a easing function which produces values less than 1 does not alter the result 
-FAIL step-start easing with input progress greater than 1 assert_equals: expected "200px" but got "100px"
-PASS step-end easing with input progress greater than 1 
-FAIL step-end easing with input progress greater than 2 assert_equals: expected "200px" but got "100px"
-PASS step-start easing with input progress less than 0 
-FAIL step-start easing with input progress less than -1 assert_equals: expected "-100px" but got "0px"
-FAIL step-end easing with input progress less than 0 assert_equals: expected "-100px" but got "0px"
-FAIL cubic-bezier easing with input progress greater than 1 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress greater than 1 and where the tangent on the upper boundary is infinity Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress less than 0 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL cubic-bezier easing with input progress less than 0 and where the tangent on the lower boundary is infinity Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
index 0e9b635..ae9d742 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
index ce69279..37a31d5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
new file mode 100644
index 0000000..24ad71a0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu-rasterization/images/color-profile-background-clip-text-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
deleted file mode 100644
index f73a3ac..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
index 129c660ee..1f6a479 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
@@ -18,8 +18,8 @@
           handle => this.bindingSet_.addBinding(this, handle));
     }
 
-    detect(bitmap_data) {
-      let receivedStruct = new Uint8Array(bitmap_data.pixel_data);
+    detect(frame_data, width, height) {
+      let receivedStruct = mojo.mapBuffer(frame_data, 0, width*height*4, 0);
       this.buffer_data_ = new Uint32Array(receivedStruct.buffer);
       return Promise.resolve({
         results: [
@@ -45,6 +45,7 @@
           },
         ],
       });
+      mojo.unmapBuffer(receivedStruct.buffer);
     }
 
     getFrameData() {
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
index c02fda2..1faf89f 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
@@ -44,8 +44,8 @@
                                            request);
     }
 
-    detect(bitmap_data) {
-      let receivedStruct = new Uint8Array(bitmap_data.pixel_data);
+    detect(frame_data, width, height) {
+      let receivedStruct = mojo.mapBuffer(frame_data, 0, width*height*4, 0);
       this.buffer_data_ = new Uint32Array(receivedStruct.buffer);
       return Promise.resolve({
         result: {
@@ -56,6 +56,7 @@
           ]
         }
       });
+      mojo.unmapBuffer(receivedStruct.buffer);
     }
   }
   return new MockFaceDetectionProvider();
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-textdetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-textdetection.js
index a622605..08195c9 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-textdetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-textdetection.js
@@ -17,8 +17,8 @@
           handle => this.bindingSet_.addBinding(this, handle));
     }
 
-    detect(bitmap_data) {
-      let receivedStruct = new Uint8Array(bitmap_data.pixel_data);
+    detect(frame_data, width, height) {
+      let receivedStruct = mojo.mapBuffer(frame_data, 0, width*height*4, 0);
       this.buffer_data_ = new Uint32Array(receivedStruct.buffer);
       return Promise.resolve({
         results: [
@@ -32,6 +32,7 @@
           },
         ],
       });
+      mojo.unmapBuffer(receivedStruct.buffer);
     }
 
     getFrameData() {
diff --git a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
index e5d83d4..b3796ad 100644
--- a/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
+++ b/third_party/WebKit/LayoutTests/webaudio/AudioParam/audioparam-update-value-attribute.html
@@ -33,7 +33,7 @@
             message: "linearRamp(" + v1 + ", " + t1 + ")",
             errorThreshold: 1.1650e-6
           };
-        }).then(done);
+        }).then(() => task.done());
       });
 
       audit.define("exponential", (task, should) => {
@@ -47,7 +47,7 @@
             message: "exponentialRamp(" + v1 + ", " + t1 + ")",
             errorThreshold: 7.4601e-7
           };
-        }).then(done);
+        }).then(() => task.done());
       });
 
       audit.define("setTarget", (task, should) => {
@@ -63,7 +63,7 @@
             message: "setTargetAtTime(" + vFinal + ", " + t0 + ", " + timeConstant + ")",
             errorThreshold: 2.2599e-6
           };
-        }).then(done);
+        }).then(() => task.done());
       });
 
       audit.define("setValueCurve", (task, should) => {
@@ -79,7 +79,7 @@
             message: "setValueCurveAtTime([" + curve + "], " + t0 + ", " + duration + ")",
             errorThreshold: 7.9577e-8
           };
-        }).then(done);
+        }).then(() => task.done());
       });
 
       audit.run();
diff --git a/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
index 63f0d38..6e06e7e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
+++ b/third_party/WebKit/LayoutTests/webaudio/DynamicsCompressor/dynamicscompressor-basic.html
@@ -37,7 +37,7 @@
     should(compressor.reduction, "compressor.reduction")
       .beEqualTo(0);
 
-    done();
+    task.done();
 });
 
 audit.run();
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
index 0efc7c9..b2b85c9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
@@ -96,7 +96,7 @@
 PASS   node.channelCountMode is equal to max. 
 PASS   node.channelInterpretation = mode did not throw an exception. 
 PASS   node.channelInterpretation is equal to speakers. 
-PASS   context.destination.channelCount = 99 threw IndexSizeError: "Failed to set the 'channelCount' property on 'AudioNode': The channel count provided (99) is outside the range [1, 2].". 
+PASS   context.destination.channelCount = 99 threw IndexSizeError: [error message omitted]. 
 PASS < [channel-stuff] All assertions passed. (total 7 assertions) 
 PASS > [audioparam]  
 PASS   param.setValueCurveAtTime(null, 0, 0) threw TypeError: "Failed to execute 'setValueCurveAtTime' on 'AudioParam': parameter 1 is not of type 'Float32Array'.". 
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
index 7991159..436fd83a 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
@@ -323,7 +323,7 @@
       should(
           () => context.destination.channelCount = 99,
           'context.destination.channelCount = 99')
-          .throw('IndexSizeError');
+          .throw('IndexSizeError', { omitErrorMessage: true });
 
       task.done();
     });
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/audit.js b/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
index d2946161..f73cd58 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
@@ -15,7 +15,7 @@
 
   'use strict';
 
-  // Selected properties from testharness.js
+  // Selected methods from testharness.js.
   let testharnessProperties = [
     'test', 'async_test', 'promise_test', 'promise_rejects',
     'generate_tests', 'setup', 'done', 'assert_true', 'assert_false'
@@ -55,6 +55,13 @@
     throw new Error(message);
   }
 
+  // TODO(hongchan): remove this hack after confirming all the tests are
+  // finished correctly. (crbug.com/708817)
+  const _testharnessDone = window.done;
+  window.done = () => {
+    _throwException('Do NOT call done() method from the test code.');
+  };
+
   // Generate a descriptive string from a target value in various types.
   function _generateDescription (target, options) {
     let targetString;
@@ -269,10 +276,15 @@
      *   should(() => { let a = b; }, 'A bad code').throw();
      *   should(() => { let c = d; }, 'Assigning d to c.')
      *       .throw('ReferenceError');
+     *   should(() => { let e = f; }, 'Assigning e to f.')
+     *       .throw('ReferenceError', { omitErrorMessage: true });
      *
      * @result
-     *   "PASS   A bad code threw an exception of ReferenceError."
-     *   "PASS   Assigning d to c threw ReferenceError."
+     *   "PASS   A bad code threw an exception of ReferenceError: b is not
+     *       defined."
+     *   "PASS   Assigning d to c threw ReferenceError: d is not defined."
+     *   "PASS   Assigning e to f threw ReferenceError: [error message
+     *       omitted]."
      */
     throw () {
       this._processArguments(arguments);
@@ -287,16 +299,17 @@
         // Catch did not happen, so the test is failed.
         failDetail = '${actual} did not throw an exception.';
       } catch (error) {
+        let errorMessage = this._options.omitErrorMessage
+            ? ': [error message omitted]'
+            : ': "' + error.message + '"';
         if (this._expected === null || this._expected === undefined) {
           // The expected error type was not given.
           didThrowCorrectly = true;
-          passDetail = '${actual} threw ' + error.name + ': "'
-              + error.message + '".';
+          passDetail = '${actual} threw ' + error.name + errorMessage + '.';
         } else if (error.name === this._expected) {
           // The expected error type match the actual one.
           didThrowCorrectly = true;
-          passDetail = '${actual} threw ${expected}: "'
-              + error.message + '".';
+          passDetail = '${actual} threw ${expected}' + errorMessage + '.';
         } else {
           didThrowCorrectly = false;
           failDetail = '${actual} threw "' + error.name
@@ -1137,7 +1150,7 @@
 
       // From testharness.js, report back to the test infrastructure that
       // the task runner completed all the tasks.
-      done();
+      _testharnessDone();
     }
 
     // |taskLabel| can be either a string or a dictionary. See Task constructor
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn
index 9d7769d..22f637f 100644
--- a/third_party/WebKit/Source/core/BUILD.gn
+++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -474,6 +474,7 @@
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFontVariantLigatures.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFontVariantNumeric.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIFontVariationSettings.h",
+    "$blink_core_output_dir/css/properties/CSSPropertyAPIFragmentation.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridAutoFlow.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridAutoLine.h",
     "$blink_core_output_dir/css/properties/CSSPropertyAPIGridLine.h",
diff --git a/third_party/WebKit/Source/core/css/CSSMatrix.cpp b/third_party/WebKit/Source/core/css/CSSMatrix.cpp
index 00e9377..afd86df 100644
--- a/third_party/WebKit/Source/core/css/CSSMatrix.cpp
+++ b/third_party/WebKit/Source/core/css/CSSMatrix.cpp
@@ -46,6 +46,10 @@
                              const String& s,
                              ExceptionState& exceptionState) {
   UseCounter::count(executionContext, UseCounter::WebKitCSSMatrix);
+  if (!s.isEmpty()) {
+    UseCounter::count(executionContext,
+                      UseCounter::WebkitCSSMatrixConstructFromString);
+  }
   return new CSSMatrix(s, exceptionState);
 }
 
diff --git a/third_party/WebKit/Source/core/css/WebKitCSSMatrix.idl b/third_party/WebKit/Source/core/css/WebKitCSSMatrix.idl
index 3610766..d9227cf0 100644
--- a/third_party/WebKit/Source/core/css/WebKitCSSMatrix.idl
+++ b/third_party/WebKit/Source/core/css/WebKitCSSMatrix.idl
@@ -56,7 +56,7 @@
     attribute unrestricted double m43;
     attribute unrestricted double m44;
 
-    [RaisesException] void setMatrixValue([Default=Undefined] optional DOMString string);
+    [RaisesException, MeasureAs=WebkitCSSMatrixSetMatrixValue] void setMatrixValue([Default=Undefined] optional DOMString string);
 
     // Multiply this matrix by secondMatrix, on the right (result = this * secondMatrix)
     [LegacyInterfaceTypeChecking] WebKitCSSMatrix multiply([Default=Undefined] optional WebKitCSSMatrix secondMatrix);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 49f2fb29..227bcb1d 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -1837,8 +1837,10 @@
   // statement.
   const CSSPropertyDescriptor& cssPropertyDesc =
       CSSPropertyDescriptor::get(property);
-  if (cssPropertyDesc.parseSingleValue)
-    return cssPropertyDesc.parseSingleValue(m_range, m_context);
+  if (cssPropertyDesc.parseSingleValue) {
+    DCHECK(m_context);
+    return cssPropertyDesc.parseSingleValue(m_range, *m_context);
+  }
 
   switch (property) {
     case CSSPropertyFontFeatureSettings:
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignItems.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignItems.cpp
index c8a956ac..790c98d 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignItems.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignItems.cpp
@@ -12,7 +12,7 @@
 
 const CSSValue* CSSPropertyAPIAlignItems::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   // align-items property does not allow the 'auto' value.
   if (CSSPropertyParserHelpers::identMatches<CSSValueAuto>(range.peek().id()))
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignOrJustifyContent.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignOrJustifyContent.cpp
index 2db116e..a5382571 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignOrJustifyContent.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignOrJustifyContent.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIAlignOrJustifyContent::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   return CSSPropertyAlignmentUtils::consumeContentDistributionOverflowPosition(
       range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignOrJustifySelf.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignOrJustifySelf.cpp
index 25628292..57112ff 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignOrJustifySelf.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIAlignOrJustifySelf.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIAlignOrJustifySelf::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   return CSSPropertyAlignmentUtils::consumeSelfPositionOverflowPosition(range);
 }
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBaselineShift.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBaselineShift.cpp
index 70ee0a5..892f707 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBaselineShift.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBaselineShift.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIBaselineShift::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValueID id = range.peek().id();
   if (id == CSSValueBaseline || id == CSSValueSub || id == CSSValueSuper)
     return CSSPropertyParserHelpers::consumeIdent(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderRadius.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderRadius.cpp
index 1515760..31d4fad5 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderRadius.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIBorderRadius.cpp
@@ -12,13 +12,13 @@
 
 const CSSValue* CSSPropertyAPIBorderRadius::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValue* parsedValue1 = CSSPropertyParserHelpers::consumeLengthOrPercent(
-      range, context->mode(), ValueRangeNonNegative);
+      range, context.mode(), ValueRangeNonNegative);
   if (!parsedValue1)
     return nullptr;
   CSSValue* parsedValue2 = CSSPropertyParserHelpers::consumeLengthOrPercent(
-      range, context->mode(), ValueRangeNonNegative);
+      range, context.mode(), ValueRangeNonNegative);
   if (!parsedValue2)
     parsedValue2 = parsedValue1;
   return CSSValuePair::create(parsedValue1, parsedValue2,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPICaretColor.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPICaretColor.cpp
index 6dcdcdb8..4fcb91cc 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPICaretColor.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPICaretColor.cpp
@@ -11,10 +11,10 @@
 
 const CSSValue* CSSPropertyAPICaretColor::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
-  return CSSPropertyParserHelpers::consumeColor(range, context->mode());
+  return CSSPropertyParserHelpers::consumeColor(range, context.mode());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIClip.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIClip.cpp
index 25699b44..77f0bdc 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIClip.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIClip.cpp
@@ -25,7 +25,7 @@
 
 const CSSValue* CSSPropertyAPIClip::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
 
@@ -34,22 +34,22 @@
 
   CSSParserTokenRange args = CSSPropertyParserHelpers::consumeFunction(range);
   // rect(t, r, b, l) || rect(t r b l)
-  CSSValue* top = consumeClipComponent(args, context->mode());
+  CSSValue* top = consumeClipComponent(args, context.mode());
   if (!top)
     return nullptr;
   bool needsComma =
       CSSPropertyParserHelpers::consumeCommaIncludingWhitespace(args);
-  CSSValue* right = consumeClipComponent(args, context->mode());
+  CSSValue* right = consumeClipComponent(args, context.mode());
   if (!right ||
       (needsComma &&
        !CSSPropertyParserHelpers::consumeCommaIncludingWhitespace(args)))
     return nullptr;
-  CSSValue* bottom = consumeClipComponent(args, context->mode());
+  CSSValue* bottom = consumeClipComponent(args, context.mode());
   if (!bottom ||
       (needsComma &&
        !CSSPropertyParserHelpers::consumeCommaIncludingWhitespace(args)))
     return nullptr;
-  CSSValue* left = consumeClipComponent(args, context->mode());
+  CSSValue* left = consumeClipComponent(args, context.mode());
   if (!left || !args.atEnd())
     return nullptr;
   return CSSQuadValue::create(top, right, bottom, left,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIClipPath.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIClipPath.cpp
index e89bc22..91c739d 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIClipPath.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIClipPath.cpp
@@ -12,12 +12,12 @@
 
 const CSSValue* CSSPropertyAPIClipPath::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
-  if (CSSURIValue* url = CSSPropertyParserHelpers::consumeUrl(range, context))
+  if (CSSURIValue* url = CSSPropertyParserHelpers::consumeUrl(range, &context))
     return url;
-  return CSSPropertyShapeUtils::consumeBasicShape(range, context);
+  return CSSPropertyShapeUtils::consumeBasicShape(range, &context);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColor.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColor.cpp
index 00a1ed2..fb4bf67 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColor.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColor.cpp
@@ -11,8 +11,8 @@
 
 const CSSValue* CSSPropertyAPIColor::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return CSSPropertyParserHelpers::consumeColor(range, context->mode());
+    const CSSParserContext& context) {
+  return CSSPropertyParserHelpers::consumeColor(range, context.mode());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnCount.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnCount.cpp
index 585f6b9..7f56e15 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnCount.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnCount.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIColumnCount::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyColumnUtils::consumeColumnCount(range);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnGap.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnGap.cpp
index 1934b94b..cc3374b 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnGap.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnGap.cpp
@@ -11,10 +11,10 @@
 
 const CSSValue* CSSPropertyAPIColumnGap::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNormal)
     return CSSPropertyParserHelpers::consumeIdent(range);
-  return CSSPropertyParserHelpers::consumeLength(range, context->mode(),
+  return CSSPropertyParserHelpers::consumeLength(range, context.mode(),
                                                  ValueRangeNonNegative);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnRuleWidth.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnRuleWidth.cpp
index d3cbcf23..d757b68 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnRuleWidth.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnRuleWidth.cpp
@@ -11,9 +11,9 @@
 
 const CSSValue* CSSPropertyAPIColumnRuleWidth::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeLineWidth(
-      range, context->mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
+      range, context.mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnSpan.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnSpan.cpp
index b727ee2..1cd8408d 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnSpan.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnSpan.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIColumnSpan::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeIdent<CSSValueAll, CSSValueNone>(
       range);
 }
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnWidth.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnWidth.cpp
index 0406848..f85abaf 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnWidth.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIColumnWidth.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIColumnWidth::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyColumnUtils::consumeColumnWidth(range);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContain.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContain.cpp
index c984337..a020cd9 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContain.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContain.cpp
@@ -13,7 +13,7 @@
 // none | strict | content | [ layout || style || paint || size ]
 const CSSValue* CSSPropertyAPIContain::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValueID id = range.peek().id();
   if (id == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContent.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContent.cpp
index 401b6250..b922d517 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContent.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIContent.cpp
@@ -72,7 +72,7 @@
 
 const CSSValue* CSSPropertyAPIContent::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (CSSPropertyParserHelpers::identMatches<CSSValueNone, CSSValueNormal>(
           range.peek().id()))
     return CSSPropertyParserHelpers::consumeIdent(range);
@@ -81,7 +81,7 @@
 
   do {
     CSSValue* parsedValue =
-        CSSPropertyParserHelpers::consumeImage(range, context);
+        CSSPropertyParserHelpers::consumeImage(range, &context);
     if (!parsedValue) {
       parsedValue = CSSPropertyParserHelpers::consumeIdent<
           CSSValueOpenQuote, CSSValueCloseQuote, CSSValueNoOpenQuote,
@@ -92,7 +92,7 @@
     if (!parsedValue) {
       if (range.peek().functionId() == CSSValueAttr) {
         parsedValue = consumeAttr(
-            CSSPropertyParserHelpers::consumeFunction(range), context);
+            CSSPropertyParserHelpers::consumeFunction(range), &context);
       } else if (range.peek().functionId() == CSSValueCounter) {
         parsedValue = consumeCounterContent(
             CSSPropertyParserHelpers::consumeFunction(range), false);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPICursor.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPICursor.cpp
index dc663be..c1b7250 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPICursor.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPICursor.cpp
@@ -15,11 +15,11 @@
 
 const CSSValue* CSSPropertyAPICursor::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  bool inQuirksMode = isQuirksModeBehavior(context->mode());
+    const CSSParserContext& context) {
+  bool inQuirksMode = isQuirksModeBehavior(context.mode());
   CSSValueList* list = nullptr;
   while (CSSValue* image = CSSPropertyParserHelpers::consumeImage(
-             range, context,
+             range, &context,
              CSSPropertyParserHelpers::ConsumeGeneratedImagePolicy::Forbid)) {
     double num;
     IntPoint hotSpot(-1, -1);
@@ -44,9 +44,9 @@
   CSSValueID id = range.peek().id();
   if (!range.atEnd()) {
     if (id == CSSValueWebkitZoomIn)
-      context->count(UseCounter::PrefixedCursorZoomIn);
+      context.count(UseCounter::PrefixedCursorZoomIn);
     else if (id == CSSValueWebkitZoomOut)
-      context->count(UseCounter::PrefixedCursorZoomOut);
+      context.count(UseCounter::PrefixedCursorZoomOut);
   }
   CSSValue* cursorType = nullptr;
   if (id == CSSValueHand) {
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFlexBasis.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFlexBasis.cpp
index 6fd88d592..6ed445b 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFlexBasis.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFlexBasis.cpp
@@ -11,12 +11,12 @@
 
 const CSSValue* CSSPropertyAPIFlexBasis::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   // FIXME: Support intrinsic dimensions too.
   if (range.peek().id() == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
   return CSSPropertyParserHelpers::consumeLengthOrPercent(
-      range, context->mode(), ValueRangeNonNegative);
+      range, context.mode(), ValueRangeNonNegative);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontFamily.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontFamily.cpp
index b8989bf..1ec596a 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontFamily.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontFamily.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPIFontFamily::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext*) {
+    const CSSParserContext&) {
   return CSSPropertyFontUtils::consumeFontFamily(range);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontSize.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontSize.cpp
index ae0f48aa..c5cb3e51 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontSize.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontSize.cpp
@@ -12,9 +12,9 @@
 
 const CSSValue* CSSPropertyAPIFontSize::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyFontUtils::consumeFontSize(
-      range, context->mode(), CSSPropertyParserHelpers::UnitlessQuirk::Allow);
+      range, context.mode(), CSSPropertyParserHelpers::UnitlessQuirk::Allow);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontSizeAdjust.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontSizeAdjust.cpp
index 2d0c853..4851691 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontSizeAdjust.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontSizeAdjust.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIFontSizeAdjust::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssFontSizeAdjustEnabled());
   if (range.peek().id() == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantCaps.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantCaps.cpp
index de5e2b8..e8dee21 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantCaps.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantCaps.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIFontVariantCaps::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeIdent<
       CSSValueNormal, CSSValueSmallCaps, CSSValueAllSmallCaps,
       CSSValuePetiteCaps, CSSValueAllPetiteCaps, CSSValueUnicase,
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantLigatures.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantLigatures.cpp
index 6c9b91d4..e6a10f6 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantLigatures.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantLigatures.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIFontVariantLigatures::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNormal || range.peek().id() == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantNumeric.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantNumeric.cpp
index 6742240d..58d590b 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantNumeric.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariantNumeric.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIFontVariantNumeric::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNormal)
     return CSSPropertyParserHelpers::consumeIdent(range);
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariationSettings.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariationSettings.cpp
index f4ed8e96..90974388 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariationSettings.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFontVariationSettings.cpp
@@ -43,7 +43,7 @@
 
 const CSSValue* CSSPropertyAPIFontVariationSettings::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssVariableFontsEnabled());
   if (range.peek().id() == CSSValueNormal)
     return CSSPropertyParserHelpers::consumeIdent(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFragmentation.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFragmentation.cpp
index d3b9cc3..050d6268 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFragmentation.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIFragmentation.cpp
@@ -7,7 +7,7 @@
 namespace blink {
 const CSSValue* CSSPropertyAPIFragmentation::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumePositiveInteger(range);
 }
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridAutoFlow.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridAutoFlow.cpp
index af14523..57196c5 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridAutoFlow.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIGridAutoFlow.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPIGridAutoFlow::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   CSSIdentifierValue* rowOrColumnValue =
       CSSPropertyParserHelpers::consumeIdent<CSSValueRow, CSSValueColumn>(
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIImage.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIImage.cpp
index 0dee170..8519d1f2 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIImage.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIImage.cpp
@@ -10,8 +10,8 @@
 
 const CSSValue* CSSPropertyAPIImage::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return CSSPropertyParserHelpers::consumeImageOrNone(range, context);
+    const CSSParserContext& context) {
+  return CSSPropertyParserHelpers::consumeImageOrNone(range, &context);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIImageOrientation.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIImageOrientation.cpp
index aecaa2c..ce400f0 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIImageOrientation.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIImageOrientation.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPIImageOrientation::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::imageOrientationEnabled());
   if (range.peek().id() == CSSValueFromImage)
     return CSSPropertyParserHelpers::consumeIdent(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIJustifyItems.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIJustifyItems.cpp
index 984240f..fd3420f 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIJustifyItems.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIJustifyItems.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPIJustifyItems::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssGridLayoutEnabled());
   CSSParserTokenRange rangeCopy = range;
   CSSIdentifierValue* legacy =
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILetterAndWordSpacing.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILetterAndWordSpacing.cpp
index e70a171f..166e100 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILetterAndWordSpacing.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILetterAndWordSpacing.cpp
@@ -11,12 +11,12 @@
 
 const CSSValue* CSSPropertyAPILetterAndWordSpacing::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNormal)
     return CSSPropertyParserHelpers::consumeIdent(range);
   // TODO(timloh): allow <percentage>s in word-spacing.
   return CSSPropertyParserHelpers::consumeLength(
-      range, context->mode(), ValueRangeAll,
+      range, context.mode(), ValueRangeAll,
       CSSPropertyParserHelpers::UnitlessQuirk::Allow);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILineHeight.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILineHeight.cpp
index 2be0560..c9beb63 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILineHeight.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILineHeight.cpp
@@ -11,8 +11,8 @@
 
 const CSSValue* CSSPropertyAPILineHeight::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return CSSPropertyFontUtils::consumeLineHeight(range, context->mode());
+    const CSSParserContext& context) {
+  return CSSPropertyFontUtils::consumeLineHeight(range, context.mode());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILineHeightStep.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILineHeightStep.cpp
index 130c513..08f7325 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILineHeightStep.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPILineHeightStep.cpp
@@ -12,8 +12,8 @@
 
 const CSSValue* CSSPropertyAPILineHeightStep::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return CSSPropertyParserHelpers::consumeLength(range, context->mode(),
+    const CSSParserContext& context) {
+  return CSSPropertyParserHelpers::consumeLength(range, context.mode(),
                                                  ValueRangeNonNegative);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMargin.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMargin.cpp
index 06cb814..9b8ec32 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMargin.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMargin.cpp
@@ -12,9 +12,9 @@
 
 const CSSValue* CSSPropertyAPIMargin::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyMarginUtils::consumeMarginOrOffset(
-      range, context->mode(), CSSPropertyParserHelpers::UnitlessQuirk::Allow);
+      range, context.mode(), CSSPropertyParserHelpers::UnitlessQuirk::Allow);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMethods.json5 b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMethods.json5
index df626e6..98bc532 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMethods.json5
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIMethods.json5
@@ -36,7 +36,7 @@
     {
       name: "parseSingleValue",
       return_type: "const CSSValue*",
-      parameters: "(CSSParserTokenRange&, const CSSParserContext*)",
+      parameters: "(CSSParserTokenRange&, const CSSParserContext&)",
       description: "Parses a single CSS property and returns the corresponding CSSValue. If the input is invalid it returns nullptr.",
     },
     {
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOffsetAnchor.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOffsetAnchor.cpp
index 152004e..1eaf47c2 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOffsetAnchor.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOffsetAnchor.cpp
@@ -13,11 +13,11 @@
 
 const CSSValue* CSSPropertyAPIOffsetAnchor::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValueID id = range.peek().id();
   if (id == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
-  return consumePosition(range, context->mode(),
+  return consumePosition(range, context.mode(),
                          CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOffsetPosition.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOffsetPosition.cpp
index 76f80cc9..cc9baa9 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOffsetPosition.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOffsetPosition.cpp
@@ -13,16 +13,16 @@
 
 const CSSValue* CSSPropertyAPIOffsetPosition::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValueID id = range.peek().id();
   if (id == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
   CSSValue* value = CSSPropertyParserHelpers::consumePosition(
-      range, context->mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
+      range, context.mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
 
   // Count when we receive a valid position other than 'auto'.
   if (value && value->isValuePair())
-    context->count(UseCounter::CSSOffsetInEffect);
+    context.count(UseCounter::CSSOffsetInEffect);
   return value;
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOpacity.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOpacity.cpp
index 2a293e9..7c2f96f 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOpacity.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOpacity.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIOpacity::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeNumber(range, ValueRangeAll);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOrder.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOrder.cpp
index 7d32548..96d6411 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOrder.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOrder.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIOrder::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeInteger(range);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineColor.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineColor.cpp
index 93e88db..f12d757a 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineColor.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineColor.cpp
@@ -12,11 +12,11 @@
 
 const CSSValue* CSSPropertyAPIOutlineColor::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   // Allow the special focus color even in HTML Standard parsing mode.
   if (range.peek().id() == CSSValueWebkitFocusRingColor)
     return CSSPropertyParserHelpers::consumeIdent(range);
-  return CSSPropertyParserHelpers::consumeColor(range, context->mode());
+  return CSSPropertyParserHelpers::consumeColor(range, context.mode());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineOffset.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineOffset.cpp
index c33a01a0..21d7f16 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineOffset.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineOffset.cpp
@@ -11,8 +11,8 @@
 
 const CSSValue* CSSPropertyAPIOutlineOffset::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return CSSPropertyParserHelpers::consumeLength(range, context->mode(),
+    const CSSParserContext& context) {
+  return CSSPropertyParserHelpers::consumeLength(range, context.mode(),
                                                  ValueRangeAll);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineWidth.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineWidth.cpp
index 98e10ea..773db9d 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineWidth.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIOutlineWidth.cpp
@@ -11,9 +11,9 @@
 
 const CSSValue* CSSPropertyAPIOutlineWidth::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeLineWidth(
-      range, context->mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
+      range, context.mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPadding.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPadding.cpp
index 2acae08..cab02fe 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPadding.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPadding.cpp
@@ -11,8 +11,8 @@
 
 const CSSValue* CSSPropertyAPIPadding::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return consumeLengthOrPercent(range, context->mode(), ValueRangeNonNegative,
+    const CSSParserContext& context) {
+  return consumeLengthOrPercent(range, context.mode(), ValueRangeNonNegative,
                                 CSSPropertyParserHelpers::UnitlessQuirk::Allow);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPage.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPage.cpp
index ebe5612..ada74f5 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPage.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPage.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIPage::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
   return CSSPropertyParserHelpers::consumeCustomIdent(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPaintOrder.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPaintOrder.cpp
index d53023b..2b3e708 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPaintOrder.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPaintOrder.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIPaintOrder::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNormal)
     return CSSPropertyParserHelpers::consumeIdent(range);
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPaintStroke.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPaintStroke.cpp
index 73685dc..9398d202 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPaintStroke.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIPaintStroke.cpp
@@ -14,17 +14,17 @@
 
 const CSSValue* CSSPropertyAPIPaintStroke::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
-  CSSURIValue* url = CSSPropertyParserHelpers::consumeUrl(range, context);
+  CSSURIValue* url = CSSPropertyParserHelpers::consumeUrl(range, &context);
   if (url) {
     CSSValue* parsedValue = nullptr;
     if (range.peek().id() == CSSValueNone) {
       parsedValue = CSSPropertyParserHelpers::consumeIdent(range);
     } else {
       parsedValue =
-          CSSPropertyParserHelpers::consumeColor(range, context->mode());
+          CSSPropertyParserHelpers::consumeColor(range, context.mode());
     }
     if (parsedValue) {
       CSSValueList* values = CSSValueList::createSpaceSeparated();
@@ -34,7 +34,7 @@
     }
     return url;
   }
-  return CSSPropertyParserHelpers::consumeColor(range, context->mode());
+  return CSSPropertyParserHelpers::consumeColor(range, context.mode());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIQuotes.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIQuotes.cpp
index d8fdc55..6ef8156 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIQuotes.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIQuotes.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPIQuotes::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
   CSSValueList* values = CSSValueList::createSpaceSeparated();
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRadius.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRadius.cpp
index ce9b83e..4d04c9f7 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRadius.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRadius.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIRadius::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
   return CSSPropertyParserHelpers::consumeLengthOrPercent(
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRotate.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRotate.cpp
index 03b87bdb..afa36c8 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRotate.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIRotate.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPIRotate::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
 
   CSSValueID id = range.peek().id();
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScale.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScale.cpp
index 7ee7f66..c9b104c63 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScale.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScale.cpp
@@ -12,7 +12,7 @@
 
 const CSSValue* CSSPropertyAPIScale::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
 
   CSSValueID id = range.peek().id();
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapCoordinate.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapCoordinate.cpp
index 9f2ce26..286856fe 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapCoordinate.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIScrollSnapCoordinate.cpp
@@ -26,10 +26,10 @@
 
 const CSSValue* CSSPropertyAPIScrollSnapCoordinate::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
-  return consumePositionList(range, context->mode());
+  return consumePositionList(range, context.mode());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeImageThreshold.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeImageThreshold.cpp
index 0adb2c5..70508c7 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeImageThreshold.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeImageThreshold.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIShapeImageThreshold::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeNumber(range, ValueRangeAll);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeMargin.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeMargin.cpp
index 38448d1..e4ba111 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeMargin.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeMargin.cpp
@@ -11,9 +11,9 @@
 
 const CSSValue* CSSPropertyAPIShapeMargin::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeLengthOrPercent(
-      range, context->mode(), ValueRangeNonNegative);
+      range, context.mode(), ValueRangeNonNegative);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeOutside.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeOutside.cpp
index 7c6c7ad..f03b359 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeOutside.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIShapeOutside.cpp
@@ -15,14 +15,14 @@
 
 const CSSValue* CSSPropertyAPIShapeOutside::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  if (CSSValue* imageValue = consumeImageOrNone(range, context))
+    const CSSParserContext& context) {
+  if (CSSValue* imageValue = consumeImageOrNone(range, &context))
     return imageValue;
   CSSValueList* list = CSSValueList::createSpaceSeparated();
   if (CSSValue* boxValue = consumeShapeBox(range))
     list->append(*boxValue);
   if (CSSValue* shapeValue =
-          CSSPropertyShapeUtils::consumeBasicShape(range, context)) {
+          CSSPropertyShapeUtils::consumeBasicShape(range, &context)) {
     list->append(*shapeValue);
     if (list->length() < 2) {
       if (CSSValue* boxValue = consumeShapeBox(range))
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPISize.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPISize.cpp
index 7e871d2..afc34cc 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPISize.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPISize.cpp
@@ -18,7 +18,7 @@
 
 const CSSValue* CSSPropertyAPISize::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValueList* result = CSSValueList::createSpaceSeparated();
 
   if (range.peek().id() == CSSValueAuto) {
@@ -27,9 +27,9 @@
   }
 
   if (CSSValue* width = CSSPropertyParserHelpers::consumeLength(
-          range, context->mode(), ValueRangeNonNegative)) {
+          range, context.mode(), ValueRangeNonNegative)) {
     CSSValue* height = CSSPropertyParserHelpers::consumeLength(
-        range, context->mode(), ValueRangeNonNegative);
+        range, context.mode(), ValueRangeNonNegative);
     result->append(*width);
     if (height)
       result->append(*height);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeDasharray.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeDasharray.cpp
index ca27b4b1..ccfe5c7 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeDasharray.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeDasharray.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIStrokeDasharray::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValueID id = range.peek().id();
   if (id == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeMiterlimit.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeMiterlimit.cpp
index c9cdd7e..37aebb08 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeMiterlimit.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIStrokeMiterlimit.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIStrokeMiterlimit::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeNumber(range, ValueRangeNonNegative);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITabSize.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITabSize.cpp
index 884ede0..59d950d1 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITabSize.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITabSize.cpp
@@ -11,12 +11,12 @@
 
 const CSSValue* CSSPropertyAPITabSize::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSPrimitiveValue* parsedValue =
       CSSPropertyParserHelpers::consumeInteger(range, 0);
   if (parsedValue)
     return parsedValue;
-  return CSSPropertyParserHelpers::consumeLength(range, context->mode(),
+  return CSSPropertyParserHelpers::consumeLength(range, context.mode(),
                                                  ValueRangeNonNegative);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationColor.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationColor.cpp
index bcc859a..2b7bf9d 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationColor.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationColor.cpp
@@ -12,9 +12,9 @@
 
 const CSSValue* CSSPropertyAPITextDecorationColor::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
-  return CSSPropertyParserHelpers::consumeColor(range, context->mode());
+  return CSSPropertyParserHelpers::consumeColor(range, context.mode());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationSkip.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationSkip.cpp
index 1f1be13..946f7be7 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationSkip.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextDecorationSkip.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPITextDecorationSkip::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
   CSSValueList* list = CSSValueList::createSpaceSeparated();
   while (true) {
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextIndent.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextIndent.cpp
index 2935c41..e586cbb 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextIndent.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextIndent.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPITextIndent::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   // [ <length> | <percentage> ] && hanging? && each-line?
   // Keywords only allowed when css3Text is enabled.
   CSSValueList* list = CSSValueList::createSpaceSeparated();
@@ -26,7 +26,7 @@
     if (!hasLengthOrPercentage) {
       if (CSSValue* textIndent =
               CSSPropertyParserHelpers::consumeLengthOrPercent(
-                  range, context->mode(), ValueRangeAll,
+                  range, context.mode(), ValueRangeAll,
                   CSSPropertyParserHelpers::UnitlessQuirk::Allow)) {
         list->append(*textIndent);
         hasLengthOrPercentage = true;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextSizeAdjust.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextSizeAdjust.cpp
index b75b076..1fbfd463 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextSizeAdjust.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextSizeAdjust.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPITextSizeAdjust::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
   if (range.peek().id() == CSSValueNone)
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextUnderlinePosition.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextUnderlinePosition.cpp
index 26e5ad0..5a6ce600 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextUnderlinePosition.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITextUnderlinePosition.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPITextUnderlinePosition::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   // auto | [ under || [ left | right ] ], but we only support auto | under
   // for now
   DCHECK(RuntimeEnabledFeatures::css3TextDecorationsEnabled());
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITouchAction.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITouchAction.cpp
index 3ca71228c..1f76343 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITouchAction.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITouchAction.cpp
@@ -36,7 +36,7 @@
 
 const CSSValue* CSSPropertyAPITouchAction::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValueList* list = CSSValueList::createSpaceSeparated();
   CSSValueID id = range.peek().id();
   if (id == CSSValueAuto || id == CSSValueNone || id == CSSValueManipulation) {
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITransformOrigin.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITransformOrigin.cpp
index 367d874..2079cab 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITransformOrigin.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITransformOrigin.cpp
@@ -12,17 +12,17 @@
 
 const CSSValue* CSSPropertyAPITransformOrigin::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValue* resultX = nullptr;
   CSSValue* resultY = nullptr;
   if (CSSPropertyParserHelpers::consumeOneOrTwoValuedPosition(
-          range, context->mode(),
+          range, context.mode(),
           CSSPropertyParserHelpers::UnitlessQuirk::Forbid, resultX, resultY)) {
     CSSValueList* list = CSSValueList::createSpaceSeparated();
     list->append(*resultX);
     list->append(*resultY);
     CSSValue* resultZ = CSSPropertyParserHelpers::consumeLength(
-        range, context->mode(), ValueRangeAll);
+        range, context.mode(), ValueRangeAll);
     if (!resultZ) {
       resultZ =
           CSSPrimitiveValue::create(0, CSSPrimitiveValue::UnitType::Pixels);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITranslate.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITranslate.cpp
index 91c93ac..a96df4f8 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITranslate.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPITranslate.cpp
@@ -13,23 +13,23 @@
 
 const CSSValue* CSSPropertyAPITranslate::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   DCHECK(RuntimeEnabledFeatures::cssIndependentTransformPropertiesEnabled());
   CSSValueID id = range.peek().id();
   if (id == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
 
   CSSValue* translate = CSSPropertyParserHelpers::consumeLengthOrPercent(
-      range, context->mode(), ValueRangeAll);
+      range, context.mode(), ValueRangeAll);
   if (!translate)
     return nullptr;
   CSSValueList* list = CSSValueList::createSpaceSeparated();
   list->append(*translate);
   translate = CSSPropertyParserHelpers::consumeLengthOrPercent(
-      range, context->mode(), ValueRangeAll);
+      range, context.mode(), ValueRangeAll);
   if (translate) {
     list->append(*translate);
-    translate = CSSPropertyParserHelpers::consumeLength(range, context->mode(),
+    translate = CSSPropertyParserHelpers::consumeLength(range, context.mode(),
                                                         ValueRangeAll);
     if (translate)
       list->append(*translate);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIVerticalAlign.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIVerticalAlign.cpp
index 1b6d0303..b5e012f 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIVerticalAlign.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIVerticalAlign.cpp
@@ -11,12 +11,12 @@
 
 const CSSValue* CSSPropertyAPIVerticalAlign::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValue* parsedValue = CSSPropertyParserHelpers::consumeIdentRange(
       range, CSSValueBaseline, CSSValueWebkitBaselineMiddle);
   if (!parsedValue) {
     parsedValue = CSSPropertyParserHelpers::consumeLengthOrPercent(
-        range, context->mode(), ValueRangeAll,
+        range, context.mode(), ValueRangeAll,
         CSSPropertyParserHelpers::UnitlessQuirk::Allow);
   }
   return parsedValue;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBorderSpacing.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBorderSpacing.cpp
index 1436e8c4..6348a8b 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBorderSpacing.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBorderSpacing.cpp
@@ -11,8 +11,8 @@
 
 const CSSValue* CSSPropertyAPIWebkitBorderSpacing::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return CSSPropertyParserHelpers::consumeLength(range, context->mode(),
+    const CSSParserContext& context) {
+  return CSSPropertyParserHelpers::consumeLength(range, context.mode(),
                                                  ValueRangeNonNegative);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBoxFlexGroup.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBoxFlexGroup.cpp
index 458b25f..ffc086b6 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBoxFlexGroup.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitBoxFlexGroup.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIWebkitBoxFlexGroup::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeInteger(range, 0);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitFontSizeDelta.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitFontSizeDelta.cpp
index be2682e..40a6d0a 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitFontSizeDelta.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitFontSizeDelta.cpp
@@ -11,9 +11,9 @@
 
 const CSSValue* CSSPropertyAPIWebkitFontSizeDelta::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeLength(
-      range, context->mode(), ValueRangeAll,
+      range, context.mode(), ValueRangeAll,
       CSSPropertyParserHelpers::UnitlessQuirk::Allow);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitHighlight.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitHighlight.cpp
index 798e4ca1..68deb80 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitHighlight.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitHighlight.cpp
@@ -11,7 +11,7 @@
 
 const CSSValue* CSSPropertyAPIWebkitHighlight::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
   return CSSPropertyParserHelpers::consumeString(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLineClamp.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLineClamp.cpp
index 982854e4..122bd6fd 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLineClamp.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitLineClamp.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIWebkitLineClamp::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().type() != PercentageToken &&
       range.peek().type() != NumberToken)
     return nullptr;
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitMargin.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitMargin.cpp
index b91ec91..00de0f30 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitMargin.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitMargin.cpp
@@ -12,9 +12,9 @@
 
 const CSSValue* CSSPropertyAPIWebkitMargin::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyMarginUtils::consumeMarginOrOffset(
-      range, context->mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
+      range, context.mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitMaxLogicalWidthOrHeight.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitMaxLogicalWidthOrHeight.cpp
index 9013b29..975faf4 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitMaxLogicalWidthOrHeight.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitMaxLogicalWidthOrHeight.cpp
@@ -10,8 +10,8 @@
 
 const CSSValue* CSSPropertyAPIWebkitMaxLogicalWidthOrHeight::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return CSSPropertyLengthUtils::consumeMaxWidthOrHeight(range, context);
+    const CSSParserContext& context) {
+  return CSSPropertyLengthUtils::consumeMaxWidthOrHeight(range, &context);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitPadding.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitPadding.cpp
index bff2e7ff..1bc0bda 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitPadding.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitPadding.cpp
@@ -12,9 +12,9 @@
 
 const CSSValue* CSSPropertyAPIWebkitPadding::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return consumeLengthOrPercent(
-      range, context->mode(), ValueRangeNonNegative,
+      range, context.mode(), ValueRangeNonNegative,
       CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp
index 8366577a..771fbc7 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextEmphasisStyle.cpp
@@ -12,7 +12,7 @@
 
 const CSSValue* CSSPropertyAPIWebkitTextEmphasisStyle::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   CSSValueID id = range.peek().id();
   if (id == CSSValueNone)
     return CSSPropertyParserHelpers::consumeIdent(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextStrokeWidth.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextStrokeWidth.cpp
index d4f95a3..71a960c 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextStrokeWidth.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTextStrokeWidth.cpp
@@ -11,9 +11,9 @@
 
 const CSSValue* CSSPropertyAPIWebkitTextStrokeWidth::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   return CSSPropertyParserHelpers::consumeLineWidth(
-      range, context->mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
+      range, context.mode(), CSSPropertyParserHelpers::UnitlessQuirk::Forbid);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTransformOriginZ.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTransformOriginZ.cpp
index 4e9c360..44a31e29 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTransformOriginZ.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWebkitTransformOriginZ.cpp
@@ -11,8 +11,8 @@
 
 const CSSValue* CSSPropertyAPIWebkitTransformOriginZ::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
-  return CSSPropertyParserHelpers::consumeLength(range, context->mode(),
+    const CSSParserContext& context) {
+  return CSSPropertyParserHelpers::consumeLength(range, context.mode(),
                                                  ValueRangeAll);
 }
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWillChange.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWillChange.cpp
index d4ed6bb..1b18414 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWillChange.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIWillChange.cpp
@@ -13,7 +13,7 @@
 
 const CSSValue* CSSPropertyAPIWillChange::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
 
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZIndex.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZIndex.cpp
index 663e350..a529cb9f 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZIndex.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZIndex.cpp
@@ -10,7 +10,7 @@
 
 const CSSValue* CSSPropertyAPIZIndex::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   if (range.peek().id() == CSSValueAuto)
     return CSSPropertyParserHelpers::consumeIdent(range);
   return CSSPropertyParserHelpers::consumeInteger(range);
diff --git a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZoom.cpp b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZoom.cpp
index a19dc07..bbf86d3 100644
--- a/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZoom.cpp
+++ b/third_party/WebKit/Source/core/css/properties/CSSPropertyAPIZoom.cpp
@@ -12,7 +12,7 @@
 
 const CSSValue* CSSPropertyAPIZoom::parseSingleValue(
     CSSParserTokenRange& range,
-    const CSSParserContext* context) {
+    const CSSParserContext& context) {
   const CSSParserToken& token = range.peek();
   CSSValue* zoom = nullptr;
   if (token.type() == IdentToken) {
@@ -32,11 +32,11 @@
            toCSSPrimitiveValue(zoom)->getDoubleValue() == 1) ||
           (token.type() == PercentageToken &&
            toCSSPrimitiveValue(zoom)->getDoubleValue() == 100)))
-      context->count(UseCounter::CSSZoomNotEqualToOne);
+      context.count(UseCounter::CSSZoomNotEqualToOne);
     if (token.id() == CSSValueReset)
-      context->countDeprecation(UseCounter::CSSZoomReset);
+      context.countDeprecation(UseCounter::CSSZoomReset);
     if (token.id() == CSSValueDocument)
-      context->countDeprecation(UseCounter::CSSZoomDocument);
+      context.countDeprecation(UseCounter::CSSZoomDocument);
   }
   return zoom;
 }
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 4943bb8..fc705c2 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2086,9 +2086,12 @@
 void Element::rebuildPseudoElementLayoutTree(PseudoId pseudoId,
                                              Text* nextTextSibling) {
   if (PseudoElement* element = pseudoElement(pseudoId)) {
+    if (pseudoId == PseudoIdFirstLetter && updateFirstLetter(element))
+      return;
     if (element->needsReattachLayoutTree() ||
-        element->childNeedsReattachLayoutTree())
+        element->childNeedsReattachLayoutTree()) {
       element->rebuildLayoutTree(nextTextSibling);
+    }
   } else {
     createPseudoElementIfNeeded(pseudoId);
   }
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 82100ba..63783f9 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1525,6 +1525,8 @@
     WindowOpenWithInvalidURL = 1909,
     CrossOriginMainFrameNulledNameAccessed = 1910,
     MenuItemElementIconAttribute = 1911,
+    WebkitCSSMatrixSetMatrixValue = 1912,
+    WebkitCSSMatrixConstructFromString = 1913,
 
     // Add new features immediately above this line. Don't change assigned
     // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 56a560a..3222aeb8 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -1246,6 +1246,7 @@
         createAcceleratedImageBufferSurface(opacityMode, &msaaSampleCount);
     if (surface) {
       buffer()->setSurface(std::move(surface));
+      setNeedsCompositingUpdate();
     }
   }
 }
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 088d892..f3aeb4d 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
@@ -238,6 +238,12 @@
 }
 
 bool NGBlockNode::CanUseNewLayout() {
+  // [Multicol]: for the 1st phase of LayoutNG's multicol implementation we want
+  // to utilize the existing ColumnBalancer class. That's why a multicol block
+  // should be processed by Legacy Layout engine.
+  if (Style().specifiesColumns())
+    return false;
+
   if (!layout_box_->isLayoutBlockFlow())
     return false;
   return RuntimeEnabledFeatures::layoutNGEnabled() || !HasInlineChildren();
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
index 63cefdd..89f29038 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm.cc
@@ -348,10 +348,12 @@
   NGLogicalOffset origin_offset =
       GetOriginPointForFloats(ConstraintSpace(), content_size_);
   NGLogicalOffset from_offset = ConstraintSpace().BfcOffset();
-  // TODO(glebl): add margins calculation.
-  NGBoxStrut margins;
+  const ComputedStyle& float_style = node->Style();
+  NGBoxStrut margins = ComputeMargins(ConstraintSpace(), float_style,
+                                      ConstraintSpace().WritingMode(),
+                                      ConstraintSpace().Direction());
   RefPtr<NGFloatingObject> floating_object = NGFloatingObject::Create(
-      node->Style(), float_space->WritingMode(), current_opportunity_.size,
+      float_style, float_space->WritingMode(), current_opportunity_.size,
       origin_offset, from_offset, margins,
       layout_result->PhysicalFragment().get());
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm_test.cc
index 0b350b3..09b8134 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_layout_algorithm_test.cc
@@ -270,5 +270,34 @@
   EXPECT_EQ(wide_float->offsetTop(), narrow_float->offsetTop());
 }
 
+// Verifies that InlineLayoutAlgorithm positions floats with respect to their
+// margins.
+TEST_F(NGInlineLayoutAlgorithmTest, PositionFloatsWithMargins) {
+  setBodyInnerHTML(R"HTML(
+    <!DOCTYPE html>
+    <style>
+      #container {
+        height: 200px; width: 200px; outline: solid orange;
+      }
+      #left {
+        float: left; width: 5px; height: 30px; background-color: blue;
+        margin: 10%;
+      }
+    </style>
+    <div id="container">
+      <span id="text">
+        The quick <div id="left"></div> brown fox jumps over the lazy dog
+      </span>
+    </div>
+  )HTML");
+  LayoutText* layout_text =
+      toLayoutText(getLayoutObjectByElementId("text")->slowFirstChild());
+  ASSERT(layout_text->hasTextBoxes());
+
+  InlineTextBox* inline_text_box1 = layout_text->firstTextBox();
+  // 45 = sum of left's inline margins: 40 + left's width: 5
+  EXPECT_EQ(LayoutUnit(45), inline_text_box1->x());
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
index b24118d..8d01052 100644
--- a/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
+++ b/third_party/WebKit/Source/core/loader/ThreadableLoaderTest.cpp
@@ -114,7 +114,7 @@
   virtual void cancelLoader() = 0;
   virtual void cancelAndClearLoader() = 0;
   virtual void clearLoader() = 0;
-  virtual Checkpoint& checkpoint() = 0;
+  virtual Checkpoint& getCheckpoint() = 0;
   virtual void callCheckpoint(int) = 0;
   virtual void onSetUp() = 0;
   virtual void onServeRequests() = 0;
@@ -147,7 +147,7 @@
     m_loader = nullptr;
   }
   void clearLoader() override { m_loader = nullptr; }
-  Checkpoint& checkpoint() override { return m_checkpoint; }
+  Checkpoint& getCheckpoint() override { return m_checkpoint; }
   void callCheckpoint(int n) override { m_checkpoint.Call(n); }
 
   void onSetUp() override {}
@@ -222,7 +222,7 @@
     m_loader = nullptr;
   }
 
-  Checkpoint& checkpoint() override { return m_checkpoint; }
+  Checkpoint& getCheckpoint() override { return m_checkpoint; }
 
   void callCheckpoint(int n) override {
     testing::runPendingTasks();
@@ -374,7 +374,7 @@
   void cancelLoader() { m_helper->cancelLoader(); }
   void cancelAndClearLoader() { m_helper->cancelAndClearLoader(); }
   void clearLoader() { m_helper->clearLoader(); }
-  Checkpoint& checkpoint() { return m_helper->checkpoint(); }
+  Checkpoint& getCheckpoint() { return m_helper->getCheckpoint(); }
   void callCheckpoint(int n) { m_helper->callCheckpoint(n); }
 
   void serveRequests() {
@@ -467,14 +467,14 @@
 
 TEST_P(ThreadableLoaderTest, CancelAfterStart) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2))
+  EXPECT_CALL(getCheckpoint(), Call(2))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelLoader));
   EXPECT_CALL(*client(), didFail(Truly(isCancellation)));
-  EXPECT_CALL(checkpoint(), Call(3));
+  EXPECT_CALL(getCheckpoint(), Call(3));
 
   startLoader(successURL());
   callCheckpoint(2);
@@ -484,15 +484,15 @@
 
 TEST_P(ThreadableLoaderTest, CancelAndClearAfterStart) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2))
+  EXPECT_CALL(getCheckpoint(), Call(2))
       .WillOnce(
           InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelAndClearLoader));
   EXPECT_CALL(*client(), didFail(Truly(isCancellation)));
-  EXPECT_CALL(checkpoint(), Call(3));
+  EXPECT_CALL(getCheckpoint(), Call(3));
 
   startLoader(successURL());
   callCheckpoint(2);
@@ -502,11 +502,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelInDidReceiveResponse) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelLoader));
   EXPECT_CALL(*client(), didFail(Truly(isCancellation)));
@@ -518,11 +518,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelAndClearInDidReceiveResponse) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _))
       .WillOnce(
           InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelAndClearLoader));
@@ -535,11 +535,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelInDidReceiveData) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didReceiveData(_, _))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelLoader));
@@ -552,11 +552,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelAndClearInDidReceiveData) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didReceiveData(_, _))
       .WillOnce(
@@ -570,11 +570,11 @@
 
 TEST_P(ThreadableLoaderTest, DidFinishLoading) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didReceiveData(StrEq("fox"), 4));
   // We expect didReceiveResourceTiming() calls in DocumentThreadableLoader;
@@ -590,11 +590,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelInDidFinishLoading) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didReceiveData(_, _));
   EXPECT_CALL(*client(), didReceiveResourceTiming(_));
@@ -608,11 +608,11 @@
 
 TEST_P(ThreadableLoaderTest, ClearInDidFinishLoading) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didReceiveData(_, _));
   EXPECT_CALL(*client(), didReceiveResourceTiming(_));
@@ -626,11 +626,11 @@
 
 TEST_P(ThreadableLoaderTest, DidFail) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didFail(Truly(isNotCancellation)));
 
@@ -641,11 +641,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelInDidFail) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didFail(_))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelLoader));
@@ -657,11 +657,11 @@
 
 TEST_P(ThreadableLoaderTest, ClearInDidFail) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didFail(_))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::clearLoader));
@@ -673,7 +673,7 @@
 
 TEST_P(ThreadableLoaderTest, DidFailInStart) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(DenyCrossOriginRequests);
   callCheckpoint(1);
 
@@ -681,7 +681,7 @@
       *client(),
       didFail(ResourceError(errorDomainBlinkInternal, 0, errorURL().getString(),
                             "Cross origin requests are not supported.")));
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
 
   startLoader(errorURL());
   callCheckpoint(2);
@@ -690,13 +690,13 @@
 
 TEST_P(ThreadableLoaderTest, CancelInDidFailInStart) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(DenyCrossOriginRequests);
   callCheckpoint(1);
 
   EXPECT_CALL(*client(), didFail(_))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelLoader));
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
 
   startLoader(errorURL());
   callCheckpoint(2);
@@ -705,13 +705,13 @@
 
 TEST_P(ThreadableLoaderTest, ClearInDidFailInStart) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(DenyCrossOriginRequests);
   callCheckpoint(1);
 
   EXPECT_CALL(*client(), didFail(_))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::clearLoader));
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
 
   startLoader(errorURL());
   callCheckpoint(2);
@@ -720,11 +720,11 @@
 
 TEST_P(ThreadableLoaderTest, DidFailAccessControlCheck) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(UseAccessControl);
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(
       *client(),
       didFailAccessControlCheck(ResourceError(
@@ -739,11 +739,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelInDidFailAccessControlCheck) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(UseAccessControl);
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didFailAccessControlCheck(_))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelLoader));
 
@@ -754,11 +754,11 @@
 
 TEST_P(ThreadableLoaderTest, ClearInDidFailAccessControlCheck) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(UseAccessControl);
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didFailAccessControlCheck(_))
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::clearLoader));
 
@@ -769,11 +769,11 @@
 
 TEST_P(ThreadableLoaderTest, RedirectDidFinishLoading) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didReceiveData(StrEq("fox"), 4));
   EXPECT_CALL(*client(), didReceiveResourceTiming(_));
@@ -786,11 +786,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelInRedirectDidFinishLoading) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didReceiveData(StrEq("fox"), 4));
   EXPECT_CALL(*client(), didReceiveResourceTiming(_));
@@ -804,11 +804,11 @@
 
 TEST_P(ThreadableLoaderTest, ClearInRedirectDidFinishLoading) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader();
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didReceiveResponseMock(_, _, _));
   EXPECT_CALL(*client(), didReceiveData(StrEq("fox"), 4));
   EXPECT_CALL(*client(), didReceiveResourceTiming(_));
@@ -822,11 +822,11 @@
 
 TEST_P(ThreadableLoaderTest, DidFailRedirectCheck) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(UseAccessControl);
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didFailRedirectCheck());
 
   startLoader(redirectLoopURL());
@@ -836,11 +836,11 @@
 
 TEST_P(ThreadableLoaderTest, CancelInDidFailRedirectCheck) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(UseAccessControl);
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didFailRedirectCheck())
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::cancelLoader));
 
@@ -851,11 +851,11 @@
 
 TEST_P(ThreadableLoaderTest, ClearInDidFailRedirectCheck) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(UseAccessControl);
   callCheckpoint(1);
 
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
   EXPECT_CALL(*client(), didFailRedirectCheck())
       .WillOnce(InvokeWithoutArgs(this, &ThreadableLoaderTest::clearLoader));
 
@@ -868,12 +868,12 @@
 // synchronously.
 TEST_P(ThreadableLoaderTest, GetResponseSynchronously) {
   InSequence s;
-  EXPECT_CALL(checkpoint(), Call(1));
+  EXPECT_CALL(getCheckpoint(), Call(1));
   createLoader(UseAccessControl);
   callCheckpoint(1);
 
   EXPECT_CALL(*client(), didFailAccessControlCheck(_));
-  EXPECT_CALL(checkpoint(), Call(2));
+  EXPECT_CALL(getCheckpoint(), Call(2));
 
   // Currently didFailAccessControlCheck is dispatched synchronously. This
   // test is not saying that didFailAccessControlCheck should be dispatched
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
index c915425..d07ce92 100644
--- a/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/ImageResource.cpp
@@ -459,14 +459,13 @@
 }
 
 static bool isLoFiImage(const ImageResource& resource) {
-  if (!(resource.resourceRequest().previewsState() &
-        WebURLRequest::ServerLoFiOn)) {
-    return false;
+  if (resource.isLoaded()) {
+    return resource.response()
+        .httpHeaderField("chrome-proxy-content-transform")
+        .contains("empty-image");
   }
-  return !resource.isLoaded() ||
-         resource.response()
-             .httpHeaderField("chrome-proxy-content-transform")
-             .contains("empty-image");
+  return resource.resourceRequest().previewsState() &
+         WebURLRequest::ServerLoFiOn;
 }
 
 void ImageResource::reloadIfLoFiOrPlaceholderImage(
diff --git a/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp b/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp
index 962a51741d..7107dca 100644
--- a/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp
+++ b/third_party/WebKit/Source/core/loader/resource/ImageResourceTest.cpp
@@ -507,7 +507,6 @@
   KURL testURL(ParsedURLString, kTestURL);
   ScopedMockedURLLoad scopedMockedURLLoad(testURL, GetTestFilePath());
   ResourceRequest request = ResourceRequest(testURL);
-  request.setPreviewsState(WebURLRequest::ServerLoFiOn);
   ImageResource* imageResource = ImageResource::create(request);
   imageResource->setStatus(ResourceStatus::Pending);
 
@@ -548,6 +547,49 @@
       WebCachePolicy::BypassingCache);
 }
 
+TEST(ImageResourceTest,
+     ReloadIfLoFiOrPlaceholderAfterFinishedWithoutLoFiHeaders) {
+  KURL testURL(ParsedURLString, kTestURL);
+  ScopedMockedURLLoad scopedMockedURLLoad(testURL, GetTestFilePath());
+  ResourceRequest request = ResourceRequest(testURL);
+  request.setPreviewsState(WebURLRequest::ServerLoFiOn);
+  ImageResource* imageResource = ImageResource::create(request);
+  imageResource->setStatus(ResourceStatus::Pending);
+
+  std::unique_ptr<MockImageResourceObserver> observer =
+      MockImageResourceObserver::create(imageResource->getContent());
+  ResourceFetcher* fetcher = createFetcher();
+
+  // Send the image response, without any LoFi image response headers.
+  imageResource->responseReceived(
+      ResourceResponse(KURL(), "image/jpeg", sizeof(kJpegImage), nullAtom),
+      nullptr);
+  imageResource->appendData(reinterpret_cast<const char*>(kJpegImage),
+                            sizeof(kJpegImage));
+  imageResource->finish();
+  EXPECT_FALSE(imageResource->errorOccurred());
+  ASSERT_TRUE(imageResource->getContent()->hasImage());
+  EXPECT_FALSE(imageResource->getContent()->getImage()->isNull());
+  EXPECT_EQ(2, observer->imageChangedCount());
+  EXPECT_EQ(kJpegImageWidth, observer->imageWidthOnLastImageChanged());
+  // The observer should have been notified that the image load completed.
+  EXPECT_TRUE(observer->imageNotifyFinishedCalled());
+  EXPECT_EQ(kJpegImageWidth, observer->imageWidthOnImageNotifyFinished());
+  EXPECT_TRUE(imageResource->getContent()->getImage()->isBitmapImage());
+  EXPECT_EQ(kJpegImageWidth, imageResource->getContent()->getImage()->width());
+  EXPECT_EQ(kJpegImageHeight,
+            imageResource->getContent()->getImage()->height());
+
+  // Call reloadIfLoFiOrPlaceholderImage() after the image has finished loading.
+  imageResource->reloadIfLoFiOrPlaceholderImage(fetcher,
+                                                Resource::kReloadAlways);
+
+  // The image should not have been reloaded, since it didn't have the LoFi
+  // image response headers.
+  EXPECT_EQ(2, observer->imageChangedCount());
+  EXPECT_TRUE(imageResource->isLoaded());
+}
+
 TEST(ImageResourceTest, ReloadIfLoFiOrPlaceholderViaResourceFetcher) {
   ResourceFetcher* fetcher = createFetcher();
 
@@ -604,12 +646,8 @@
       MockImageResourceObserver::create(imageResource->getContent());
 
   // Send the image response.
-  ResourceResponse initialResourceResponse(testURL, "image/jpeg",
-                                           sizeof(kJpegImage), nullAtom);
-  initialResourceResponse.addHTTPHeaderField("chrome-proxy", "q=low");
-
-  imageResource->loader()->didReceiveResponse(
-      WrappedResourceResponse(initialResourceResponse));
+  imageResource->loader()->didReceiveResponse(WrappedResourceResponse(
+      ResourceResponse(testURL, "image/jpeg", sizeof(kJpegImage), nullAtom)));
   imageResource->loader()->didReceiveData(
       reinterpret_cast<const char*>(kJpegImage), sizeof(kJpegImage));
 
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js b/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js
index 6a985aa..ebfc037 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/BlackboxManager.js
@@ -276,10 +276,8 @@
     var promises = [];
     for (var debuggerModel of SDK.targetManager.models(SDK.DebuggerModel)) {
       promises.push(this._setBlackboxPatterns(debuggerModel));
-      for (var scriptId in debuggerModel.scripts) {
-        var script = debuggerModel.scripts[scriptId];
+      for (var script of debuggerModel.scripts())
         promises.push(this._addScript(script).then(loadSourceMap.bind(this, script)));
-      }
     }
     Promise.all(promises).then(() => {
       var listeners = Array.from(this._listeners);
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
index f1855cc..80b52d1 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
@@ -87,11 +87,15 @@
           resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.FrameDetached, this._frameDetached, this));
     }
 
-    var debuggerModel = target.model(SDK.DebuggerModel);
-    if (debuggerModel) {
+    this._debuggerModel = target.model(SDK.DebuggerModel);
+    if (this._debuggerModel) {
+      var runtimeModel = this._debuggerModel.runtimeModel();
       this._eventListeners.push(
-          debuggerModel.addEventListener(SDK.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this),
-          debuggerModel.addEventListener(
+          runtimeModel.addEventListener(
+              SDK.RuntimeModel.Events.ExecutionContextDestroyed, this._executionContextDestroyed, this),
+          this._debuggerModel.addEventListener(
+              SDK.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this),
+          this._debuggerModel.addEventListener(
               SDK.DebuggerModel.Events.FailedToParseScriptSource, this._parsedScriptSource, this));
     }
     var cssModel = target.model(SDK.CSSModel);
@@ -250,21 +254,32 @@
   }
 
   /**
-   * @param {!Common.Event} event
+   * @param {!SDK.Script} script
+   * @return {boolean}
    */
-  _parsedScriptSource(event) {
-    var script = /** @type {!SDK.Script} */ (event.data);
+  _acceptsScript(script) {
     if (!script.sourceURL || script.isLiveEdit() || (script.isInlineScript() && !script.hasSourceURL))
-      return;
+      return false;
     // Filter out embedder injected content scripts.
     if (script.isContentScript() && !script.hasSourceURL) {
       var parsedURL = new Common.ParsedURL(script.sourceURL);
       if (!parsedURL.isValid)
-        return;
+        return false;
     }
+    return true;
+  }
+
+  /**
+   * @param {!Common.Event} event
+   */
+  _parsedScriptSource(event) {
+    var script = /** @type {!SDK.Script} */ (event.data);
+    if (!this._acceptsScript(script))
+      return;
     var originalContentProvider = script.originalContentProvider();
     var executionContext = script.executionContext();
     var frameId = executionContext ? executionContext.frameId || '' : '';
+    script[Bindings.NetworkProject._frameIdSymbol] = frameId;
     var uiSourceCode = this._createFile(originalContentProvider, frameId, script.isContentScript());
     uiSourceCode[Bindings.NetworkProject._scriptSymbol] = script;
     var resource = SDK.ResourceTreeModel.resourceForURL(uiSourceCode.url());
@@ -274,11 +289,34 @@
   /**
    * @param {!Common.Event} event
    */
+  _executionContextDestroyed(event) {
+    var executionContext = /** @type {!SDK.ExecutionContext} */ (event.data);
+    var scripts = this._debuggerModel.scriptsForExecutionContext(executionContext);
+    for (var script of scripts) {
+      if (!this._acceptsScript(script))
+        continue;
+      var frameId = script[Bindings.NetworkProject._frameIdSymbol];
+      this._removeFileForURL(script.contentURL(), frameId, script.isContentScript());
+    }
+  }
+
+  /**
+   * @param {!SDK.CSSStyleSheetHeader} header
+   */
+  _acceptsHeader(header) {
+    if (header.isInline && !header.hasSourceURL && header.origin !== 'inspector')
+      return false;
+    if (!header.resourceURL())
+      return false;
+    return true;
+  }
+
+  /**
+   * @param {!Common.Event} event
+   */
   _styleSheetAdded(event) {
     var header = /** @type {!SDK.CSSStyleSheetHeader} */ (event.data);
-    if (header.isInline && !header.hasSourceURL && header.origin !== 'inspector')
-      return;
-    if (!header.resourceURL())
+    if (!this._acceptsHeader(header))
       return;
 
     var originalContentProvider = header.originalContentProvider();
@@ -293,9 +331,8 @@
    */
   _styleSheetRemoved(event) {
     var header = /** @type {!SDK.CSSStyleSheetHeader} */ (event.data);
-    if (header.isInline && !header.hasSourceURL && header.origin !== 'inspector')
+    if (!this._acceptsHeader(header))
       return;
-
     this._removeFileForURL(header.resourceURL(), header.frameId, false);
   }
 
@@ -317,7 +354,6 @@
         resourceType !== Common.resourceTypes.Document && resourceType !== Common.resourceTypes.Manifest)
       return;
 
-
     // Ignore non-images and non-fonts.
     if (resourceType === Common.resourceTypes.Image && resource.mimeType && !resource.mimeType.startsWith('image'))
       return;
@@ -448,3 +484,4 @@
 Bindings.NetworkProject._styleSheetSymbol = Symbol('styleSheet');
 Bindings.NetworkProject._targetSymbol = Symbol('target');
 Bindings.NetworkProject._frameSymbol = Symbol('frame');
+Bindings.NetworkProject._frameIdSymbol = Symbol('frameid');
\ No newline at end of file
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 df312c2b..d7d545e 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -662,12 +662,11 @@
 
 /**
  * @implements {UI.ToolbarItem.Provider}
- * @unrestricted
  */
 Main.Main.MainMenuItem = class {
   constructor() {
-    this._item = new UI.ToolbarButton(Common.UIString('Customize and control DevTools'), 'largeicon-menu');
-    this._item.addEventListener(UI.ToolbarButton.Events.MouseDown, this._mouseDown, this);
+    this._item = new UI.ToolbarMenuButton(this._handleContextMenu.bind(this), true);
+    this._item.setTitle(Common.UIString('Customize and control DevTools'));
   }
 
   /**
@@ -679,13 +678,9 @@
   }
 
   /**
-   * @param {!Common.Event} event
+   * @param {!UI.ContextMenu} contextMenu
    */
-  _mouseDown(event) {
-    var contextMenu = new UI.ContextMenu(
-        /** @type {!Event} */ (event.data), true, this._item.element.totalOffsetLeft(),
-        this._item.element.totalOffsetTop() + this._item.element.offsetHeight);
-
+  _handleContextMenu(contextMenu) {
     if (Components.dockController.canDock()) {
       var dockItemElement = createElementWithClass('div', 'flex-centered flex-auto');
       var titleElement = dockItemElement.createChild('span', 'flex-auto');
@@ -746,7 +741,6 @@
     var helpSubMenu = contextMenu.namedSubMenu('mainMenuHelp');
     helpSubMenu.appendAction('settings.documentation');
     helpSubMenu.appendItem('Release Notes', () => InspectorFrontendHost.openInNewTab(Help.latestReleaseNote().link));
-    contextMenu.show();
   }
 };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
index 657d96b..fb5ad2e18 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
@@ -49,8 +49,8 @@
 
     /** @type {?SDK.DebuggerPausedDetails} */
     this._debuggerPausedDetails = null;
-    /** @type {!Object.<string, !SDK.Script>} */
-    this._scripts = {};
+    /** @type {!Map<string, !SDK.Script>} */
+    this._scripts = new Map();
     /** @type {!Map.<string, !Array.<!SDK.Script>>} */
     this._scriptsBySourceURL = new Map();
     /** @type {!Array.<!SDK.Script>} */
@@ -345,17 +345,17 @@
       this._sourceMapManager.detachSourceMap(scriptWithSourceMap);
     this._sourceMapIdToScript.clear();
 
-    this._scripts = {};
+    this._scripts.clear();
     this._scriptsBySourceURL.clear();
     this._stringMap.clear();
     this._discardableScripts = [];
   }
 
   /**
-   * @return {!Object.<string, !SDK.Script>}
+   * @return {!Array<!SDK.Script>}
    */
-  get scripts() {
-    return this._scripts;
+  scripts() {
+    return Array.from(this._scripts.values());
   }
 
   /**
@@ -363,7 +363,7 @@
    * @return {?SDK.Script}
    */
   scriptForId(scriptId) {
-    return this._scripts[scriptId] || null;
+    return this._scripts.get(scriptId) || null;
   }
 
   /**
@@ -376,12 +376,26 @@
   }
 
   /**
+   * @param {!SDK.ExecutionContext} executionContext
+   * @return {!Array<!SDK.Script>}
+   */
+  scriptsForExecutionContext(executionContext) {
+    var result = [];
+    for (var script of this._scripts.values()) {
+      if (script.executionContextId === executionContext.id)
+        result.push(script);
+    }
+    return result;
+  }
+
+  /**
    * @param {!Protocol.Runtime.ScriptId} scriptId
    * @param {string} newSource
    * @param {function(?Protocol.Error, !Protocol.Runtime.ExceptionDetails=)} callback
    */
   setScriptSource(scriptId, newSource, callback) {
-    this._scripts[scriptId].editSource(newSource, this._didEditScriptSource.bind(this, scriptId, newSource, callback));
+    this._scripts.get(scriptId).editSource(
+        newSource, this._didEditScriptSource.bind(this, scriptId, newSource, callback));
   }
 
   /**
@@ -573,7 +587,7 @@
    * @param {!SDK.Script} script
    */
   _registerScript(script) {
-    this._scripts[script.scriptId] = script;
+    this._scripts.set(script.scriptId, script);
     if (script.isAnonymousScript())
       return;
 
@@ -590,7 +604,7 @@
    */
   _unregisterScript(script) {
     console.assert(script.isAnonymousScript());
-    delete this._scripts[script.scriptId];
+    this._scripts.delete(script.scriptId);
   }
 
   _collectDiscardedScripts() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index c8fcef6..a1ce9bf7 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -57,10 +57,6 @@
     this._navigatorGroupByFolderSetting.addChangeListener(this._groupingChanged.bind(this));
 
     this._initGrouping();
-    SDK.targetManager.addModelListener(
-        SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.FrameNavigated, this._frameNavigated, this);
-    SDK.targetManager.addModelListener(
-        SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.FrameDetached, this._frameDetached, this);
 
     if (Runtime.experiments.isEnabled('persistence2')) {
       Persistence.persistence.addEventListener(
@@ -758,28 +754,6 @@
   }
 
   /**
-   * @param {!Common.Event} event
-   */
-  _frameNavigated(event) {
-    var frame = /** @type {!SDK.ResourceTreeFrame} */ (event.data);
-    var node = this._frameNodes.get(frame);
-    if (!node)
-      return;
-
-    node.treeNode().title = frame.displayName();
-    for (var child of frame.childFrames)
-      this._discardFrame(child);
-  }
-
-  /**
-   * @param {!Common.Event} event
-   */
-  _frameDetached(event) {
-    var frame = /** @type {!SDK.ResourceTreeFrame} */ (event.data);
-    this._discardFrame(frame);
-  }
-
-  /**
    * @param {!SDK.ResourceTreeFrame} frame
    */
   _discardFrame(frame) {
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
index 3e18e55..5906d71 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObject.cpp
@@ -1731,10 +1731,13 @@
 }
 
 bool AXObject::nameFromContents() const {
+  // ARIA 1.1, section 5.2.7.5.
   switch (roleValue()) {
     case AnchorRole:
     case ButtonRole:
+    case CellRole:
     case CheckBoxRole:
+    case ColumnHeaderRole:
     case DirectoryRole:
     case DisclosureTriangleRole:
     case HeadingRole:
@@ -1748,12 +1751,14 @@
     case MenuListOptionRole:
     case PopUpButtonRole:
     case RadioButtonRole:
+    case RowHeaderRole:
     case StaticTextRole:
     case StatusRole:
     case SwitchRole:
     case TabRole:
     case ToggleButtonRole:
     case TreeItemRole:
+    case UserInterfaceTooltipRole:
       return true;
     default:
       return false;
diff --git a/third_party/WebKit/Source/modules/shapedetection/BUILD.gn b/third_party/WebKit/Source/modules/shapedetection/BUILD.gn
index 663f27599..8102c764 100644
--- a/third_party/WebKit/Source/modules/shapedetection/BUILD.gn
+++ b/third_party/WebKit/Source/modules/shapedetection/BUILD.gn
@@ -24,6 +24,5 @@
 
   public_deps = [
     "//services/shape_detection/public/interfaces:interfaces_blink",
-    "//skia/public/interfaces:interfaces_blink",
   ]
 }
diff --git a/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.cpp
index 927d8ef..024e271d 100644
--- a/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.cpp
@@ -26,8 +26,11 @@
                 wrapWeakPersistent(this))));
 }
 
-ScriptPromise BarcodeDetector::doDetect(ScriptPromiseResolver* resolver,
-                                        skia::mojom::blink::BitmapPtr bitmap) {
+ScriptPromise BarcodeDetector::doDetect(
+    ScriptPromiseResolver* resolver,
+    mojo::ScopedSharedBufferHandle sharedBufferHandle,
+    int imageWidth,
+    int imageHeight) {
   ScriptPromise promise = resolver->promise();
   if (!m_barcodeService) {
     resolver->reject(DOMException::create(
@@ -36,9 +39,10 @@
   }
   m_barcodeServiceRequests.insert(resolver);
   m_barcodeService->Detect(
-      std::move(bitmap), convertToBaseCallback(WTF::bind(
-                             &BarcodeDetector::onDetectBarcodes,
-                             wrapPersistent(this), wrapPersistent(resolver))));
+      std::move(sharedBufferHandle), imageWidth, imageHeight,
+      convertToBaseCallback(WTF::bind(&BarcodeDetector::onDetectBarcodes,
+                                      wrapPersistent(this),
+                                      wrapPersistent(resolver))));
   return promise;
 }
 
diff --git a/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.h b/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.h
index 7e3fa4af8..2d0e598 100644
--- a/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.h
+++ b/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.h
@@ -29,7 +29,9 @@
   ~BarcodeDetector() override = default;
 
   ScriptPromise doDetect(ScriptPromiseResolver*,
-                         skia::mojom::blink::BitmapPtr) override;
+                         mojo::ScopedSharedBufferHandle,
+                         int imageWidth,
+                         int imageHeight) override;
   void onDetectBarcodes(
       ScriptPromiseResolver*,
       Vector<shape_detection::mojom::blink::BarcodeDetectionResultPtr>);
diff --git a/third_party/WebKit/Source/modules/shapedetection/DEPS b/third_party/WebKit/Source/modules/shapedetection/DEPS
index 2ebe46d3..aefd1f3 100644
--- a/third_party/WebKit/Source/modules/shapedetection/DEPS
+++ b/third_party/WebKit/Source/modules/shapedetection/DEPS
@@ -5,7 +5,6 @@
     "+modules/imagecapture/Point2D.h",
     "+modules/shapedetection",
     "+services/shape_detection",
-    "+skia/public/interfaces/bitmap.mojom-blink.h",
     "+third_party/skia/include/core/SkImage.h",
     "+third_party/skia/include/core/SkImageInfo.h",
     "+ui/gfx/geometry",
diff --git a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
index e2c1f90..a80c9c90 100644
--- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
@@ -35,8 +35,11 @@
       &FaceDetector::onFaceServiceConnectionError, wrapWeakPersistent(this))));
 }
 
-ScriptPromise FaceDetector::doDetect(ScriptPromiseResolver* resolver,
-                                     skia::mojom::blink::BitmapPtr bitmap) {
+ScriptPromise FaceDetector::doDetect(
+    ScriptPromiseResolver* resolver,
+    mojo::ScopedSharedBufferHandle sharedBufferHandle,
+    int imageWidth,
+    int imageHeight) {
   ScriptPromise promise = resolver->promise();
   if (!m_faceService) {
     resolver->reject(DOMException::create(
@@ -44,7 +47,7 @@
     return promise;
   }
   m_faceServiceRequests.insert(resolver);
-  m_faceService->Detect(std::move(bitmap),
+  m_faceService->Detect(std::move(sharedBufferHandle), imageWidth, imageHeight,
                         convertToBaseCallback(WTF::bind(
                             &FaceDetector::onDetectFaces, wrapPersistent(this),
                             wrapPersistent(resolver))));
diff --git a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h
index 2047879c..84f6b9f 100644
--- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h
+++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h
@@ -31,7 +31,9 @@
   ~FaceDetector() override = default;
 
   ScriptPromise doDetect(ScriptPromiseResolver*,
-                         skia::mojom::blink::BitmapPtr) override;
+                         mojo::ScopedSharedBufferHandle,
+                         int imageWidth,
+                         int imageHeight) override;
   void onDetectFaces(ScriptPromiseResolver*,
                      shape_detection::mojom::blink::FaceDetectionResultPtr);
   void onFaceServiceConnectionError();
diff --git a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
index 373be36..73adbca 100644
--- a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
@@ -22,22 +22,28 @@
 
 namespace {
 
-skia::mojom::blink::BitmapPtr createBitmapFromData(int width,
-                                                   int height,
-                                                   Vector<uint8_t> bitmapData) {
-  skia::mojom::blink::BitmapPtr bitmap = skia::mojom::blink::Bitmap::New();
+mojo::ScopedSharedBufferHandle getSharedBufferOnData(
+    ScriptPromiseResolver* resolver,
+    uint8_t* data,
+    int size) {
+  DCHECK(data);
+  DCHECK(size);
+  ScriptPromise promise = resolver->promise();
 
-  bitmap->color_type = (kN32_SkColorType == kRGBA_8888_SkColorType)
-                           ? skia::mojom::blink::ColorType::RGBA_8888
-                           : skia::mojom::blink::ColorType::BGRA_8888;
-  bitmap->alpha_type = skia::mojom::blink::AlphaType::ALPHA_TYPE_OPAQUE;
-  bitmap->profile_type = skia::mojom::blink::ColorProfileType::LINEAR;
-  bitmap->width = width;
-  bitmap->height = height;
-  bitmap->row_bytes = width * 4 /* bytes per pixel */;
-  bitmap->pixel_data = std::move(bitmapData);
+  mojo::ScopedSharedBufferHandle sharedBufferHandle =
+      mojo::SharedBufferHandle::Create(size);
+  if (!sharedBufferHandle->is_valid()) {
+    resolver->reject(
+        DOMException::create(InvalidStateError, "Internal allocation error"));
+    return sharedBufferHandle;
+  }
 
-  return bitmap;
+  const mojo::ScopedSharedBufferMapping mappedBuffer =
+      sharedBufferHandle->Map(size);
+  DCHECK(mappedBuffer.get());
+  memcpy(mappedBuffer.get(), data, size);
+
+  return sharedBufferHandle;
 }
 
 }  // anonymous namespace
@@ -128,13 +134,13 @@
     return promise;
   }
 
-  WTF::Vector<uint8_t> bitmapData;
-  bitmapData.append(pixelDataPtr,
-                    static_cast<int>(allocationSize.ValueOrDefault(0)));
+  mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData(
+      resolver, pixelDataPtr, allocationSize.ValueOrDefault(0));
+  if (!sharedBufferHandle->is_valid())
+    return promise;
 
-  return doDetect(resolver,
-                  createBitmapFromData(image->width(), image->height(),
-                                       std::move(bitmapData)));
+  return doDetect(resolver, std::move(sharedBufferHandle), image->width(),
+                  image->height());
 }
 
 ScriptPromise ShapeDetector::detectShapesOnImageData(
@@ -149,12 +155,14 @@
 
   uint8_t* const data = imageData->data()->data();
   WTF::CheckedNumeric<int> allocationSize = imageData->size().area() * 4;
-  WTF::Vector<uint8_t> bitmapData;
-  bitmapData.append(data, static_cast<int>(allocationSize.ValueOrDefault(0)));
 
-  return doDetect(resolver,
-                  createBitmapFromData(imageData->width(), imageData->height(),
-                                       std::move(bitmapData)));
+  mojo::ScopedSharedBufferHandle sharedBufferHandle =
+      getSharedBufferOnData(resolver, data, allocationSize.ValueOrDefault(0));
+  if (!sharedBufferHandle->is_valid())
+    return promise;
+
+  return doDetect(resolver, std::move(sharedBufferHandle), imageData->width(),
+                  imageData->height());
 }
 
 ScriptPromise ShapeDetector::detectShapesOnImageElement(
@@ -193,10 +201,26 @@
 
   const SkImageInfo skiaInfo =
       SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType());
-  size_t rowBytes = skiaInfo.minRowBytes();
 
-  Vector<uint8_t> bitmapData(skiaInfo.getSafeSize(rowBytes));
-  const SkPixmap pixmap(skiaInfo, bitmapData.data(), rowBytes);
+  const uint32_t allocationSize = skiaInfo.getSafeSize(skiaInfo.minRowBytes());
+
+  mojo::ScopedSharedBufferHandle sharedBufferHandle =
+      mojo::SharedBufferHandle::Create(allocationSize);
+  if (!sharedBufferHandle.is_valid()) {
+    DLOG(ERROR) << "Requested allocation : " << allocationSize
+                << "B, larger than |mojo::edk::kMaxSharedBufferSize| == 16MB ";
+    // TODO(xianglu): For now we reject the promise if the image is too large.
+    // But consider resizing the image to remove restriction on the user side.
+    // Also, add LayoutTests for this case later.
+    resolver->reject(
+        DOMException::create(InvalidStateError, "Image exceeds size limit."));
+    return promise;
+  }
+
+  const mojo::ScopedSharedBufferMapping mappedBuffer =
+      sharedBufferHandle->Map(allocationSize);
+
+  const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes());
   if (!image->readPixels(pixmap, 0, 0)) {
     resolver->reject(DOMException::create(
         InvalidStateError,
@@ -204,9 +228,8 @@
     return promise;
   }
 
-  return doDetect(
-      resolver, createBitmapFromData(img->naturalWidth(), img->naturalHeight(),
-                                     std::move(bitmapData)));
+  return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(),
+                  img->naturalHeight());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.h b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.h
index cd55e5cc..74b8e70e 100644
--- a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.h
+++ b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.h
@@ -10,7 +10,6 @@
 #include "core/imagebitmap/ImageBitmapFactories.h"
 #include "modules/ModulesExport.h"
 #include "modules/canvas2d/CanvasRenderingContext2D.h"
-#include "skia/public/interfaces/bitmap.mojom-blink.h"
 
 namespace blink {
 
@@ -28,7 +27,9 @@
                                            const HTMLImageElement*);
 
   virtual ScriptPromise doDetect(ScriptPromiseResolver*,
-                                 skia::mojom::blink::BitmapPtr) = 0;
+                                 mojo::ScopedSharedBufferHandle,
+                                 int imageWidth,
+                                 int imageHeight) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/shapedetection/TextDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/TextDetector.cpp
index 3cab8b2..734ae85 100644
--- a/third_party/WebKit/Source/modules/shapedetection/TextDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/TextDetector.cpp
@@ -24,8 +24,11 @@
       &TextDetector::onTextServiceConnectionError, wrapWeakPersistent(this))));
 }
 
-ScriptPromise TextDetector::doDetect(ScriptPromiseResolver* resolver,
-                                     skia::mojom::blink::BitmapPtr bitmap) {
+ScriptPromise TextDetector::doDetect(
+    ScriptPromiseResolver* resolver,
+    mojo::ScopedSharedBufferHandle sharedBufferHandle,
+    int imageWidth,
+    int imageHeight) {
   ScriptPromise promise = resolver->promise();
   if (!m_textService) {
     resolver->reject(DOMException::create(
@@ -33,7 +36,7 @@
     return promise;
   }
   m_textServiceRequests.insert(resolver);
-  m_textService->Detect(std::move(bitmap),
+  m_textService->Detect(std::move(sharedBufferHandle), imageWidth, imageHeight,
                         convertToBaseCallback(WTF::bind(
                             &TextDetector::onDetectText, wrapPersistent(this),
                             wrapPersistent(resolver))));
diff --git a/third_party/WebKit/Source/modules/shapedetection/TextDetector.h b/third_party/WebKit/Source/modules/shapedetection/TextDetector.h
index 800893c..64791e3 100644
--- a/third_party/WebKit/Source/modules/shapedetection/TextDetector.h
+++ b/third_party/WebKit/Source/modules/shapedetection/TextDetector.h
@@ -29,7 +29,9 @@
   ~TextDetector() override = default;
 
   ScriptPromise doDetect(ScriptPromiseResolver*,
-                         skia::mojom::blink::BitmapPtr) override;
+                         mojo::ScopedSharedBufferHandle,
+                         int imageWidth,
+                         int imageHeight) override;
   void onDetectText(
       ScriptPromiseResolver*,
       Vector<shape_detection::mojom::blink::TextDetectionResultPtr>);
diff --git a/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h b/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
index a53210d..340d96c 100644
--- a/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
+++ b/third_party/WebKit/Source/platform/graphics/ExpensiveCanvasHeuristicParameters.h
@@ -98,7 +98,7 @@
   // acceleration on the destination first. If that does not succeed,
   // we disable acceleration on the source canvas. Either way, future
   // readbacks are prevented.
-  EnableAccelerationToAvoidReadbacks = 0,
+  EnableAccelerationToAvoidReadbacks = 1,
 
 };  // enum
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
index 839b5c3..bbcb285 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -352,6 +352,7 @@
 
         if try_results and self.git_cl.has_failing_try_results(try_results):
             self.fetch_new_expectations_and_baselines()
+            self._upload_patchset('Update test expectations and baselines.')
 
         # Trigger CQ and wait for CQ try jobs to finish.
         self.git_cl.run(['set-commit', '--gerrit'])
@@ -386,6 +387,9 @@
             description,
         ] + self._cc_part(directory_owners))
 
+    def _upload_patchset(self, message):
+        self.git_cl.run(['upload', '-f', '-t', message, '--gerrit'])
+
     @staticmethod
     def _cc_part(directory_owners):
         cc_part = []
@@ -435,9 +439,6 @@
         _log.info('Adding test expectations lines to LayoutTests/TestExpectations.')
         expectation_updater = WPTExpectationsUpdater(self.host)
         expectation_updater.run(args=[])
-        message = 'Update test expectations and baselines.'
-        self.check_run(['git', 'commit', '-a', '-m', message])
-        self.git_cl.run(['upload', '-t', message, '--gerrit'])
 
     def update_all_test_expectations_files(self, deleted_tests, renamed_tests):
         """Updates all test expectations files for tests that have been deleted or renamed."""
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
index 832ee5a..5ee01b9 100644
--- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
+++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -657,98 +657,108 @@
 bool ShouldPrefixFunctionName(const std::string& old_method_name) {
   // Functions that are named similarily to a type - they should be prefixed
   // with a "Get" prefix.
-  static const char* kConflictingMethods[] = {
-      "accumulatorMap",
-      "animationWorklet",
-      "audioWorklet",
-      "binaryType",
-      "blob",
-      "channelCountMode",
-      "color",
-      "compositorElementId",
-      "counterDirectives",
-      "document",
-      "element",
-      "emptyChromeClient",
-      "emptyEditorClient",
-      "emptySpellCheckerClient",
-      "entryType",
-      "error",
-      "eventTargetDataMap",
-      "fileUtilities",
-      "font",
-      "frame",
-      "frameBlameContext",
-      "frontend",
-      "gridCell",
-      "hash",
-      "heapObjectHeader",
-      "heapObjectSet",
-      "iconURL",
-      "image",
-      "inputMethodController",
-      "inputType",
-      "interpolationTypes",
-      "layout",
-      "layoutBlock",
-      "layoutObject",
-      "layoutSize",
-      "lineCap",
-      "lineEndings",
-      "lineJoin",
-      "listItems",
-      "matchedProperties",
-      "midpointState",
-      "modifiers",
-      "mouseEvent",
-      "name",
-      "navigationType",
-      "node",
-      "notificationManager",
-      "outcome",
-      "pagePopup",
-      "paintWorklet",
-      "path",
-      "position",
-      "processingInstruction",
-      "qualifiedNameCache",
-      "readyState",
-      "relList",
-      "referrer",
-      "referrerPolicy",
-      "resource",
-      "response",
-      "restrictedKeyMap",
-      "sandboxSupport",
-      "screenInfo",
-      "screenOrientationController",
-      "scrollAnimator",
-      "selectionInDOMTree",
-      "selectionInFlatTree",
-      "selectorTextCache",
-      "settings",
-      "signalingState",
-      "snapshotById",
-      "state",
-      "string",
-      "styleSheet",
-      "supplementable",
-      "text",
-      "textAlign",
-      "textBaseline",
-      "theme",
-      "thread",
-      "timing",
-      "topLevelBlameContext",
-      "type",
-      "vector",
-      "visibleSelection",
-      "visibleSelectionInFlatTree",
-      "webFrame",
-      "widget",
-      "wordBoundaries",
-      "wrapperTypeInfo",
-  };
+  static const char* kConflictingMethods[] = {"accumulatorMap",
+                                              "animationWorklet",
+                                              "attrNodeList",
+                                              "audioWorklet",
+                                              "binaryType",
+                                              "blob",
+                                              "channelCountMode",
+                                              "color",
+                                              "compositorElementId",
+                                              "constructionStack",
+                                              "counterDirectives",
+                                              "counterMaps"
+                                              "document",
+                                              "element",
+                                              "emptyChromeClient",
+                                              "emptyEditorClient",
+                                              "emptySpellCheckerClient",
+                                              "entryType",
+                                              "error",
+                                              "eventTargetDataMap",
+                                              "fileUtilities",
+                                              "font",
+                                              "frame",
+                                              "frameBlameContext",
+                                              "frontend",
+                                              "gridCell",
+                                              "harfBuzzFontCache",
+                                              "hash",
+                                              "heapObjectHeader",
+                                              "heapObjectSet",
+                                              "iconURL",
+                                              "image",
+                                              "infoMap",
+                                              "inputMethodController",
+                                              "inputType",
+                                              "interpolationTypes",
+                                              "intervalArena",
+                                              "layout",
+                                              "layoutBlock",
+                                              "layoutObject",
+                                              "layoutSize",
+                                              "lineCap",
+                                              "lineEndings",
+                                              "lineJoin",
+                                              "listItems",
+                                              "matchedProperties",
+                                              "midpointState",
+                                              "modifiers",
+                                              "mouseEvent",
+                                              "name",
+                                              "navigationType",
+                                              "node",
+                                              "notificationManager",
+                                              "originAccessMap",
+                                              "outcome",
+                                              "pagePopup",
+                                              "paintWorklet",
+                                              "path",
+                                              "position",
+                                              "presentationAttributeCache",
+                                              "processingInstruction",
+                                              "qualifiedNameCache",
+                                              "readyState",
+                                              "relList",
+                                              "referrer",
+                                              "referrerPolicy",
+                                              "resource",
+                                              "response",
+                                              "restrictedKeyMap",
+                                              "sandboxSupport",
+                                              "screenInfo",
+                                              "screenOrientationController",
+                                              "scrollAnimator",
+                                              "selectionInDOMTree",
+                                              "selectionInFlatTree",
+                                              "selectionVisualRectMap",
+                                              "selectorTextCache",
+                                              "settings",
+                                              "signalingState",
+                                              "snapshotById",
+                                              "state",
+                                              "string",
+                                              "styleSharingList",
+                                              "styleSheet",
+                                              "supplementable",
+                                              "text",
+                                              "textAlign",
+                                              "textBaseline",
+                                              "theme",
+                                              "thread",
+                                              "timing",
+                                              "topLevelBlameContext",
+                                              "type",
+                                              "vector",
+                                              "visibleSelection",
+                                              "visibleSelectionInFlatTree",
+                                              "weakHeapObjectSet",
+                                              "webFrame",
+                                              "widget",
+                                              "wordBoundaries",
+                                              "worldMap",
+                                              "wrapperTypeInfo"};
   for (const auto& conflicting_method : kConflictingMethods) {
     if (old_method_name == conflicting_method)
       return true;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 7ad3ec2..0fddafe 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -37573,7 +37573,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.SSL_Connection_Error_Google" units="NetErrorCodes">
+<histogram name="Net.SSL_Connection_Error_Google" enum="NetErrorCodes">
   <owner>svaldez@chromium.org</owner>
   <summary>
     Counts of specific error codes returned when opening an SSL connection for
@@ -37581,8 +37581,7 @@
   </summary>
 </histogram>
 
-<histogram name="Net.SSL_Connection_Error_TLS13Experiment"
-    units="NetErrorCodes">
+<histogram name="Net.SSL_Connection_Error_TLS13Experiment" enum="NetErrorCodes">
   <owner>svaldez@chromium.org</owner>
   <summary>
     Counts of specific error codes returned when opening an SSL connection for
@@ -94927,6 +94926,8 @@
   <int value="1909" label="WindowOpenWithInvalidURL"/>
   <int value="1910" label="CrossOriginMainFrameNulledNameAccessed"/>
   <int value="1911" label="MenuItemElementIconAttribute"/>
+  <int value="1912" label="WebkitCSSMatrixSetMatrixValue"/>
+  <int value="1913" label="WebkitCSSMatrixConstructFromString"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
@@ -100785,6 +100786,7 @@
   <int value="-1634154256" label="ZeroSuggestRedirectToChrome:enabled"/>
   <int value="-1631329950" label="ssl-version-max"/>
   <int value="-1630419335" label="enable-download-notification"/>
+  <int value="-1629748710" label="ash-enable-smooth-screen-rotation"/>
   <int value="-1624854957" label="enable-es3-apis"/>
   <int value="-1620568042" label="FeaturePolicy:disabled"/>
   <int value="-1619757314" label="touch-scrolling-mode"/>
@@ -100964,6 +100966,7 @@
   <int value="-918618075" label="enable-service-worker"/>
   <int value="-914210146" label="enable-web-based-signin"/>
   <int value="-912456561" label="MidiManagerWinrt:enabled"/>
+  <int value="-909641013" label="DataReductionProxySiteBreakdown:enabled"/>
   <int value="-908421850" label="PointerEvent:enabled"/>
   <int value="-907234795" label="NewAudioRenderingMixingStrategy:disabled"/>
   <int value="-899334103" label="disable-fast-text-autosizing"/>
@@ -101331,6 +101334,7 @@
   <int value="637396292" label="AllBookmarks:enabled"/>
   <int value="643725031" label="disable-touch-feedback"/>
   <int value="644189071" label="PermissionsBlacklist:enabled"/>
+  <int value="644674603" label="DataReductionProxySiteBreakdown:disabled"/>
   <int value="646252875" label="ReadItLaterInMenu:enabled"/>
   <int value="646738320" label="disable-gesture-editing"/>
   <int value="650602639" label="enable-autofill-keyboard-accessory-view"/>
@@ -108624,7 +108628,9 @@
   <int value="92" label="MULTIPATH_PATH_NOT_ACTIVE"/>
   <int value="93" label="TOO_MANY_FRAME_GAPS"/>
   <int value="94" label="UNSUPPORTED_PROOF_DEMAND"/>
-  <int value="95" label="HEADERS_STREAM_DATA_DECOMPRESS_FAILURE"/>
+  <int value="95" label="STREAM_SEQUENCER_INVALID_STATE"/>
+  <int value="96" label="TOO_MANY_SESSIONS_ON_SERVER"/>
+  <int value="97" label="HEADERS_STREAM_DATA_DECOMPRESS_FAILURE"/>
 </enum>
 
 <enum name="QuicHandshakeFailureReason" type="int">
diff --git a/ui/gfx/platform_font.h b/ui/gfx/platform_font.h
index 48e14cf..183486e 100644
--- a/ui/gfx/platform_font.h
+++ b/ui/gfx/platform_font.h
@@ -21,6 +21,16 @@
 
 class GFX_EXPORT PlatformFont : public base::RefCounted<PlatformFont> {
  public:
+// The size of the font returned by CreateDefault() on a "default" platform
+// configuration. This allows UI that wants to target a particular size of font
+// to obtain that size for the majority of users, while still compensating for a
+// user preference for a larger or smaller font.
+#if defined(OS_MACOSX)
+  static constexpr int kDefaultBaseFontSize = 13;
+#else
+  static constexpr int kDefaultBaseFontSize = 12;
+#endif
+
   // Creates an appropriate PlatformFont implementation.
   static PlatformFont* CreateDefault();
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_IOS)
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index a4268c63..b6b98d1 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -1295,8 +1295,7 @@
                 'extensions': ['GL_ANGLE_robust_client_memory']}],
   'arguments':
       'GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, '
-      'GLenum type, GLsizei bufSize, GLsizei* length, GLsizei* columns, '
-      'GLsizei* rows, void* data', },
+      'GLenum type, GLsizei bufSize, GLsizei* length, void* data', },
 { 'return_type': 'void',
   'names': ['glReadPixels'],
   'arguments':
@@ -1307,8 +1306,7 @@
                 'extensions': ['GL_ANGLE_robust_client_memory']}],
   'arguments':
       'GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, '
-      'GLenum type, GLsizei bufSize, GLsizei* length, GLsizei* columns, '
-      'GLsizei* rows, void* pixels', },
+      'GLenum type, GLsizei bufSize, GLsizei* length, void* pixels', },
 { 'return_type': 'void',
   'names': ['glReleaseShaderCompiler'],
   'arguments': 'void', },
diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h
index fcb7b66..b2a6ae4 100644
--- a/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/ui/gl/gl_bindings_api_autogen_gl.h
@@ -849,8 +849,6 @@
                                 GLenum type,
                                 GLsizei bufSize,
                                 GLsizei* length,
-                                GLsizei* columns,
-                                GLsizei* rows,
                                 void* data) override;
 void glReadPixelsFn(GLint x,
                     GLint y,
@@ -867,8 +865,6 @@
                                GLenum type,
                                GLsizei bufSize,
                                GLsizei* length,
-                               GLsizei* columns,
-                               GLsizei* rows,
                                void* pixels) override;
 void glReleaseShaderCompilerFn(void) override;
 void glRenderbufferStorageEXTFn(GLenum target,
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index 7e7b73b2..8740c1d 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -4247,11 +4247,9 @@
                                            GLenum type,
                                            GLsizei bufSize,
                                            GLsizei* length,
-                                           GLsizei* columns,
-                                           GLsizei* rows,
                                            void* data) {
   driver_->fn.glReadnPixelsRobustANGLEFn(x, y, width, height, format, type,
-                                         bufSize, length, columns, rows, data);
+                                         bufSize, length, data);
 }
 
 void GLApiBase::glReadPixelsFn(GLint x,
@@ -4272,11 +4270,9 @@
                                           GLenum type,
                                           GLsizei bufSize,
                                           GLsizei* length,
-                                          GLsizei* columns,
-                                          GLsizei* rows,
                                           void* pixels) {
   driver_->fn.glReadPixelsRobustANGLEFn(x, y, width, height, format, type,
-                                        bufSize, length, columns, rows, pixels);
+                                        bufSize, length, pixels);
 }
 
 void GLApiBase::glReleaseShaderCompilerFn(void) {
@@ -7150,12 +7146,10 @@
                                             GLenum type,
                                             GLsizei bufSize,
                                             GLsizei* length,
-                                            GLsizei* columns,
-                                            GLsizei* rows,
                                             void* data) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadnPixelsRobustANGLE")
   gl_api_->glReadnPixelsRobustANGLEFn(x, y, width, height, format, type,
-                                      bufSize, length, columns, rows, data);
+                                      bufSize, length, data);
 }
 
 void TraceGLApi::glReadPixelsFn(GLint x,
@@ -7177,12 +7171,10 @@
                                            GLenum type,
                                            GLsizei bufSize,
                                            GLsizei* length,
-                                           GLsizei* columns,
-                                           GLsizei* rows,
                                            void* pixels) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glReadPixelsRobustANGLE")
   gl_api_->glReadPixelsRobustANGLEFn(x, y, width, height, format, type, bufSize,
-                                     length, columns, rows, pixels);
+                                     length, pixels);
 }
 
 void TraceGLApi::glReleaseShaderCompilerFn(void) {
@@ -10867,19 +10859,15 @@
                                             GLenum type,
                                             GLsizei bufSize,
                                             GLsizei* length,
-                                            GLsizei* columns,
-                                            GLsizei* rows,
                                             void* data) {
   GL_SERVICE_LOG("glReadnPixelsRobustANGLE"
                  << "(" << x << ", " << y << ", " << width << ", " << height
                  << ", " << GLEnums::GetStringEnum(format) << ", "
                  << GLEnums::GetStringEnum(type) << ", " << bufSize << ", "
                  << static_cast<const void*>(length) << ", "
-                 << static_cast<const void*>(columns) << ", "
-                 << static_cast<const void*>(rows) << ", "
                  << static_cast<const void*>(data) << ")");
   gl_api_->glReadnPixelsRobustANGLEFn(x, y, width, height, format, type,
-                                      bufSize, length, columns, rows, data);
+                                      bufSize, length, data);
 }
 
 void DebugGLApi::glReadPixelsFn(GLint x,
@@ -10905,19 +10893,15 @@
                                            GLenum type,
                                            GLsizei bufSize,
                                            GLsizei* length,
-                                           GLsizei* columns,
-                                           GLsizei* rows,
                                            void* pixels) {
   GL_SERVICE_LOG("glReadPixelsRobustANGLE"
                  << "(" << x << ", " << y << ", " << width << ", " << height
                  << ", " << GLEnums::GetStringEnum(format) << ", "
                  << GLEnums::GetStringEnum(type) << ", " << bufSize << ", "
                  << static_cast<const void*>(length) << ", "
-                 << static_cast<const void*>(columns) << ", "
-                 << static_cast<const void*>(rows) << ", "
                  << static_cast<const void*>(pixels) << ")");
   gl_api_->glReadPixelsRobustANGLEFn(x, y, width, height, format, type, bufSize,
-                                     length, columns, rows, pixels);
+                                     length, pixels);
 }
 
 void DebugGLApi::glReleaseShaderCompilerFn(void) {
@@ -14490,8 +14474,6 @@
                                                 GLenum type,
                                                 GLsizei bufSize,
                                                 GLsizei* length,
-                                                GLsizei* columns,
-                                                GLsizei* rows,
                                                 void* data) {
   NOTREACHED()
       << "Trying to call glReadnPixelsRobustANGLE() without current GL context";
@@ -14518,8 +14500,6 @@
                                                GLenum type,
                                                GLsizei bufSize,
                                                GLsizei* length,
-                                               GLsizei* columns,
-                                               GLsizei* rows,
                                                void* pixels) {
   NOTREACHED()
       << "Trying to call glReadPixelsRobustANGLE() without current GL context";
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h
index 6c9cc2de..f72be65 100644
--- a/ui/gl/gl_bindings_autogen_gl.h
+++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -1003,8 +1003,6 @@
                                                             GLenum type,
                                                             GLsizei bufSize,
                                                             GLsizei* length,
-                                                            GLsizei* columns,
-                                                            GLsizei* rows,
                                                             void* data);
 typedef void(GL_BINDING_CALL* glReadPixelsProc)(GLint x,
                                                 GLint y,
@@ -1021,8 +1019,6 @@
                                                            GLenum type,
                                                            GLsizei bufSize,
                                                            GLsizei* length,
-                                                           GLsizei* columns,
-                                                           GLsizei* rows,
                                                            void* pixels);
 typedef void(GL_BINDING_CALL* glReleaseShaderCompilerProc)(void);
 typedef void(GL_BINDING_CALL* glRenderbufferStorageEXTProc)(
@@ -2835,8 +2831,6 @@
                                           GLenum type,
                                           GLsizei bufSize,
                                           GLsizei* length,
-                                          GLsizei* columns,
-                                          GLsizei* rows,
                                           void* data) = 0;
   virtual void glReadPixelsFn(GLint x,
                               GLint y,
@@ -2853,8 +2847,6 @@
                                          GLenum type,
                                          GLsizei bufSize,
                                          GLsizei* length,
-                                         GLsizei* columns,
-                                         GLsizei* rows,
                                          void* pixels) = 0;
   virtual void glReleaseShaderCompilerFn(void) = 0;
   virtual void glRenderbufferStorageEXTFn(GLenum target,
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index de274b3..ea0f41d 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -2851,12 +2851,10 @@
                                               GLenum type,
                                               GLsizei bufSize,
                                               GLsizei* length,
-                                              GLsizei* columns,
-                                              GLsizei* rows,
                                               void* pixels) {
   MakeFunctionUnique("glReadPixelsRobustANGLE");
   interface_->ReadPixelsRobustANGLE(x, y, width, height, format, type, bufSize,
-                                    length, columns, rows, pixels);
+                                    length, pixels);
 }
 
 void GL_BINDING_CALL
@@ -2868,12 +2866,10 @@
                                                GLenum type,
                                                GLsizei bufSize,
                                                GLsizei* length,
-                                               GLsizei* columns,
-                                               GLsizei* rows,
                                                void* data) {
   MakeFunctionUnique("glReadnPixelsRobustANGLE");
   interface_->ReadnPixelsRobustANGLE(x, y, width, height, format, type, bufSize,
-                                     length, columns, rows, data);
+                                     length, data);
 }
 
 void GL_BINDING_CALL MockGLInterface::Mock_glReleaseShaderCompiler(void) {
diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h
index 340b8a6..1e91945 100644
--- a/ui/gl/gl_bindings_autogen_mock.h
+++ b/ui/gl/gl_bindings_autogen_mock.h
@@ -1177,8 +1177,6 @@
                                                          GLenum type,
                                                          GLsizei bufSize,
                                                          GLsizei* length,
-                                                         GLsizei* columns,
-                                                         GLsizei* rows,
                                                          void* pixels);
 static void GL_BINDING_CALL Mock_glReadnPixelsRobustANGLE(GLint x,
                                                           GLint y,
@@ -1188,8 +1186,6 @@
                                                           GLenum type,
                                                           GLsizei bufSize,
                                                           GLsizei* length,
-                                                          GLsizei* columns,
-                                                          GLsizei* rows,
                                                           void* data);
 static void GL_BINDING_CALL Mock_glReleaseShaderCompiler(void);
 static void GL_BINDING_CALL Mock_glRenderbufferStorage(GLenum target,
diff --git a/ui/gl/gl_mock.h b/ui/gl/gl_mock.h
index ab78732f..e7440cf 100644
--- a/ui/gl/gl_mock.h
+++ b/ui/gl/gl_mock.h
@@ -116,34 +116,6 @@
                      GLenum format,
                      GLenum type));
 
-  void ReadPixelsRobustANGLE(GLint /*x*/,
-                             GLint /*y*/,
-                             GLsizei /*width*/,
-                             GLsizei /*height*/,
-                             GLenum /*format*/,
-                             GLenum /*type*/,
-                             GLsizei /*bufSize*/,
-                             GLsizei* /*length*/,
-                             GLsizei* /*columns*/,
-                             GLsizei* /*rows*/,
-                             void* /*pixels*/) {
-    NOTREACHED();
-  }
-
-  void ReadnPixelsRobustANGLE(GLint /*x*/,
-                              GLint /*y*/,
-                              GLsizei /*width*/,
-                              GLsizei /*height*/,
-                              GLenum /*format*/,
-                              GLenum /*type*/,
-                              GLsizei /*bufSize*/,
-                              GLsizei* /*length*/,
-                              GLsizei* /*columns*/,
-                              GLsizei* /*rows*/,
-                              void* /*data*/) {
-    NOTREACHED();
-  }
-
  private:
   static MockGLInterface* interface_;
 
diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h
index 60d1d2e..82525d6 100644
--- a/ui/gl/gl_mock_autogen_gl.h
+++ b/ui/gl/gl_mock_autogen_gl.h
@@ -865,8 +865,16 @@
 MOCK_METHOD2(PushGroupMarkerEXT, void(GLsizei length, const char* marker));
 MOCK_METHOD2(QueryCounter, void(GLuint id, GLenum target));
 MOCK_METHOD1(ReadBuffer, void(GLenum src));
-// TODO(zmo): crbug.com/456340
-// glReadnPixelsRobustANGLE cannot be mocked because it has 11 args.
+MOCK_METHOD9(ReadnPixelsRobustANGLE,
+             void(GLint x,
+                  GLint y,
+                  GLsizei width,
+                  GLsizei height,
+                  GLenum format,
+                  GLenum type,
+                  GLsizei bufSize,
+                  GLsizei* length,
+                  void* data));
 MOCK_METHOD7(ReadPixels,
              void(GLint x,
                   GLint y,
@@ -875,8 +883,16 @@
                   GLenum format,
                   GLenum type,
                   void* pixels));
-// TODO(zmo): crbug.com/456340
-// glReadPixelsRobustANGLE cannot be mocked because it has 11 args.
+MOCK_METHOD9(ReadPixelsRobustANGLE,
+             void(GLint x,
+                  GLint y,
+                  GLsizei width,
+                  GLsizei height,
+                  GLenum format,
+                  GLenum type,
+                  GLsizei bufSize,
+                  GLsizei* length,
+                  void* pixels));
 MOCK_METHOD0(ReleaseShaderCompiler, void());
 MOCK_METHOD4(
     RenderbufferStorageEXT,
diff --git a/ui/gl/gl_stub_autogen_gl.h b/ui/gl/gl_stub_autogen_gl.h
index a49500dc..9c48030 100644
--- a/ui/gl/gl_stub_autogen_gl.h
+++ b/ui/gl/gl_stub_autogen_gl.h
@@ -862,8 +862,6 @@
                                 GLenum type,
                                 GLsizei bufSize,
                                 GLsizei* length,
-                                GLsizei* columns,
-                                GLsizei* rows,
                                 void* data) override {}
 void glReadPixelsFn(GLint x,
                     GLint y,
@@ -880,8 +878,6 @@
                                GLenum type,
                                GLsizei bufSize,
                                GLsizei* length,
-                               GLsizei* columns,
-                               GLsizei* rows,
                                void* pixels) override {}
 void glReleaseShaderCompilerFn() override {}
 void glRenderbufferStorageEXTFn(GLenum target,
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc
index f2c1ff9..21707e8 100644
--- a/ui/views/controls/button/label_button.cc
+++ b/ui/views/controls/button/label_button.cc
@@ -234,6 +234,7 @@
 
   // Use a temporary label copy for sizing to avoid calculation side-effects.
   Label label(GetText(), {label_->font_list()});
+  label.SetLineHeight(label_->line_height());
   label.SetShadows(label_->shadows());
 
   if (style_ == STYLE_BUTTON && PlatformStyle::kDefaultLabelButtonHasBoldFont) {
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index f2d891d..762227f 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -49,6 +49,7 @@
 Label::Label(const base::string16& text, int text_context, int text_style)
     : context_menu_contents_(this) {
   Init(text, style::GetFont(text_context, text_style));
+  SetLineHeight(style::GetLineHeight(text_context, text_style));
 }
 
 Label::Label(const base::string16& text, const CustomFont& font)
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp b/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp
index 1d42ee80..c51dc3ba 100644
--- a/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp
@@ -6,6 +6,7 @@
     {
       'target_name': 'cr_action_menu',
       'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
index 41566841..f2fa45e5 100644
--- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
+++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html
@@ -1,3 +1,4 @@
+<link rel="import" href="chrome://resources/html/util.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 
diff --git a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
index 9f58dc4..c68aece 100644
--- a/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
+++ b/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js
@@ -26,12 +26,16 @@
    */
   boundClose_: null,
 
+  /** @private {boolean} */
+  hasMousemoveListener_: false,
+
   hostAttributes: {
     tabindex: 0,
   },
 
   listeners: {
     'keydown': 'onKeyDown_',
+    'mouseover': 'onMouseover_',
     'tap': 'onTap_',
   },
 
@@ -77,13 +81,41 @@
       return;
 
     var nextOption = this.getNextOption_(e.key == 'ArrowDown' ? 1 : -1);
-    if (nextOption)
+    if (nextOption) {
+      if (!this.hasMousemoveListener_) {
+        this.hasMousemoveListener_ = true;
+        listenOnce(this, 'mousemove', function(e) {
+          this.onMouseover_(e);
+          this.hasMousemoveListener_ = false;
+        }.bind(this));
+      }
       nextOption.focus();
+    }
 
     e.preventDefault();
   },
 
   /**
+   * @param {!Event} e
+   * @private
+   */
+  onMouseover_: function(e) {
+    // TODO(scottchen): Using "focus" to determine selected item might mess
+    // with screen readers in some edge cases.
+    var i = 0;
+    do {
+      var target = e.path[i++];
+      if (target.classList && target.classList.contains('dropdown-item')) {
+        target.focus();
+        return;
+      }
+    } while (this != target);
+
+    // The user moved the mouse off the options. Reset focus to the dialog.
+    this.focus();
+  },
+
+  /**
    * @param {number} step -1 for getting previous option (up), 1 for getting
    *     next option (down).
    * @return {?Element} The next focusable option, taking into account